1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * DHAV demuxer 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (c) 2018 Paul B Mahol 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 24cabdff1aSopenharmony_ci#include "avio_internal.h" 25cabdff1aSopenharmony_ci#include "avformat.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_citypedef struct DHAVContext { 29cabdff1aSopenharmony_ci unsigned type; 30cabdff1aSopenharmony_ci unsigned subtype; 31cabdff1aSopenharmony_ci unsigned channel; 32cabdff1aSopenharmony_ci unsigned frame_subnumber; 33cabdff1aSopenharmony_ci unsigned frame_number; 34cabdff1aSopenharmony_ci unsigned date; 35cabdff1aSopenharmony_ci unsigned timestamp; 36cabdff1aSopenharmony_ci int width, height; 37cabdff1aSopenharmony_ci int video_codec; 38cabdff1aSopenharmony_ci int frame_rate; 39cabdff1aSopenharmony_ci int audio_channels; 40cabdff1aSopenharmony_ci int audio_codec; 41cabdff1aSopenharmony_ci int sample_rate; 42cabdff1aSopenharmony_ci int64_t last_good_pos; 43cabdff1aSopenharmony_ci int64_t duration; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci int video_stream_index; 46cabdff1aSopenharmony_ci int audio_stream_index; 47cabdff1aSopenharmony_ci} DHAVContext; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_citypedef struct DHAVStream { 50cabdff1aSopenharmony_ci int64_t last_frame_number; 51cabdff1aSopenharmony_ci int64_t last_timestamp; 52cabdff1aSopenharmony_ci int64_t last_time; 53cabdff1aSopenharmony_ci int64_t pts; 54cabdff1aSopenharmony_ci} DHAVStream; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_cistatic int dhav_probe(const AVProbeData *p) 57cabdff1aSopenharmony_ci{ 58cabdff1aSopenharmony_ci if (!memcmp(p->buf, "DAHUA", 5)) 59cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci if (memcmp(p->buf, "DHAV", 4)) 62cabdff1aSopenharmony_ci return 0; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci if (p->buf[4] == 0xf0 || 65cabdff1aSopenharmony_ci p->buf[4] == 0xf1 || 66cabdff1aSopenharmony_ci p->buf[4] == 0xfc || 67cabdff1aSopenharmony_ci p->buf[4] == 0xfd) 68cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 69cabdff1aSopenharmony_ci return 0; 70cabdff1aSopenharmony_ci} 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_cistatic const uint32_t sample_rates[] = { 73cabdff1aSopenharmony_ci 8000, 4000, 8000, 11025, 16000, 74cabdff1aSopenharmony_ci 20000, 22050, 32000, 44100, 48000, 75cabdff1aSopenharmony_ci 96000, 192000, 64000, 76cabdff1aSopenharmony_ci}; 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_cistatic int parse_ext(AVFormatContext *s, int length) 79cabdff1aSopenharmony_ci{ 80cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 81cabdff1aSopenharmony_ci int64_t ret = 0; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci while (length > 0) { 84cabdff1aSopenharmony_ci int type = avio_r8(s->pb); 85cabdff1aSopenharmony_ci int index; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci switch (type) { 88cabdff1aSopenharmony_ci case 0x80: 89cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 1); 90cabdff1aSopenharmony_ci dhav->width = 8 * avio_r8(s->pb); 91cabdff1aSopenharmony_ci dhav->height = 8 * avio_r8(s->pb); 92cabdff1aSopenharmony_ci length -= 4; 93cabdff1aSopenharmony_ci break; 94cabdff1aSopenharmony_ci case 0x81: 95cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 1); 96cabdff1aSopenharmony_ci dhav->video_codec = avio_r8(s->pb); 97cabdff1aSopenharmony_ci dhav->frame_rate = avio_r8(s->pb); 98cabdff1aSopenharmony_ci length -= 4; 99cabdff1aSopenharmony_ci break; 100cabdff1aSopenharmony_ci case 0x82: 101cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 3); 102cabdff1aSopenharmony_ci dhav->width = avio_rl16(s->pb); 103cabdff1aSopenharmony_ci dhav->height = avio_rl16(s->pb); 104cabdff1aSopenharmony_ci length -= 8; 105cabdff1aSopenharmony_ci break; 106cabdff1aSopenharmony_ci case 0x83: 107cabdff1aSopenharmony_ci dhav->audio_channels = avio_r8(s->pb); 108cabdff1aSopenharmony_ci dhav->audio_codec = avio_r8(s->pb); 109cabdff1aSopenharmony_ci index = avio_r8(s->pb); 110cabdff1aSopenharmony_ci if (index < FF_ARRAY_ELEMS(sample_rates)) { 111cabdff1aSopenharmony_ci dhav->sample_rate = sample_rates[index]; 112cabdff1aSopenharmony_ci } else { 113cabdff1aSopenharmony_ci dhav->sample_rate = 8000; 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci length -= 4; 116cabdff1aSopenharmony_ci break; 117cabdff1aSopenharmony_ci case 0x88: 118cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 7); 119cabdff1aSopenharmony_ci length -= 8; 120cabdff1aSopenharmony_ci break; 121cabdff1aSopenharmony_ci case 0x8c: 122cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 1); 123cabdff1aSopenharmony_ci dhav->audio_channels = avio_r8(s->pb); 124cabdff1aSopenharmony_ci dhav->audio_codec = avio_r8(s->pb); 125cabdff1aSopenharmony_ci index = avio_r8(s->pb); 126cabdff1aSopenharmony_ci if (index < FF_ARRAY_ELEMS(sample_rates)) { 127cabdff1aSopenharmony_ci dhav->sample_rate = sample_rates[index]; 128cabdff1aSopenharmony_ci } else { 129cabdff1aSopenharmony_ci dhav->sample_rate = 8000; 130cabdff1aSopenharmony_ci } 131cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 3); 132cabdff1aSopenharmony_ci length -= 8; 133cabdff1aSopenharmony_ci break; 134cabdff1aSopenharmony_ci case 0x91: 135cabdff1aSopenharmony_ci case 0x92: 136cabdff1aSopenharmony_ci case 0x93: 137cabdff1aSopenharmony_ci case 0x95: 138cabdff1aSopenharmony_ci case 0x9a: 139cabdff1aSopenharmony_ci case 0x9b: // sample aspect ratio 140cabdff1aSopenharmony_ci case 0xb3: 141cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 7); 142cabdff1aSopenharmony_ci length -= 8; 143cabdff1aSopenharmony_ci break; 144cabdff1aSopenharmony_ci case 0x84: 145cabdff1aSopenharmony_ci case 0x85: 146cabdff1aSopenharmony_ci case 0x8b: 147cabdff1aSopenharmony_ci case 0x94: 148cabdff1aSopenharmony_ci case 0x96: 149cabdff1aSopenharmony_ci case 0xa0: 150cabdff1aSopenharmony_ci case 0xb2: 151cabdff1aSopenharmony_ci case 0xb4: 152cabdff1aSopenharmony_ci ret = avio_skip(s->pb, 3); 153cabdff1aSopenharmony_ci length -= 4; 154cabdff1aSopenharmony_ci break; 155cabdff1aSopenharmony_ci default: 156cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "Unknown type: %X, skipping rest of header.\n", type); 157cabdff1aSopenharmony_ci ret = avio_skip(s->pb, length - 1); 158cabdff1aSopenharmony_ci length = 0; 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci if (ret < 0) 162cabdff1aSopenharmony_ci return ret; 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci return 0; 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cistatic int read_chunk(AVFormatContext *s) 169cabdff1aSopenharmony_ci{ 170cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 171cabdff1aSopenharmony_ci int frame_length, ext_length; 172cabdff1aSopenharmony_ci int64_t start, end, ret; 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 175cabdff1aSopenharmony_ci return AVERROR_EOF; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci while (avio_r8(s->pb) != 'D' || avio_r8(s->pb) != 'H' || avio_r8(s->pb) != 'A' || avio_r8(s->pb) != 'V') { 178cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 179cabdff1aSopenharmony_ci return AVERROR_EOF; 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci start = avio_tell(s->pb) - 4; 183cabdff1aSopenharmony_ci dhav->last_good_pos = start; 184cabdff1aSopenharmony_ci dhav->type = avio_r8(s->pb); 185cabdff1aSopenharmony_ci dhav->subtype = avio_r8(s->pb); 186cabdff1aSopenharmony_ci dhav->channel = avio_r8(s->pb); 187cabdff1aSopenharmony_ci dhav->frame_subnumber = avio_r8(s->pb); 188cabdff1aSopenharmony_ci dhav->frame_number = avio_rl32(s->pb); 189cabdff1aSopenharmony_ci frame_length = avio_rl32(s->pb); 190cabdff1aSopenharmony_ci dhav->date = avio_rl32(s->pb); 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci if (frame_length < 24) 193cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 194cabdff1aSopenharmony_ci if (dhav->type == 0xf1) { 195cabdff1aSopenharmony_ci ret = avio_skip(s->pb, frame_length - 20); 196cabdff1aSopenharmony_ci return ret < 0 ? ret : 0; 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci 199cabdff1aSopenharmony_ci dhav->timestamp = avio_rl16(s->pb); 200cabdff1aSopenharmony_ci ext_length = avio_r8(s->pb); 201cabdff1aSopenharmony_ci avio_skip(s->pb, 1); // checksum 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci ret = parse_ext(s, ext_length); 204cabdff1aSopenharmony_ci if (ret < 0) 205cabdff1aSopenharmony_ci return ret; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci end = avio_tell(s->pb); 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci return frame_length - 8 - (end - start); 210cabdff1aSopenharmony_ci} 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_cistatic void get_timeinfo(unsigned date, struct tm *timeinfo) 213cabdff1aSopenharmony_ci{ 214cabdff1aSopenharmony_ci int year, month, day, hour, min, sec; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci sec = date & 0x3F; 217cabdff1aSopenharmony_ci min = (date >> 6) & 0x3F; 218cabdff1aSopenharmony_ci hour = (date >> 12) & 0x1F; 219cabdff1aSopenharmony_ci day = (date >> 17) & 0x1F; 220cabdff1aSopenharmony_ci month = (date >> 22) & 0x0F; 221cabdff1aSopenharmony_ci year = ((date >> 26) & 0x3F) + 2000; 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci timeinfo->tm_year = year - 1900; 224cabdff1aSopenharmony_ci timeinfo->tm_mon = month - 1; 225cabdff1aSopenharmony_ci timeinfo->tm_mday = day; 226cabdff1aSopenharmony_ci timeinfo->tm_hour = hour; 227cabdff1aSopenharmony_ci timeinfo->tm_min = min; 228cabdff1aSopenharmony_ci timeinfo->tm_sec = sec; 229cabdff1aSopenharmony_ci} 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_cistatic int64_t get_duration(AVFormatContext *s) 232cabdff1aSopenharmony_ci{ 233cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 234cabdff1aSopenharmony_ci int64_t start_pos = avio_tell(s->pb); 235cabdff1aSopenharmony_ci int64_t start = 0, end = 0; 236cabdff1aSopenharmony_ci struct tm timeinfo; 237cabdff1aSopenharmony_ci int max_interations = 100000; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci if (!s->pb->seekable) 240cabdff1aSopenharmony_ci return 0; 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci avio_seek(s->pb, avio_size(s->pb) - 8, SEEK_SET); 243cabdff1aSopenharmony_ci while (avio_tell(s->pb) > 12 && max_interations--) { 244cabdff1aSopenharmony_ci if (avio_rl32(s->pb) == MKTAG('d','h','a','v')) { 245cabdff1aSopenharmony_ci int64_t seek_back = avio_rl32(s->pb); 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci avio_seek(s->pb, -seek_back, SEEK_CUR); 248cabdff1aSopenharmony_ci read_chunk(s); 249cabdff1aSopenharmony_ci get_timeinfo(dhav->date, &timeinfo); 250cabdff1aSopenharmony_ci end = av_timegm(&timeinfo) * 1000LL; 251cabdff1aSopenharmony_ci break; 252cabdff1aSopenharmony_ci } else { 253cabdff1aSopenharmony_ci avio_seek(s->pb, -12, SEEK_CUR); 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci avio_seek(s->pb, start_pos, SEEK_SET); 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci read_chunk(s); 260cabdff1aSopenharmony_ci get_timeinfo(dhav->date, &timeinfo); 261cabdff1aSopenharmony_ci start = av_timegm(&timeinfo) * 1000LL; 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci avio_seek(s->pb, start_pos, SEEK_SET); 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci return end - start; 266cabdff1aSopenharmony_ci} 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_cistatic int dhav_read_header(AVFormatContext *s) 269cabdff1aSopenharmony_ci{ 270cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 271cabdff1aSopenharmony_ci uint8_t signature[5]; 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci ffio_ensure_seekback(s->pb, 5); 274cabdff1aSopenharmony_ci avio_read(s->pb, signature, sizeof(signature)); 275cabdff1aSopenharmony_ci if (!memcmp(signature, "DAHUA", 5)) { 276cabdff1aSopenharmony_ci avio_skip(s->pb, 0x400 - 5); 277cabdff1aSopenharmony_ci dhav->last_good_pos = avio_tell(s->pb); 278cabdff1aSopenharmony_ci } else { 279cabdff1aSopenharmony_ci if (!memcmp(signature, "DHAV", 4)) { 280cabdff1aSopenharmony_ci avio_seek(s->pb, -5, SEEK_CUR); 281cabdff1aSopenharmony_ci dhav->last_good_pos = avio_tell(s->pb); 282cabdff1aSopenharmony_ci } else if (s->pb->seekable) { 283cabdff1aSopenharmony_ci avio_seek(s->pb, avio_size(s->pb) - 8, SEEK_SET); 284cabdff1aSopenharmony_ci while (avio_rl32(s->pb) == MKTAG('d','h','a','v')) { 285cabdff1aSopenharmony_ci int seek_back; 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci seek_back = avio_rl32(s->pb) + 8; 288cabdff1aSopenharmony_ci if (seek_back < 9) 289cabdff1aSopenharmony_ci break; 290cabdff1aSopenharmony_ci dhav->last_good_pos = avio_tell(s->pb); 291cabdff1aSopenharmony_ci avio_seek(s->pb, -seek_back, SEEK_CUR); 292cabdff1aSopenharmony_ci } 293cabdff1aSopenharmony_ci avio_seek(s->pb, dhav->last_good_pos, SEEK_SET); 294cabdff1aSopenharmony_ci } 295cabdff1aSopenharmony_ci } 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci dhav->duration = get_duration(s); 298cabdff1aSopenharmony_ci dhav->last_good_pos = avio_tell(s->pb); 299cabdff1aSopenharmony_ci s->ctx_flags |= AVFMTCTX_NOHEADER; 300cabdff1aSopenharmony_ci dhav->video_stream_index = -1; 301cabdff1aSopenharmony_ci dhav->audio_stream_index = -1; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci return 0; 304cabdff1aSopenharmony_ci} 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_cistatic int64_t get_pts(AVFormatContext *s, int stream_index) 307cabdff1aSopenharmony_ci{ 308cabdff1aSopenharmony_ci DHAVStream *dst = s->streams[stream_index]->priv_data; 309cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 310cabdff1aSopenharmony_ci struct tm timeinfo; 311cabdff1aSopenharmony_ci time_t t; 312cabdff1aSopenharmony_ci 313cabdff1aSopenharmony_ci get_timeinfo(dhav->date, &timeinfo); 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci t = av_timegm(&timeinfo); 316cabdff1aSopenharmony_ci if (dst->last_time == t) { 317cabdff1aSopenharmony_ci int64_t diff = dhav->timestamp - dst->last_timestamp; 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci if (diff < 0) 320cabdff1aSopenharmony_ci diff += 65535; 321cabdff1aSopenharmony_ci if (diff == 0 && dhav->frame_rate) 322cabdff1aSopenharmony_ci diff = av_rescale(dhav->frame_number - dst->last_frame_number, 1000, dhav->frame_rate); 323cabdff1aSopenharmony_ci dst->pts += diff; 324cabdff1aSopenharmony_ci } else { 325cabdff1aSopenharmony_ci dst->pts = t * 1000LL; 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_ci dst->last_time = t; 329cabdff1aSopenharmony_ci dst->last_timestamp = dhav->timestamp; 330cabdff1aSopenharmony_ci dst->last_frame_number = dhav->frame_number; 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_ci return dst->pts; 333cabdff1aSopenharmony_ci} 334cabdff1aSopenharmony_ci 335cabdff1aSopenharmony_cistatic int dhav_read_packet(AVFormatContext *s, AVPacket *pkt) 336cabdff1aSopenharmony_ci{ 337cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 338cabdff1aSopenharmony_ci int size, ret, stream_index; 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_ciretry: 341cabdff1aSopenharmony_ci while ((ret = read_chunk(s)) == 0) 342cabdff1aSopenharmony_ci ; 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci if (ret < 0) 345cabdff1aSopenharmony_ci return ret; 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci if (dhav->type == 0xfd && dhav->video_stream_index == -1) { 348cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 349cabdff1aSopenharmony_ci DHAVStream *dst; 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci if (!st) 352cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 355cabdff1aSopenharmony_ci switch (dhav->video_codec) { 356cabdff1aSopenharmony_ci case 0x1: st->codecpar->codec_id = AV_CODEC_ID_MPEG4; break; 357cabdff1aSopenharmony_ci case 0x3: st->codecpar->codec_id = AV_CODEC_ID_MJPEG; break; 358cabdff1aSopenharmony_ci case 0x2: 359cabdff1aSopenharmony_ci case 0x4: 360cabdff1aSopenharmony_ci case 0x8: st->codecpar->codec_id = AV_CODEC_ID_H264; break; 361cabdff1aSopenharmony_ci case 0xc: st->codecpar->codec_id = AV_CODEC_ID_HEVC; break; 362cabdff1aSopenharmony_ci default: avpriv_request_sample(s, "Unknown video codec %X", dhav->video_codec); 363cabdff1aSopenharmony_ci } 364cabdff1aSopenharmony_ci st->duration = dhav->duration; 365cabdff1aSopenharmony_ci st->codecpar->width = dhav->width; 366cabdff1aSopenharmony_ci st->codecpar->height = dhav->height; 367cabdff1aSopenharmony_ci st->avg_frame_rate.num = dhav->frame_rate; 368cabdff1aSopenharmony_ci st->avg_frame_rate.den = 1; 369cabdff1aSopenharmony_ci st->priv_data = dst = av_mallocz(sizeof(DHAVStream)); 370cabdff1aSopenharmony_ci if (!st->priv_data) 371cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 372cabdff1aSopenharmony_ci dst->last_time = AV_NOPTS_VALUE; 373cabdff1aSopenharmony_ci dhav->video_stream_index = st->index; 374cabdff1aSopenharmony_ci 375cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, 1000); 376cabdff1aSopenharmony_ci } else if (dhav->type == 0xf0 && dhav->audio_stream_index == -1) { 377cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 378cabdff1aSopenharmony_ci DHAVStream *dst; 379cabdff1aSopenharmony_ci 380cabdff1aSopenharmony_ci if (!st) 381cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 384cabdff1aSopenharmony_ci switch (dhav->audio_codec) { 385cabdff1aSopenharmony_ci case 0x07: st->codecpar->codec_id = AV_CODEC_ID_PCM_S8; break; 386cabdff1aSopenharmony_ci case 0x0c: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break; 387cabdff1aSopenharmony_ci case 0x10: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break; 388cabdff1aSopenharmony_ci case 0x0a: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break; 389cabdff1aSopenharmony_ci case 0x16: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break; 390cabdff1aSopenharmony_ci case 0x0e: st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; break; 391cabdff1aSopenharmony_ci case 0x1a: st->codecpar->codec_id = AV_CODEC_ID_AAC; break; 392cabdff1aSopenharmony_ci case 0x1f: st->codecpar->codec_id = AV_CODEC_ID_MP2; break; 393cabdff1aSopenharmony_ci case 0x21: st->codecpar->codec_id = AV_CODEC_ID_MP3; break; 394cabdff1aSopenharmony_ci case 0x0d: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_MS; break; 395cabdff1aSopenharmony_ci default: avpriv_request_sample(s, "Unknown audio codec %X", dhav->audio_codec); 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci st->duration = dhav->duration; 398cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels = dhav->audio_channels; 399cabdff1aSopenharmony_ci st->codecpar->sample_rate = dhav->sample_rate; 400cabdff1aSopenharmony_ci st->priv_data = dst = av_mallocz(sizeof(DHAVStream)); 401cabdff1aSopenharmony_ci if (!st->priv_data) 402cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 403cabdff1aSopenharmony_ci dst->last_time = AV_NOPTS_VALUE; 404cabdff1aSopenharmony_ci dhav->audio_stream_index = st->index; 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, 1000); 407cabdff1aSopenharmony_ci } 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci stream_index = dhav->type == 0xf0 ? dhav->audio_stream_index : dhav->video_stream_index; 410cabdff1aSopenharmony_ci if (stream_index < 0) { 411cabdff1aSopenharmony_ci avio_skip(s->pb, ret); 412cabdff1aSopenharmony_ci if (avio_rl32(s->pb) == MKTAG('d','h','a','v')) 413cabdff1aSopenharmony_ci avio_skip(s->pb, 4); 414cabdff1aSopenharmony_ci goto retry; 415cabdff1aSopenharmony_ci } 416cabdff1aSopenharmony_ci 417cabdff1aSopenharmony_ci size = ret; 418cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, size); 419cabdff1aSopenharmony_ci if (ret < 0) 420cabdff1aSopenharmony_ci return ret; 421cabdff1aSopenharmony_ci pkt->stream_index = stream_index; 422cabdff1aSopenharmony_ci if (dhav->type != 0xfc) 423cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 424cabdff1aSopenharmony_ci pkt->duration = 1; 425cabdff1aSopenharmony_ci if (pkt->stream_index >= 0) 426cabdff1aSopenharmony_ci pkt->pts = get_pts(s, pkt->stream_index); 427cabdff1aSopenharmony_ci pkt->pos = dhav->last_good_pos; 428cabdff1aSopenharmony_ci if (avio_rl32(s->pb) == MKTAG('d','h','a','v')) 429cabdff1aSopenharmony_ci avio_skip(s->pb, 4); 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci return ret; 432cabdff1aSopenharmony_ci} 433cabdff1aSopenharmony_ci 434cabdff1aSopenharmony_cistatic int dhav_read_seek(AVFormatContext *s, int stream_index, 435cabdff1aSopenharmony_ci int64_t timestamp, int flags) 436cabdff1aSopenharmony_ci{ 437cabdff1aSopenharmony_ci DHAVContext *dhav = s->priv_data; 438cabdff1aSopenharmony_ci AVStream *st = s->streams[stream_index]; 439cabdff1aSopenharmony_ci FFStream *const sti = ffstream(st); 440cabdff1aSopenharmony_ci int index = av_index_search_timestamp(st, timestamp, flags); 441cabdff1aSopenharmony_ci int64_t pts; 442cabdff1aSopenharmony_ci 443cabdff1aSopenharmony_ci if (index < 0) 444cabdff1aSopenharmony_ci return -1; 445cabdff1aSopenharmony_ci pts = sti->index_entries[index].timestamp; 446cabdff1aSopenharmony_ci if (pts < timestamp) 447cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 448cabdff1aSopenharmony_ci if (avio_seek(s->pb, sti->index_entries[index].pos, SEEK_SET) < 0) 449cabdff1aSopenharmony_ci return -1; 450cabdff1aSopenharmony_ci 451cabdff1aSopenharmony_ci for (int n = 0; n < s->nb_streams; n++) { 452cabdff1aSopenharmony_ci AVStream *st = s->streams[n]; 453cabdff1aSopenharmony_ci DHAVStream *dst = st->priv_data; 454cabdff1aSopenharmony_ci 455cabdff1aSopenharmony_ci dst->pts = pts; 456cabdff1aSopenharmony_ci dst->last_time = AV_NOPTS_VALUE; 457cabdff1aSopenharmony_ci } 458cabdff1aSopenharmony_ci dhav->last_good_pos = avio_tell(s->pb); 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci return 0; 461cabdff1aSopenharmony_ci} 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ciconst AVInputFormat ff_dhav_demuxer = { 464cabdff1aSopenharmony_ci .name = "dhav", 465cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Video DAV"), 466cabdff1aSopenharmony_ci .priv_data_size = sizeof(DHAVContext), 467cabdff1aSopenharmony_ci .read_probe = dhav_probe, 468cabdff1aSopenharmony_ci .read_header = dhav_read_header, 469cabdff1aSopenharmony_ci .read_packet = dhav_read_packet, 470cabdff1aSopenharmony_ci .read_seek = dhav_read_seek, 471cabdff1aSopenharmony_ci .extensions = "dav", 472cabdff1aSopenharmony_ci .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK | AVFMT_TS_DISCONT | AVFMT_TS_NONSTRICT | AVFMT_SEEK_TO_PTS, 473cabdff1aSopenharmony_ci}; 474