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