1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Windows Television (WTV) demuxer
3cabdff1aSopenharmony_ci * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Windows Television (WTV) demuxer
25cabdff1aSopenharmony_ci * @author Peter Ross <pross@xvid.org>
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include <inttypes.h>
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
32cabdff1aSopenharmony_ci#include "libavutil/intfloat.h"
33cabdff1aSopenharmony_ci#include "libavutil/time_internal.h"
34cabdff1aSopenharmony_ci#include "avformat.h"
35cabdff1aSopenharmony_ci#include "demux.h"
36cabdff1aSopenharmony_ci#include "internal.h"
37cabdff1aSopenharmony_ci#include "wtv.h"
38cabdff1aSopenharmony_ci#include "mpegts.h"
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci/* Macros for formatting GUIDs */
41cabdff1aSopenharmony_ci#define PRI_PRETTY_GUID \
42cabdff1aSopenharmony_ci    "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02x%02x%02x%02x%02x%02x%02x%02x"
43cabdff1aSopenharmony_ci#define ARG_PRETTY_GUID(g) \
44cabdff1aSopenharmony_ci    AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
45cabdff1aSopenharmony_ci#define LEN_PRETTY_GUID 34
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci/*
48cabdff1aSopenharmony_ci * File system routines
49cabdff1aSopenharmony_ci */
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_citypedef struct WtvFile {
52cabdff1aSopenharmony_ci    AVIOContext *pb_filesystem;  /**< file system (AVFormatContext->pb) */
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_ci    int sector_bits;     /**< sector shift bits; used to convert sector number into pb_filesystem offset */
55cabdff1aSopenharmony_ci    uint32_t *sectors;   /**< file allocation table */
56cabdff1aSopenharmony_ci    int nb_sectors;      /**< number of sectors */
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    int error;
59cabdff1aSopenharmony_ci    int64_t position;
60cabdff1aSopenharmony_ci    int64_t length;
61cabdff1aSopenharmony_ci} WtvFile;
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_cistatic int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
64cabdff1aSopenharmony_ci{
65cabdff1aSopenharmony_ci    return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
66cabdff1aSopenharmony_ci}
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci/**
69cabdff1aSopenharmony_ci * @return bytes read, AVERROR_EOF on end of file, or <0 on error
70cabdff1aSopenharmony_ci */
71cabdff1aSopenharmony_cistatic int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
72cabdff1aSopenharmony_ci{
73cabdff1aSopenharmony_ci    WtvFile *wf = opaque;
74cabdff1aSopenharmony_ci    AVIOContext *pb = wf->pb_filesystem;
75cabdff1aSopenharmony_ci    int nread = 0, n = 0;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    if (wf->error || pb->error)
78cabdff1aSopenharmony_ci        return -1;
79cabdff1aSopenharmony_ci    if (wf->position >= wf->length || avio_feof(pb))
80cabdff1aSopenharmony_ci        return AVERROR_EOF;
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    buf_size = FFMIN(buf_size, wf->length - wf->position);
83cabdff1aSopenharmony_ci    while(nread < buf_size) {
84cabdff1aSopenharmony_ci        int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1));
85cabdff1aSopenharmony_ci        int read_request        = FFMIN(buf_size - nread, remaining_in_sector);
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci        n = avio_read(pb, buf, read_request);
88cabdff1aSopenharmony_ci        if (n <= 0)
89cabdff1aSopenharmony_ci            break;
90cabdff1aSopenharmony_ci        nread += n;
91cabdff1aSopenharmony_ci        buf += n;
92cabdff1aSopenharmony_ci        wf->position += n;
93cabdff1aSopenharmony_ci        if (n == remaining_in_sector) {
94cabdff1aSopenharmony_ci            int i = wf->position >> wf->sector_bits;
95cabdff1aSopenharmony_ci            if (i >= wf->nb_sectors ||
96cabdff1aSopenharmony_ci                (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
97cabdff1aSopenharmony_ci                seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
98cabdff1aSopenharmony_ci                wf->error = 1;
99cabdff1aSopenharmony_ci                break;
100cabdff1aSopenharmony_ci            }
101cabdff1aSopenharmony_ci        }
102cabdff1aSopenharmony_ci    }
103cabdff1aSopenharmony_ci    return nread ? nread : n;
104cabdff1aSopenharmony_ci}
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_ci/**
107cabdff1aSopenharmony_ci * @return position (or file length)
108cabdff1aSopenharmony_ci */
109cabdff1aSopenharmony_cistatic int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
110cabdff1aSopenharmony_ci{
111cabdff1aSopenharmony_ci    WtvFile *wf = opaque;
112cabdff1aSopenharmony_ci    AVIOContext *pb = wf->pb_filesystem;
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci    if (whence == AVSEEK_SIZE)
115cabdff1aSopenharmony_ci        return wf->length;
116cabdff1aSopenharmony_ci    else if (whence == SEEK_CUR)
117cabdff1aSopenharmony_ci        offset = wf->position + offset;
118cabdff1aSopenharmony_ci    else if (whence == SEEK_END)
119cabdff1aSopenharmony_ci        offset = wf->length;
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci    wf->error = offset < 0 || offset >= wf->length ||
122cabdff1aSopenharmony_ci                seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
123cabdff1aSopenharmony_ci                               offset & ((1 << wf->sector_bits) - 1)) < 0;
124cabdff1aSopenharmony_ci    wf->position = offset;
125cabdff1aSopenharmony_ci    return offset;
126cabdff1aSopenharmony_ci}
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci/**
129cabdff1aSopenharmony_ci * read non-zero integers (le32) from input stream
130cabdff1aSopenharmony_ci * @param pb
131cabdff1aSopenharmony_ci * @param[out] data destination
132cabdff1aSopenharmony_ci * @param     count maximum number of integers to read
133cabdff1aSopenharmony_ci * @return    total number of integers read
134cabdff1aSopenharmony_ci */
135cabdff1aSopenharmony_cistatic int read_ints(AVIOContext *pb, uint32_t *data, int count)
136cabdff1aSopenharmony_ci{
137cabdff1aSopenharmony_ci    int i, total = 0;
138cabdff1aSopenharmony_ci    for (i = 0; i < count; i++) {
139cabdff1aSopenharmony_ci        if ((data[total] = avio_rl32(pb)))
140cabdff1aSopenharmony_ci           total++;
141cabdff1aSopenharmony_ci    }
142cabdff1aSopenharmony_ci    return total;
143cabdff1aSopenharmony_ci}
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci/**
146cabdff1aSopenharmony_ci * Open file
147cabdff1aSopenharmony_ci * @param first_sector  First sector
148cabdff1aSopenharmony_ci * @param length        Length of file (bytes)
149cabdff1aSopenharmony_ci * @param depth         File allocation table depth
150cabdff1aSopenharmony_ci * @return NULL on error
151cabdff1aSopenharmony_ci */
152cabdff1aSopenharmony_cistatic AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length, int depth, AVFormatContext *s)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    AVIOContext *pb;
155cabdff1aSopenharmony_ci    WtvFile *wf;
156cabdff1aSopenharmony_ci    uint8_t *buffer;
157cabdff1aSopenharmony_ci    int64_t size;
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    if (seek_by_sector(s->pb, first_sector, 0) < 0)
160cabdff1aSopenharmony_ci        return NULL;
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    wf = av_mallocz(sizeof(WtvFile));
163cabdff1aSopenharmony_ci    if (!wf)
164cabdff1aSopenharmony_ci        return NULL;
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci    if (depth == 0) {
167cabdff1aSopenharmony_ci        wf->sectors = av_malloc(sizeof(uint32_t));
168cabdff1aSopenharmony_ci        if (!wf->sectors) {
169cabdff1aSopenharmony_ci            av_free(wf);
170cabdff1aSopenharmony_ci            return NULL;
171cabdff1aSopenharmony_ci        }
172cabdff1aSopenharmony_ci        wf->sectors[0]  = first_sector;
173cabdff1aSopenharmony_ci        wf->nb_sectors  = 1;
174cabdff1aSopenharmony_ci    } else if (depth == 1) {
175cabdff1aSopenharmony_ci        wf->sectors = av_malloc(WTV_SECTOR_SIZE);
176cabdff1aSopenharmony_ci        if (!wf->sectors) {
177cabdff1aSopenharmony_ci            av_free(wf);
178cabdff1aSopenharmony_ci            return NULL;
179cabdff1aSopenharmony_ci        }
180cabdff1aSopenharmony_ci        wf->nb_sectors  = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
181cabdff1aSopenharmony_ci    } else if (depth == 2) {
182cabdff1aSopenharmony_ci        uint32_t sectors1[WTV_SECTOR_SIZE / 4];
183cabdff1aSopenharmony_ci        int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4);
184cabdff1aSopenharmony_ci        int i;
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci        wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS);
187cabdff1aSopenharmony_ci        if (!wf->sectors) {
188cabdff1aSopenharmony_ci            av_free(wf);
189cabdff1aSopenharmony_ci            return NULL;
190cabdff1aSopenharmony_ci        }
191cabdff1aSopenharmony_ci        wf->nb_sectors = 0;
192cabdff1aSopenharmony_ci        for (i = 0; i < nb_sectors1; i++) {
193cabdff1aSopenharmony_ci            if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
194cabdff1aSopenharmony_ci                break;
195cabdff1aSopenharmony_ci            wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
196cabdff1aSopenharmony_ci        }
197cabdff1aSopenharmony_ci    } else {
198cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
199cabdff1aSopenharmony_ci        av_free(wf);
200cabdff1aSopenharmony_ci        return NULL;
201cabdff1aSopenharmony_ci    }
202cabdff1aSopenharmony_ci    wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    if (!wf->nb_sectors) {
205cabdff1aSopenharmony_ci        av_freep(&wf->sectors);
206cabdff1aSopenharmony_ci        av_freep(&wf);
207cabdff1aSopenharmony_ci        return NULL;
208cabdff1aSopenharmony_ci    }
209cabdff1aSopenharmony_ci
210cabdff1aSopenharmony_ci    size = avio_size(s->pb);
211cabdff1aSopenharmony_ci    if (size >= 0 && (int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > size)
212cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "truncated file\n");
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ci    /* check length */
215cabdff1aSopenharmony_ci    length &= 0xFFFFFFFFFFFF;
216cabdff1aSopenharmony_ci    if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) {
217cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits);
218cabdff1aSopenharmony_ci        length = (int64_t)wf->nb_sectors <<  wf->sector_bits;
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci    wf->length = length;
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci    /* seek to initial sector */
223cabdff1aSopenharmony_ci    wf->position = 0;
224cabdff1aSopenharmony_ci    if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
225cabdff1aSopenharmony_ci        av_freep(&wf->sectors);
226cabdff1aSopenharmony_ci        av_freep(&wf);
227cabdff1aSopenharmony_ci        return NULL;
228cabdff1aSopenharmony_ci    }
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    wf->pb_filesystem = s->pb;
231cabdff1aSopenharmony_ci    buffer = av_malloc(1 << wf->sector_bits);
232cabdff1aSopenharmony_ci    if (!buffer) {
233cabdff1aSopenharmony_ci        av_freep(&wf->sectors);
234cabdff1aSopenharmony_ci        av_freep(&wf);
235cabdff1aSopenharmony_ci        return NULL;
236cabdff1aSopenharmony_ci    }
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
239cabdff1aSopenharmony_ci                           wtvfile_read_packet, NULL, wtvfile_seek);
240cabdff1aSopenharmony_ci    if (!pb) {
241cabdff1aSopenharmony_ci        av_freep(&buffer);
242cabdff1aSopenharmony_ci        av_freep(&wf->sectors);
243cabdff1aSopenharmony_ci        av_freep(&wf);
244cabdff1aSopenharmony_ci    }
245cabdff1aSopenharmony_ci    return pb;
246cabdff1aSopenharmony_ci}
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_ci/**
249cabdff1aSopenharmony_ci * Open file using filename
250cabdff1aSopenharmony_ci * @param[in]  buf       directory buffer
251cabdff1aSopenharmony_ci * @param      buf_size  directory buffer size
252cabdff1aSopenharmony_ci * @param[in]  filename
253cabdff1aSopenharmony_ci * @param      filename_size size of filename
254cabdff1aSopenharmony_ci * @return NULL on error
255cabdff1aSopenharmony_ci */
256cabdff1aSopenharmony_cistatic AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
257cabdff1aSopenharmony_ci{
258cabdff1aSopenharmony_ci    const uint8_t *buf_end = buf + buf_size;
259cabdff1aSopenharmony_ci
260cabdff1aSopenharmony_ci    while(buf + 48 <= buf_end) {
261cabdff1aSopenharmony_ci        int dir_length, name_size, first_sector, depth;
262cabdff1aSopenharmony_ci        uint64_t file_length;
263cabdff1aSopenharmony_ci        const uint8_t *name;
264cabdff1aSopenharmony_ci        if (ff_guidcmp(buf, ff_dir_entry_guid)) {
265cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; "
266cabdff1aSopenharmony_ci                   "remaining directory entries ignored\n", FF_ARG_GUID(buf));
267cabdff1aSopenharmony_ci            break;
268cabdff1aSopenharmony_ci        }
269cabdff1aSopenharmony_ci        dir_length  = AV_RL16(buf + 16);
270cabdff1aSopenharmony_ci        file_length = AV_RL64(buf + 24);
271cabdff1aSopenharmony_ci        name_size   = 2 * AV_RL32(buf + 32);
272cabdff1aSopenharmony_ci        if (name_size < 0) {
273cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR,
274cabdff1aSopenharmony_ci                   "bad filename length, remaining directory entries ignored\n");
275cabdff1aSopenharmony_ci            break;
276cabdff1aSopenharmony_ci        }
277cabdff1aSopenharmony_ci        if (dir_length == 0) {
278cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR,
279cabdff1aSopenharmony_ci                   "bad dir length, remaining directory entries ignored\n");
280cabdff1aSopenharmony_ci            break;
281cabdff1aSopenharmony_ci        }
282cabdff1aSopenharmony_ci        if (48 + (int64_t)name_size > buf_end - buf) {
283cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
284cabdff1aSopenharmony_ci            break;
285cabdff1aSopenharmony_ci        }
286cabdff1aSopenharmony_ci        first_sector = AV_RL32(buf + 40 + name_size);
287cabdff1aSopenharmony_ci        depth        = AV_RL32(buf + 44 + name_size);
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci        /* compare file name; test optional null terminator */
290cabdff1aSopenharmony_ci        name = buf + 40;
291cabdff1aSopenharmony_ci        if (name_size >= filename_size &&
292cabdff1aSopenharmony_ci            !memcmp(name, filename, filename_size) &&
293cabdff1aSopenharmony_ci            (name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
294cabdff1aSopenharmony_ci            return wtvfile_open_sector(first_sector, file_length, depth, s);
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_ci        buf += dir_length;
297cabdff1aSopenharmony_ci    }
298cabdff1aSopenharmony_ci    return NULL;
299cabdff1aSopenharmony_ci}
300cabdff1aSopenharmony_ci
301cabdff1aSopenharmony_ci#define wtvfile_open(s, buf, buf_size, filename) \
302cabdff1aSopenharmony_ci    wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci/**
305cabdff1aSopenharmony_ci * Close file opened with wtvfile_open_sector(), or wtv_open()
306cabdff1aSopenharmony_ci */
307cabdff1aSopenharmony_cistatic void wtvfile_close(AVIOContext *pb)
308cabdff1aSopenharmony_ci{
309cabdff1aSopenharmony_ci    WtvFile *wf = pb->opaque;
310cabdff1aSopenharmony_ci    av_freep(&wf->sectors);
311cabdff1aSopenharmony_ci    av_freep(&pb->opaque);
312cabdff1aSopenharmony_ci    av_freep(&pb->buffer);
313cabdff1aSopenharmony_ci    avio_context_free(&pb);
314cabdff1aSopenharmony_ci}
315cabdff1aSopenharmony_ci
316cabdff1aSopenharmony_ci/*
317cabdff1aSopenharmony_ci * Main demuxer
318cabdff1aSopenharmony_ci */
319cabdff1aSopenharmony_ci
320cabdff1aSopenharmony_citypedef struct WtvStream {
321cabdff1aSopenharmony_ci    int seen_data;
322cabdff1aSopenharmony_ci} WtvStream;
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_citypedef struct WtvContext {
325cabdff1aSopenharmony_ci    AVIOContext *pb;       /**< timeline file */
326cabdff1aSopenharmony_ci    int64_t epoch;
327cabdff1aSopenharmony_ci    int64_t pts;             /**< pts for next data chunk */
328cabdff1aSopenharmony_ci    int64_t last_valid_pts;  /**< latest valid pts, used for interactive seeking */
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ci    /* maintain private seek index, as the AVIndexEntry->pos is relative to the
331cabdff1aSopenharmony_ci       start of the 'timeline' file, not the file system (AVFormatContext->pb) */
332cabdff1aSopenharmony_ci    AVIndexEntry *index_entries;
333cabdff1aSopenharmony_ci    int nb_index_entries;
334cabdff1aSopenharmony_ci    unsigned int index_entries_allocated_size;
335cabdff1aSopenharmony_ci} WtvContext;
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci/* WTV GUIDs */
338cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_SubtitleSpanningEvent =
339cabdff1aSopenharmony_ci    {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A};
340cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_LanguageSpanningEvent =
341cabdff1aSopenharmony_ci    {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95};
342cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent =
343cabdff1aSopenharmony_ci    {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E};
344cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent =
345cabdff1aSopenharmony_ci    {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24};
346cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_CSDescriptorSpanningEvent =
347cabdff1aSopenharmony_ci    {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66};
348cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent =
349cabdff1aSopenharmony_ci    {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B};
350cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_StreamIDSpanningEvent =
351cabdff1aSopenharmony_ci    {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE};
352cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_TeletextSpanningEvent =
353cabdff1aSopenharmony_ci    {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3};
354cabdff1aSopenharmony_cistatic const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
355cabdff1aSopenharmony_ci    {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3};
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci/* Windows media GUIDs */
358cabdff1aSopenharmony_ci
359cabdff1aSopenharmony_ci/* Media types */
360cabdff1aSopenharmony_cistatic const ff_asf_guid mediasubtype_mpeg1payload =
361cabdff1aSopenharmony_ci    {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70};
362cabdff1aSopenharmony_cistatic const ff_asf_guid mediatype_mpeg2_sections =
363cabdff1aSopenharmony_ci    {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5};
364cabdff1aSopenharmony_cistatic const ff_asf_guid mediatype_mpeg2_pes =
365cabdff1aSopenharmony_ci    {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
366cabdff1aSopenharmony_cistatic const ff_asf_guid mediatype_mstvcaption =
367cabdff1aSopenharmony_ci    {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1};
368cabdff1aSopenharmony_ci
369cabdff1aSopenharmony_ci/* Media subtypes */
370cabdff1aSopenharmony_cistatic const ff_asf_guid mediasubtype_dvb_subtitle =
371cabdff1aSopenharmony_ci    {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F};
372cabdff1aSopenharmony_cistatic const ff_asf_guid mediasubtype_teletext =
373cabdff1aSopenharmony_ci    {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
374cabdff1aSopenharmony_cistatic const ff_asf_guid mediasubtype_dtvccdata =
375cabdff1aSopenharmony_ci    {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A};
376cabdff1aSopenharmony_cistatic const ff_asf_guid mediasubtype_mpeg2_sections =
377cabdff1aSopenharmony_ci    {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61};
378cabdff1aSopenharmony_ci
379cabdff1aSopenharmony_cistatic int read_probe(const AVProbeData *p)
380cabdff1aSopenharmony_ci{
381cabdff1aSopenharmony_ci    return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
382cabdff1aSopenharmony_ci}
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci/**
385cabdff1aSopenharmony_ci * Convert win32 FILETIME to ISO-8601 string
386cabdff1aSopenharmony_ci * @return <0 on error
387cabdff1aSopenharmony_ci */
388cabdff1aSopenharmony_cistatic int filetime_to_iso8601(char *buf, int buf_size, int64_t value)
389cabdff1aSopenharmony_ci{
390cabdff1aSopenharmony_ci    time_t t = (value / 10000000LL) - 11644473600LL;
391cabdff1aSopenharmony_ci    struct tm tmbuf;
392cabdff1aSopenharmony_ci    struct tm *tm = gmtime_r(&t, &tmbuf);
393cabdff1aSopenharmony_ci    if (!tm)
394cabdff1aSopenharmony_ci        return -1;
395cabdff1aSopenharmony_ci    if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
396cabdff1aSopenharmony_ci        return -1;
397cabdff1aSopenharmony_ci    return 0;
398cabdff1aSopenharmony_ci}
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci/**
401cabdff1aSopenharmony_ci * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string
402cabdff1aSopenharmony_ci * @return <0 on error
403cabdff1aSopenharmony_ci */
404cabdff1aSopenharmony_cistatic int crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
405cabdff1aSopenharmony_ci{
406cabdff1aSopenharmony_ci    time_t t = (value / 10000000LL) - 719162LL*86400LL;
407cabdff1aSopenharmony_ci    struct tm tmbuf;
408cabdff1aSopenharmony_ci    struct tm *tm = gmtime_r(&t, &tmbuf);
409cabdff1aSopenharmony_ci    if (!tm)
410cabdff1aSopenharmony_ci        return -1;
411cabdff1aSopenharmony_ci    if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
412cabdff1aSopenharmony_ci        return -1;
413cabdff1aSopenharmony_ci    return 0;
414cabdff1aSopenharmony_ci}
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci/**
417cabdff1aSopenharmony_ci * Convert OLE DATE to ISO-8601 string
418cabdff1aSopenharmony_ci * @return <0 on error
419cabdff1aSopenharmony_ci */
420cabdff1aSopenharmony_cistatic int oledate_to_iso8601(char *buf, int buf_size, int64_t value)
421cabdff1aSopenharmony_ci{
422cabdff1aSopenharmony_ci    time_t t = (av_int2double(value) - 25569.0) * 86400;
423cabdff1aSopenharmony_ci    struct tm tmbuf;
424cabdff1aSopenharmony_ci    struct tm *tm= gmtime_r(&t, &tmbuf);
425cabdff1aSopenharmony_ci    if (!tm)
426cabdff1aSopenharmony_ci        return -1;
427cabdff1aSopenharmony_ci    if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
428cabdff1aSopenharmony_ci        return -1;
429cabdff1aSopenharmony_ci    return 0;
430cabdff1aSopenharmony_ci}
431cabdff1aSopenharmony_ci
432cabdff1aSopenharmony_cistatic void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
433cabdff1aSopenharmony_ci{
434cabdff1aSopenharmony_ci    char mime[1024];
435cabdff1aSopenharmony_ci    char description[1024];
436cabdff1aSopenharmony_ci    unsigned int filesize;
437cabdff1aSopenharmony_ci    AVStream *st;
438cabdff1aSopenharmony_ci    int64_t pos = avio_tell(pb);
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
441cabdff1aSopenharmony_ci    if (strcmp(mime, "image/jpeg"))
442cabdff1aSopenharmony_ci        goto done;
443cabdff1aSopenharmony_ci
444cabdff1aSopenharmony_ci    avio_r8(pb);
445cabdff1aSopenharmony_ci    avio_get_str16le(pb, INT_MAX, description, sizeof(description));
446cabdff1aSopenharmony_ci    filesize = avio_rl32(pb);
447cabdff1aSopenharmony_ci    if (!filesize)
448cabdff1aSopenharmony_ci        goto done;
449cabdff1aSopenharmony_ci
450cabdff1aSopenharmony_ci    if (ff_add_attached_pic(s, NULL, pb, NULL, filesize) < 0)
451cabdff1aSopenharmony_ci        goto done;
452cabdff1aSopenharmony_ci    st = s->streams[s->nb_streams - 1];
453cabdff1aSopenharmony_ci    av_dict_set(&st->metadata, "title", description, 0);
454cabdff1aSopenharmony_ci    st->codecpar->codec_id   = AV_CODEC_ID_MJPEG;
455cabdff1aSopenharmony_ci    st->id = -1;
456cabdff1aSopenharmony_cidone:
457cabdff1aSopenharmony_ci    avio_seek(pb, pos + length, SEEK_SET);
458cabdff1aSopenharmony_ci}
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_cistatic void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length)
461cabdff1aSopenharmony_ci{
462cabdff1aSopenharmony_ci    int buf_size;
463cabdff1aSopenharmony_ci    char *buf;
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci    if (!strcmp(key, "WM/MediaThumbType")) {
466cabdff1aSopenharmony_ci        avio_skip(pb, length);
467cabdff1aSopenharmony_ci        return;
468cabdff1aSopenharmony_ci    }
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_ci    buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
471cabdff1aSopenharmony_ci    buf = av_malloc(buf_size);
472cabdff1aSopenharmony_ci    if (!buf)
473cabdff1aSopenharmony_ci        return;
474cabdff1aSopenharmony_ci
475cabdff1aSopenharmony_ci    if (type == 0 && length == 4) {
476cabdff1aSopenharmony_ci        snprintf(buf, buf_size, "%u", avio_rl32(pb));
477cabdff1aSopenharmony_ci    } else if (type == 1) {
478cabdff1aSopenharmony_ci        avio_get_str16le(pb, length, buf, buf_size);
479cabdff1aSopenharmony_ci        if (!strlen(buf)) {
480cabdff1aSopenharmony_ci           av_free(buf);
481cabdff1aSopenharmony_ci           return;
482cabdff1aSopenharmony_ci        }
483cabdff1aSopenharmony_ci    } else if (type == 3 && length == 4) {
484cabdff1aSopenharmony_ci        strcpy(buf, avio_rl32(pb) ? "true" : "false");
485cabdff1aSopenharmony_ci    } else if (type == 4 && length == 8) {
486cabdff1aSopenharmony_ci        int64_t num = avio_rl64(pb);
487cabdff1aSopenharmony_ci        if (!strcmp(key, "WM/EncodingTime") ||
488cabdff1aSopenharmony_ci            !strcmp(key, "WM/MediaOriginalBroadcastDateTime")) {
489cabdff1aSopenharmony_ci            if (filetime_to_iso8601(buf, buf_size, num) < 0) {
490cabdff1aSopenharmony_ci                av_free(buf);
491cabdff1aSopenharmony_ci                return;
492cabdff1aSopenharmony_ci            }
493cabdff1aSopenharmony_ci        } else if (!strcmp(key, "WM/WMRVEncodeTime") ||
494cabdff1aSopenharmony_ci                   !strcmp(key, "WM/WMRVEndTime")) {
495cabdff1aSopenharmony_ci            if (crazytime_to_iso8601(buf, buf_size, num) < 0) {
496cabdff1aSopenharmony_ci                av_free(buf);
497cabdff1aSopenharmony_ci                return;
498cabdff1aSopenharmony_ci            }
499cabdff1aSopenharmony_ci        } else if (!strcmp(key, "WM/WMRVExpirationDate")) {
500cabdff1aSopenharmony_ci            if (oledate_to_iso8601(buf, buf_size, num) < 0 ) {
501cabdff1aSopenharmony_ci                av_free(buf);
502cabdff1aSopenharmony_ci                return;
503cabdff1aSopenharmony_ci            }
504cabdff1aSopenharmony_ci        } else if (!strcmp(key, "WM/WMRVBitrate"))
505cabdff1aSopenharmony_ci            snprintf(buf, buf_size, "%f", av_int2double(num));
506cabdff1aSopenharmony_ci        else
507cabdff1aSopenharmony_ci            snprintf(buf, buf_size, "%"PRIi64, num);
508cabdff1aSopenharmony_ci    } else if (type == 5 && length == 2) {
509cabdff1aSopenharmony_ci        snprintf(buf, buf_size, "%u", avio_rl16(pb));
510cabdff1aSopenharmony_ci    } else if (type == 6 && length == 16) {
511cabdff1aSopenharmony_ci        ff_asf_guid guid;
512cabdff1aSopenharmony_ci        avio_read(pb, guid, 16);
513cabdff1aSopenharmony_ci        snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid));
514cabdff1aSopenharmony_ci    } else if (type == 2 && !strcmp(key, "WM/Picture")) {
515cabdff1aSopenharmony_ci        get_attachment(s, pb, length);
516cabdff1aSopenharmony_ci        av_freep(&buf);
517cabdff1aSopenharmony_ci        return;
518cabdff1aSopenharmony_ci    } else {
519cabdff1aSopenharmony_ci        av_freep(&buf);
520cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length);
521cabdff1aSopenharmony_ci        avio_skip(pb, length);
522cabdff1aSopenharmony_ci        return;
523cabdff1aSopenharmony_ci    }
524cabdff1aSopenharmony_ci
525cabdff1aSopenharmony_ci    av_dict_set(&s->metadata, key, buf, 0);
526cabdff1aSopenharmony_ci    av_freep(&buf);
527cabdff1aSopenharmony_ci}
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci/**
530cabdff1aSopenharmony_ci * Parse metadata entries
531cabdff1aSopenharmony_ci */
532cabdff1aSopenharmony_cistatic void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
533cabdff1aSopenharmony_ci{
534cabdff1aSopenharmony_ci    ff_asf_guid guid;
535cabdff1aSopenharmony_ci    int length, type;
536cabdff1aSopenharmony_ci    while(!avio_feof(pb)) {
537cabdff1aSopenharmony_ci        char key[1024];
538cabdff1aSopenharmony_ci        ff_get_guid(pb, &guid);
539cabdff1aSopenharmony_ci        type   = avio_rl32(pb);
540cabdff1aSopenharmony_ci        length = avio_rl32(pb);
541cabdff1aSopenharmony_ci        if (!length)
542cabdff1aSopenharmony_ci            break;
543cabdff1aSopenharmony_ci        if (ff_guidcmp(&guid, ff_metadata_guid)) {
544cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; "
545cabdff1aSopenharmony_ci                   "remaining metadata entries ignored\n", FF_ARG_GUID(guid));
546cabdff1aSopenharmony_ci            break;
547cabdff1aSopenharmony_ci        }
548cabdff1aSopenharmony_ci        avio_get_str16le(pb, INT_MAX, key, sizeof(key));
549cabdff1aSopenharmony_ci        get_tag(s, pb, key, type, length);
550cabdff1aSopenharmony_ci    }
551cabdff1aSopenharmony_ci
552cabdff1aSopenharmony_ci    ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv);
553cabdff1aSopenharmony_ci}
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci/**
556cabdff1aSopenharmony_ci * parse VIDEOINFOHEADER2 structure
557cabdff1aSopenharmony_ci * @return bytes consumed
558cabdff1aSopenharmony_ci */
559cabdff1aSopenharmony_cistatic int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
560cabdff1aSopenharmony_ci{
561cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
562cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
563cabdff1aSopenharmony_ci
564cabdff1aSopenharmony_ci    avio_skip(pb, 72);  // picture aspect ratio is unreliable
565cabdff1aSopenharmony_ci    st->codecpar->codec_tag = ff_get_bmp_header(pb, st, NULL);
566cabdff1aSopenharmony_ci
567cabdff1aSopenharmony_ci    return 72 + 40;
568cabdff1aSopenharmony_ci}
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_ci/**
571cabdff1aSopenharmony_ci * Parse MPEG1WAVEFORMATEX extradata structure
572cabdff1aSopenharmony_ci */
573cabdff1aSopenharmony_cistatic void parse_mpeg1waveformatex(AVStream *st)
574cabdff1aSopenharmony_ci{
575cabdff1aSopenharmony_ci    /* fwHeadLayer */
576cabdff1aSopenharmony_ci    switch (AV_RL16(st->codecpar->extradata)) {
577cabdff1aSopenharmony_ci    case 0x0001 : st->codecpar->codec_id = AV_CODEC_ID_MP1; break;
578cabdff1aSopenharmony_ci    case 0x0002 : st->codecpar->codec_id = AV_CODEC_ID_MP2; break;
579cabdff1aSopenharmony_ci    case 0x0004 : st->codecpar->codec_id = AV_CODEC_ID_MP3; break;
580cabdff1aSopenharmony_ci    }
581cabdff1aSopenharmony_ci
582cabdff1aSopenharmony_ci    st->codecpar->bit_rate = AV_RL32(st->codecpar->extradata + 2); /* dwHeadBitrate */
583cabdff1aSopenharmony_ci
584cabdff1aSopenharmony_ci    /* dwHeadMode */
585cabdff1aSopenharmony_ci    switch (AV_RL16(st->codecpar->extradata + 6)) {
586cabdff1aSopenharmony_ci    case 1 :
587cabdff1aSopenharmony_ci    case 2 :
588cabdff1aSopenharmony_ci    case 4 : st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
589cabdff1aSopenharmony_ci             break;
590cabdff1aSopenharmony_ci    case 8 : st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
591cabdff1aSopenharmony_ci             break;
592cabdff1aSopenharmony_ci    }
593cabdff1aSopenharmony_ci}
594cabdff1aSopenharmony_ci
595cabdff1aSopenharmony_ci/**
596cabdff1aSopenharmony_ci * Initialise stream
597cabdff1aSopenharmony_ci * @param st Stream to initialise, or NULL to create and initialise new stream
598cabdff1aSopenharmony_ci * @return NULL on error
599cabdff1aSopenharmony_ci */
600cabdff1aSopenharmony_cistatic AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type)
601cabdff1aSopenharmony_ci{
602cabdff1aSopenharmony_ci    if (st) {
603cabdff1aSopenharmony_ci        if (st->codecpar->extradata) {
604cabdff1aSopenharmony_ci            av_freep(&st->codecpar->extradata);
605cabdff1aSopenharmony_ci            st->codecpar->extradata_size = 0;
606cabdff1aSopenharmony_ci        }
607cabdff1aSopenharmony_ci    } else {
608cabdff1aSopenharmony_ci        WtvStream *wst = av_mallocz(sizeof(WtvStream));
609cabdff1aSopenharmony_ci        if (!wst)
610cabdff1aSopenharmony_ci            return NULL;
611cabdff1aSopenharmony_ci        st = avformat_new_stream(s, NULL);
612cabdff1aSopenharmony_ci        if (!st) {
613cabdff1aSopenharmony_ci            av_free(wst);
614cabdff1aSopenharmony_ci            return NULL;
615cabdff1aSopenharmony_ci        }
616cabdff1aSopenharmony_ci        st->id = sid;
617cabdff1aSopenharmony_ci        st->priv_data = wst;
618cabdff1aSopenharmony_ci    }
619cabdff1aSopenharmony_ci    st->codecpar->codec_type = codec_type;
620cabdff1aSopenharmony_ci    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL;
621cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, 10000000);
622cabdff1aSopenharmony_ci    return st;
623cabdff1aSopenharmony_ci}
624cabdff1aSopenharmony_ci
625cabdff1aSopenharmony_ci/**
626cabdff1aSopenharmony_ci * parse Media Type structure and populate stream
627cabdff1aSopenharmony_ci * @param st         Stream, or NULL to create new stream
628cabdff1aSopenharmony_ci * @param mediatype  Mediatype GUID
629cabdff1aSopenharmony_ci * @param subtype    Subtype GUID
630cabdff1aSopenharmony_ci * @param formattype Format GUID
631cabdff1aSopenharmony_ci * @param size       Size of format buffer
632cabdff1aSopenharmony_ci * @return NULL on error
633cabdff1aSopenharmony_ci */
634cabdff1aSopenharmony_cistatic AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
635cabdff1aSopenharmony_ci                                   ff_asf_guid mediatype, ff_asf_guid subtype,
636cabdff1aSopenharmony_ci                                   ff_asf_guid formattype, uint64_t size)
637cabdff1aSopenharmony_ci{
638cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
639cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
640cabdff1aSopenharmony_ci    if (!ff_guidcmp(subtype, ff_mediasubtype_cpfilters_processed) &&
641cabdff1aSopenharmony_ci        !ff_guidcmp(formattype, ff_format_cpfilters_processed)) {
642cabdff1aSopenharmony_ci        ff_asf_guid actual_subtype;
643cabdff1aSopenharmony_ci        ff_asf_guid actual_formattype;
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_ci        if (size < 32) {
646cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "format buffer size underflow\n");
647cabdff1aSopenharmony_ci            avio_skip(pb, size);
648cabdff1aSopenharmony_ci            return NULL;
649cabdff1aSopenharmony_ci        }
650cabdff1aSopenharmony_ci
651cabdff1aSopenharmony_ci        avio_skip(pb, size - 32);
652cabdff1aSopenharmony_ci        ff_get_guid(pb, &actual_subtype);
653cabdff1aSopenharmony_ci        ff_get_guid(pb, &actual_formattype);
654cabdff1aSopenharmony_ci        if (avio_feof(pb))
655cabdff1aSopenharmony_ci            return NULL;
656cabdff1aSopenharmony_ci        avio_seek(pb, -size, SEEK_CUR);
657cabdff1aSopenharmony_ci
658cabdff1aSopenharmony_ci        st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32);
659cabdff1aSopenharmony_ci        avio_skip(pb, 32);
660cabdff1aSopenharmony_ci        return st;
661cabdff1aSopenharmony_ci    } else if (!ff_guidcmp(mediatype, ff_mediatype_audio)) {
662cabdff1aSopenharmony_ci        st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO);
663cabdff1aSopenharmony_ci        if (!st)
664cabdff1aSopenharmony_ci            return NULL;
665cabdff1aSopenharmony_ci        if (!ff_guidcmp(formattype, ff_format_waveformatex)) {
666cabdff1aSopenharmony_ci            int ret = ff_get_wav_header(s, pb, st->codecpar, size, 0);
667cabdff1aSopenharmony_ci            if (ret < 0)
668cabdff1aSopenharmony_ci                return NULL;
669cabdff1aSopenharmony_ci        } else {
670cabdff1aSopenharmony_ci            if (ff_guidcmp(formattype, ff_format_none))
671cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
672cabdff1aSopenharmony_ci            avio_skip(pb, size);
673cabdff1aSopenharmony_ci        }
674cabdff1aSopenharmony_ci
675cabdff1aSopenharmony_ci        if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
676cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codecpar->bits_per_coded_sample);
677cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) {
678cabdff1aSopenharmony_ci            if (st->codecpar->extradata && st->codecpar->extradata_size >= 22)
679cabdff1aSopenharmony_ci                parse_mpeg1waveformatex(st);
680cabdff1aSopenharmony_ci            else
681cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n");
682cabdff1aSopenharmony_ci        } else {
683cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype);
684cabdff1aSopenharmony_ci            if (st->codecpar->codec_id == AV_CODEC_ID_NONE)
685cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
686cabdff1aSopenharmony_ci        }
687cabdff1aSopenharmony_ci        return st;
688cabdff1aSopenharmony_ci    } else if (!ff_guidcmp(mediatype, ff_mediatype_video)) {
689cabdff1aSopenharmony_ci        st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO);
690cabdff1aSopenharmony_ci        if (!st)
691cabdff1aSopenharmony_ci            return NULL;
692cabdff1aSopenharmony_ci        if (!ff_guidcmp(formattype, ff_format_videoinfo2)) {
693cabdff1aSopenharmony_ci            int consumed = parse_videoinfoheader2(s, st);
694cabdff1aSopenharmony_ci            avio_skip(pb, FFMAX(size - consumed, 0));
695cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) {
696cabdff1aSopenharmony_ci            uint64_t consumed = parse_videoinfoheader2(s, st);
697cabdff1aSopenharmony_ci            /* ignore extradata; files produced by windows media center contain meaningless mpeg1 sequence header */
698cabdff1aSopenharmony_ci            avio_skip(pb, FFMAX(size - consumed, 0));
699cabdff1aSopenharmony_ci        } else {
700cabdff1aSopenharmony_ci            if (ff_guidcmp(formattype, ff_format_none))
701cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
702cabdff1aSopenharmony_ci            avio_skip(pb, size);
703cabdff1aSopenharmony_ci        }
704cabdff1aSopenharmony_ci
705cabdff1aSopenharmony_ci        if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
706cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype));
707cabdff1aSopenharmony_ci        } else {
708cabdff1aSopenharmony_ci            st->codecpar->codec_id = ff_codec_guid_get_id(ff_video_guids, subtype);
709cabdff1aSopenharmony_ci        }
710cabdff1aSopenharmony_ci        if (st->codecpar->codec_id == AV_CODEC_ID_NONE)
711cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
712cabdff1aSopenharmony_ci        return st;
713cabdff1aSopenharmony_ci    } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) &&
714cabdff1aSopenharmony_ci               !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) {
715cabdff1aSopenharmony_ci        st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
716cabdff1aSopenharmony_ci        if (!st)
717cabdff1aSopenharmony_ci            return NULL;
718cabdff1aSopenharmony_ci        if (ff_guidcmp(formattype, ff_format_none))
719cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
720cabdff1aSopenharmony_ci        avio_skip(pb, size);
721cabdff1aSopenharmony_ci        st->codecpar->codec_id = AV_CODEC_ID_DVB_SUBTITLE;
722cabdff1aSopenharmony_ci        return st;
723cabdff1aSopenharmony_ci    } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) &&
724cabdff1aSopenharmony_ci               (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) {
725cabdff1aSopenharmony_ci        st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
726cabdff1aSopenharmony_ci        if (!st)
727cabdff1aSopenharmony_ci            return NULL;
728cabdff1aSopenharmony_ci        if (ff_guidcmp(formattype, ff_format_none))
729cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
730cabdff1aSopenharmony_ci        avio_skip(pb, size);
731cabdff1aSopenharmony_ci        st->codecpar->codec_id = !ff_guidcmp(subtype, mediasubtype_teletext) ? AV_CODEC_ID_DVB_TELETEXT : AV_CODEC_ID_EIA_608;
732cabdff1aSopenharmony_ci        return st;
733cabdff1aSopenharmony_ci    } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) &&
734cabdff1aSopenharmony_ci               !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) {
735cabdff1aSopenharmony_ci        if (ff_guidcmp(formattype, ff_format_none))
736cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
737cabdff1aSopenharmony_ci        avio_skip(pb, size);
738cabdff1aSopenharmony_ci        return NULL;
739cabdff1aSopenharmony_ci    }
740cabdff1aSopenharmony_ci
741cabdff1aSopenharmony_ci    av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID
742cabdff1aSopenharmony_ci                              ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n",
743cabdff1aSopenharmony_ci                              FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype));
744cabdff1aSopenharmony_ci    avio_skip(pb, size);
745cabdff1aSopenharmony_ci    return NULL;
746cabdff1aSopenharmony_ci}
747cabdff1aSopenharmony_ci
748cabdff1aSopenharmony_cienum {
749cabdff1aSopenharmony_ci    SEEK_TO_DATA = 0,
750cabdff1aSopenharmony_ci    SEEK_TO_PTS,
751cabdff1aSopenharmony_ci};
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci/**
754cabdff1aSopenharmony_ci * Try to seek over a broken chunk
755cabdff1aSopenharmony_ci * @return <0 on error
756cabdff1aSopenharmony_ci */
757cabdff1aSopenharmony_cistatic int recover(WtvContext *wtv, uint64_t broken_pos)
758cabdff1aSopenharmony_ci{
759cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
760cabdff1aSopenharmony_ci    int i;
761cabdff1aSopenharmony_ci    for (i = 0; i < wtv->nb_index_entries; i++) {
762cabdff1aSopenharmony_ci        if (wtv->index_entries[i].pos > broken_pos) {
763cabdff1aSopenharmony_ci            int64_t ret = avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET);
764cabdff1aSopenharmony_ci            if (ret < 0)
765cabdff1aSopenharmony_ci                return ret;
766cabdff1aSopenharmony_ci            wtv->pts = wtv->index_entries[i].timestamp;
767cabdff1aSopenharmony_ci            return 0;
768cabdff1aSopenharmony_ci         }
769cabdff1aSopenharmony_ci     }
770cabdff1aSopenharmony_ci     return AVERROR(EIO);
771cabdff1aSopenharmony_ci}
772cabdff1aSopenharmony_ci
773cabdff1aSopenharmony_ci/**
774cabdff1aSopenharmony_ci * Parse WTV chunks
775cabdff1aSopenharmony_ci * @param mode SEEK_TO_DATA or SEEK_TO_PTS
776cabdff1aSopenharmony_ci * @param seekts timestamp
777cabdff1aSopenharmony_ci * @param[out] len_ptr Length of data chunk
778cabdff1aSopenharmony_ci * @return stream index of data chunk, or <0 on error
779cabdff1aSopenharmony_ci */
780cabdff1aSopenharmony_cistatic int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
781cabdff1aSopenharmony_ci{
782cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
783cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
784cabdff1aSopenharmony_ci    while (!avio_feof(pb)) {
785cabdff1aSopenharmony_ci        ff_asf_guid g;
786cabdff1aSopenharmony_ci        int len, sid, consumed;
787cabdff1aSopenharmony_ci
788cabdff1aSopenharmony_ci        ff_get_guid(pb, &g);
789cabdff1aSopenharmony_ci        len = avio_rl32(pb);
790cabdff1aSopenharmony_ci        if (len < 32 || len > INT_MAX - 7) {
791cabdff1aSopenharmony_ci            int ret;
792cabdff1aSopenharmony_ci            if (avio_feof(pb))
793cabdff1aSopenharmony_ci                return AVERROR_EOF;
794cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "encountered broken chunk\n");
795cabdff1aSopenharmony_ci            if ((ret = recover(wtv, avio_tell(pb) - 20)) < 0)
796cabdff1aSopenharmony_ci                return ret;
797cabdff1aSopenharmony_ci            continue;
798cabdff1aSopenharmony_ci        }
799cabdff1aSopenharmony_ci        sid = avio_rl32(pb) & 0x7FFF;
800cabdff1aSopenharmony_ci        avio_skip(pb, 8);
801cabdff1aSopenharmony_ci        consumed = 32;
802cabdff1aSopenharmony_ci
803cabdff1aSopenharmony_ci        if (!ff_guidcmp(g, ff_SBE2_STREAM_DESC_EVENT)) {
804cabdff1aSopenharmony_ci            if (ff_find_stream_index(s, sid) < 0) {
805cabdff1aSopenharmony_ci                ff_asf_guid mediatype, subtype, formattype;
806cabdff1aSopenharmony_ci                int size;
807cabdff1aSopenharmony_ci                avio_skip(pb, 28);
808cabdff1aSopenharmony_ci                ff_get_guid(pb, &mediatype);
809cabdff1aSopenharmony_ci                ff_get_guid(pb, &subtype);
810cabdff1aSopenharmony_ci                avio_skip(pb, 12);
811cabdff1aSopenharmony_ci                ff_get_guid(pb, &formattype);
812cabdff1aSopenharmony_ci                size = avio_rl32(pb);
813cabdff1aSopenharmony_ci                if (size < 0 || size > INT_MAX - 92 - consumed)
814cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
815cabdff1aSopenharmony_ci                parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
816cabdff1aSopenharmony_ci                consumed += 92 + size;
817cabdff1aSopenharmony_ci            }
818cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, ff_stream2_guid)) {
819cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
820cabdff1aSopenharmony_ci            if (stream_index >= 0 && s->streams[stream_index]->priv_data && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
821cabdff1aSopenharmony_ci                ff_asf_guid mediatype, subtype, formattype;
822cabdff1aSopenharmony_ci                int size;
823cabdff1aSopenharmony_ci                avio_skip(pb, 12);
824cabdff1aSopenharmony_ci                ff_get_guid(pb, &mediatype);
825cabdff1aSopenharmony_ci                ff_get_guid(pb, &subtype);
826cabdff1aSopenharmony_ci                avio_skip(pb, 12);
827cabdff1aSopenharmony_ci                ff_get_guid(pb, &formattype);
828cabdff1aSopenharmony_ci                size = avio_rl32(pb);
829cabdff1aSopenharmony_ci                if (size < 0 || size > INT_MAX - 76 - consumed)
830cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
831cabdff1aSopenharmony_ci                parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size);
832cabdff1aSopenharmony_ci                consumed += 76 + size;
833cabdff1aSopenharmony_ci            }
834cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) ||
835cabdff1aSopenharmony_ci                   !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
836cabdff1aSopenharmony_ci                   !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) ||
837cabdff1aSopenharmony_ci                   !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) ||
838cabdff1aSopenharmony_ci                   !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) ||
839cabdff1aSopenharmony_ci                   !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) {
840cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
841cabdff1aSopenharmony_ci            if (stream_index >= 0) {
842cabdff1aSopenharmony_ci                AVStream *st = s->streams[stream_index];
843cabdff1aSopenharmony_ci                uint8_t buf[258];
844cabdff1aSopenharmony_ci                const uint8_t *pbuf = buf;
845cabdff1aSopenharmony_ci                int buf_size;
846cabdff1aSopenharmony_ci
847cabdff1aSopenharmony_ci                avio_skip(pb, 8);
848cabdff1aSopenharmony_ci                consumed += 8;
849cabdff1aSopenharmony_ci                if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
850cabdff1aSopenharmony_ci                    !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) {
851cabdff1aSopenharmony_ci                    avio_skip(pb, 6);
852cabdff1aSopenharmony_ci                    consumed += 6;
853cabdff1aSopenharmony_ci                }
854cabdff1aSopenharmony_ci
855cabdff1aSopenharmony_ci                buf_size = FFMIN(len - consumed, sizeof(buf));
856cabdff1aSopenharmony_ci                avio_read(pb, buf, buf_size);
857cabdff1aSopenharmony_ci                consumed += buf_size;
858cabdff1aSopenharmony_ci                ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL);
859cabdff1aSopenharmony_ci            }
860cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
861cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
862cabdff1aSopenharmony_ci            if (stream_index >= 0) {
863cabdff1aSopenharmony_ci                AVStream *st = s->streams[stream_index];
864cabdff1aSopenharmony_ci                int audio_type;
865cabdff1aSopenharmony_ci                avio_skip(pb, 8);
866cabdff1aSopenharmony_ci                audio_type = avio_r8(pb);
867cabdff1aSopenharmony_ci                if (audio_type == 2)
868cabdff1aSopenharmony_ci                    st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
869cabdff1aSopenharmony_ci                else if (audio_type == 3)
870cabdff1aSopenharmony_ci                    st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
871cabdff1aSopenharmony_ci                consumed += 9;
872cabdff1aSopenharmony_ci            }
873cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) {
874cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
875cabdff1aSopenharmony_ci            if (stream_index >= 0) {
876cabdff1aSopenharmony_ci                avio_skip(pb, 12);
877cabdff1aSopenharmony_ci                if (avio_rl32(pb))
878cabdff1aSopenharmony_ci                    av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index);
879cabdff1aSopenharmony_ci                consumed += 16;
880cabdff1aSopenharmony_ci            }
881cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) {
882cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
883cabdff1aSopenharmony_ci            if (stream_index >= 0) {
884cabdff1aSopenharmony_ci                AVStream *st = s->streams[stream_index];
885cabdff1aSopenharmony_ci                uint8_t language[4];
886cabdff1aSopenharmony_ci                avio_skip(pb, 12);
887cabdff1aSopenharmony_ci                avio_read(pb, language, 3);
888cabdff1aSopenharmony_ci                if (language[0]) {
889cabdff1aSopenharmony_ci                    language[3] = 0;
890cabdff1aSopenharmony_ci                    av_dict_set(&st->metadata, "language", language, 0);
891cabdff1aSopenharmony_ci                    if (!strcmp(language, "nar") || !strcmp(language, "NAR"))
892cabdff1aSopenharmony_ci                        st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
893cabdff1aSopenharmony_ci                }
894cabdff1aSopenharmony_ci                consumed += 15;
895cabdff1aSopenharmony_ci            }
896cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, ff_timestamp_guid)) {
897cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
898cabdff1aSopenharmony_ci            if (stream_index >= 0) {
899cabdff1aSopenharmony_ci                avio_skip(pb, 8);
900cabdff1aSopenharmony_ci                wtv->pts = avio_rl64(pb);
901cabdff1aSopenharmony_ci                consumed += 16;
902cabdff1aSopenharmony_ci                if (wtv->pts == -1)
903cabdff1aSopenharmony_ci                    wtv->pts = AV_NOPTS_VALUE;
904cabdff1aSopenharmony_ci                else {
905cabdff1aSopenharmony_ci                    wtv->last_valid_pts = wtv->pts;
906cabdff1aSopenharmony_ci                    if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch)
907cabdff1aSopenharmony_ci                        wtv->epoch = wtv->pts;
908cabdff1aSopenharmony_ci                    if (mode == SEEK_TO_PTS && wtv->pts >= seekts) {
909cabdff1aSopenharmony_ci                        avio_skip(pb, WTV_PAD8(len) - consumed);
910cabdff1aSopenharmony_ci                        return 0;
911cabdff1aSopenharmony_ci                    }
912cabdff1aSopenharmony_ci                }
913cabdff1aSopenharmony_ci            }
914cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, ff_data_guid)) {
915cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
916cabdff1aSopenharmony_ci            if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32 && s->streams[stream_index]->priv_data) {
917cabdff1aSopenharmony_ci                WtvStream *wst = s->streams[stream_index]->priv_data;
918cabdff1aSopenharmony_ci                wst->seen_data = 1;
919cabdff1aSopenharmony_ci                if (len_ptr) {
920cabdff1aSopenharmony_ci                    *len_ptr = len;
921cabdff1aSopenharmony_ci                }
922cabdff1aSopenharmony_ci                return stream_index;
923cabdff1aSopenharmony_ci            }
924cabdff1aSopenharmony_ci        } else if (!ff_guidcmp(g, /* DSATTRIB_WMDRMProtectionInfo */ (const ff_asf_guid){0x83,0x95,0x74,0x40,0x9D,0x6B,0xEC,0x4E,0xB4,0x3C,0x67,0xA1,0x80,0x1E,0x1A,0x9B})) {
925cabdff1aSopenharmony_ci            int stream_index = ff_find_stream_index(s, sid);
926cabdff1aSopenharmony_ci            if (stream_index >= 0)
927cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "encrypted stream detected (st:%d), decoding will likely fail\n", stream_index);
928cabdff1aSopenharmony_ci        } else if (
929cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) ||
930cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* DSATTRIB_PBDATAG_ATTRIBUTE */ (const ff_asf_guid){0x79,0x66,0xB5,0xE0,0xB9,0x12,0xCC,0x43,0xB7,0xDF,0x57,0x8C,0xAA,0x5A,0x7B,0x63}) ||
931cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) ||
932cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ ff_DSATTRIB_TRANSPORT_PROPERTIES) ||
933cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) ||
934cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) ||
935cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) ||
936cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) ||
937cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) ||
938cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) ||
939cabdff1aSopenharmony_ci            !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) ||
940cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) ||
941cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) ||
942cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) ||
943cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
944cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) ||
945cabdff1aSopenharmony_ci            !ff_guidcmp(g, ff_index_guid) ||
946cabdff1aSopenharmony_ci            !ff_guidcmp(g, ff_sync_guid) ||
947cabdff1aSopenharmony_ci            !ff_guidcmp(g, ff_stream1_guid) ||
948cabdff1aSopenharmony_ci            !ff_guidcmp(g, (const ff_asf_guid){0xF7,0x10,0x02,0xB9,0xEE,0x7C,0xED,0x4E,0xBD,0x7F,0x05,0x40,0x35,0x86,0x18,0xA1})) {
949cabdff1aSopenharmony_ci            //ignore known guids
950cabdff1aSopenharmony_ci        } else
951cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g));
952cabdff1aSopenharmony_ci
953cabdff1aSopenharmony_ci        if (avio_feof(pb))
954cabdff1aSopenharmony_ci            break;
955cabdff1aSopenharmony_ci
956cabdff1aSopenharmony_ci        avio_skip(pb, WTV_PAD8(len) - consumed);
957cabdff1aSopenharmony_ci    }
958cabdff1aSopenharmony_ci    return AVERROR_EOF;
959cabdff1aSopenharmony_ci}
960cabdff1aSopenharmony_ci
961cabdff1aSopenharmony_cistatic int read_header(AVFormatContext *s)
962cabdff1aSopenharmony_ci{
963cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
964cabdff1aSopenharmony_ci    unsigned root_sector;
965cabdff1aSopenharmony_ci    int root_size;
966cabdff1aSopenharmony_ci    uint8_t root[WTV_SECTOR_SIZE];
967cabdff1aSopenharmony_ci    AVIOContext *pb;
968cabdff1aSopenharmony_ci    int64_t timeline_pos;
969cabdff1aSopenharmony_ci    int64_t ret;
970cabdff1aSopenharmony_ci
971cabdff1aSopenharmony_ci    wtv->epoch          =
972cabdff1aSopenharmony_ci    wtv->pts            =
973cabdff1aSopenharmony_ci    wtv->last_valid_pts = AV_NOPTS_VALUE;
974cabdff1aSopenharmony_ci
975cabdff1aSopenharmony_ci    /* read root directory sector */
976cabdff1aSopenharmony_ci    avio_skip(s->pb, 0x30);
977cabdff1aSopenharmony_ci    root_size = avio_rl32(s->pb);
978cabdff1aSopenharmony_ci    if (root_size > sizeof(root)) {
979cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n");
980cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
981cabdff1aSopenharmony_ci    }
982cabdff1aSopenharmony_ci    avio_skip(s->pb, 4);
983cabdff1aSopenharmony_ci    root_sector = avio_rl32(s->pb);
984cabdff1aSopenharmony_ci
985cabdff1aSopenharmony_ci    ret = seek_by_sector(s->pb, root_sector, 0);
986cabdff1aSopenharmony_ci    if (ret < 0)
987cabdff1aSopenharmony_ci        return ret;
988cabdff1aSopenharmony_ci    root_size = avio_read(s->pb, root, root_size);
989cabdff1aSopenharmony_ci    if (root_size < 0)
990cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
991cabdff1aSopenharmony_ci
992cabdff1aSopenharmony_ci    /* parse chunks up until first data chunk */
993cabdff1aSopenharmony_ci    wtv->pb = wtvfile_open(s, root, root_size, ff_timeline_le16);
994cabdff1aSopenharmony_ci    if (!wtv->pb) {
995cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "timeline data missing\n");
996cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
997cabdff1aSopenharmony_ci    }
998cabdff1aSopenharmony_ci
999cabdff1aSopenharmony_ci    ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
1000cabdff1aSopenharmony_ci    if (ret < 0) {
1001cabdff1aSopenharmony_ci        wtvfile_close(wtv->pb);
1002cabdff1aSopenharmony_ci        return ret;
1003cabdff1aSopenharmony_ci    }
1004cabdff1aSopenharmony_ci    avio_seek(wtv->pb, -32, SEEK_CUR);
1005cabdff1aSopenharmony_ci
1006cabdff1aSopenharmony_ci    timeline_pos = avio_tell(s->pb); // save before opening another file
1007cabdff1aSopenharmony_ci
1008cabdff1aSopenharmony_ci    /* read metadata */
1009cabdff1aSopenharmony_ci    pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16);
1010cabdff1aSopenharmony_ci    if (pb) {
1011cabdff1aSopenharmony_ci        parse_legacy_attrib(s, pb);
1012cabdff1aSopenharmony_ci        wtvfile_close(pb);
1013cabdff1aSopenharmony_ci    }
1014cabdff1aSopenharmony_ci
1015cabdff1aSopenharmony_ci    s->ctx_flags |= AVFMTCTX_NOHEADER; // Needed for noStreams.wtv
1016cabdff1aSopenharmony_ci
1017cabdff1aSopenharmony_ci    /* read seek index */
1018cabdff1aSopenharmony_ci    if (s->nb_streams) {
1019cabdff1aSopenharmony_ci        AVStream *st = s->streams[0];
1020cabdff1aSopenharmony_ci        pb = wtvfile_open(s, root, root_size, ff_table_0_entries_time_le16);
1021cabdff1aSopenharmony_ci        if (pb) {
1022cabdff1aSopenharmony_ci            while(1) {
1023cabdff1aSopenharmony_ci                uint64_t timestamp = avio_rl64(pb);
1024cabdff1aSopenharmony_ci                uint64_t frame_nb  = avio_rl64(pb);
1025cabdff1aSopenharmony_ci                if (avio_feof(pb))
1026cabdff1aSopenharmony_ci                    break;
1027cabdff1aSopenharmony_ci                ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
1028cabdff1aSopenharmony_ci                                   0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
1029cabdff1aSopenharmony_ci            }
1030cabdff1aSopenharmony_ci            wtvfile_close(pb);
1031cabdff1aSopenharmony_ci
1032cabdff1aSopenharmony_ci            if (wtv->nb_index_entries) {
1033cabdff1aSopenharmony_ci                pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
1034cabdff1aSopenharmony_ci                if (pb) {
1035cabdff1aSopenharmony_ci                    AVIndexEntry *e = wtv->index_entries;
1036cabdff1aSopenharmony_ci                    AVIndexEntry *e_end = wtv->index_entries + wtv->nb_index_entries - 1;
1037cabdff1aSopenharmony_ci                    uint64_t last_position = 0;
1038cabdff1aSopenharmony_ci                    while (1) {
1039cabdff1aSopenharmony_ci                        uint64_t frame_nb = avio_rl64(pb);
1040cabdff1aSopenharmony_ci                        uint64_t position = avio_rl64(pb);
1041cabdff1aSopenharmony_ci                        while (e <= e_end && frame_nb > e->size) {
1042cabdff1aSopenharmony_ci                            e->pos = last_position;
1043cabdff1aSopenharmony_ci                            e++;
1044cabdff1aSopenharmony_ci                        }
1045cabdff1aSopenharmony_ci                        if (avio_feof(pb))
1046cabdff1aSopenharmony_ci                            break;
1047cabdff1aSopenharmony_ci                        last_position = position;
1048cabdff1aSopenharmony_ci                    }
1049cabdff1aSopenharmony_ci                    e_end->pos = last_position;
1050cabdff1aSopenharmony_ci                    wtvfile_close(pb);
1051cabdff1aSopenharmony_ci                    st->duration = e_end->timestamp;
1052cabdff1aSopenharmony_ci                }
1053cabdff1aSopenharmony_ci            }
1054cabdff1aSopenharmony_ci        }
1055cabdff1aSopenharmony_ci    }
1056cabdff1aSopenharmony_ci
1057cabdff1aSopenharmony_ci    avio_seek(s->pb, timeline_pos, SEEK_SET);
1058cabdff1aSopenharmony_ci    return 0;
1059cabdff1aSopenharmony_ci}
1060cabdff1aSopenharmony_ci
1061cabdff1aSopenharmony_cistatic int read_packet(AVFormatContext *s, AVPacket *pkt)
1062cabdff1aSopenharmony_ci{
1063cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
1064cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
1065cabdff1aSopenharmony_ci    int stream_index, len, ret;
1066cabdff1aSopenharmony_ci
1067cabdff1aSopenharmony_ci    stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
1068cabdff1aSopenharmony_ci    if (stream_index < 0)
1069cabdff1aSopenharmony_ci        return stream_index;
1070cabdff1aSopenharmony_ci
1071cabdff1aSopenharmony_ci    ret = av_get_packet(pb, pkt, len - 32);
1072cabdff1aSopenharmony_ci    if (ret < 0)
1073cabdff1aSopenharmony_ci        return ret;
1074cabdff1aSopenharmony_ci    pkt->stream_index = stream_index;
1075cabdff1aSopenharmony_ci    pkt->pts          = wtv->pts;
1076cabdff1aSopenharmony_ci    avio_skip(pb, WTV_PAD8(len) - len);
1077cabdff1aSopenharmony_ci    return 0;
1078cabdff1aSopenharmony_ci}
1079cabdff1aSopenharmony_ci
1080cabdff1aSopenharmony_cistatic int read_seek(AVFormatContext *s, int stream_index,
1081cabdff1aSopenharmony_ci                     int64_t ts, int flags)
1082cabdff1aSopenharmony_ci{
1083cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
1084cabdff1aSopenharmony_ci    AVIOContext *pb = wtv->pb;
1085cabdff1aSopenharmony_ci    AVStream *st = s->streams[0];
1086cabdff1aSopenharmony_ci    int64_t ts_relative;
1087cabdff1aSopenharmony_ci    int i;
1088cabdff1aSopenharmony_ci
1089cabdff1aSopenharmony_ci    if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
1090cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
1091cabdff1aSopenharmony_ci
1092cabdff1aSopenharmony_ci    /* timestamp adjustment is required because wtv->pts values are absolute,
1093cabdff1aSopenharmony_ci     * whereas AVIndexEntry->timestamp values are relative to epoch. */
1094cabdff1aSopenharmony_ci    ts_relative = ts;
1095cabdff1aSopenharmony_ci    if (wtv->epoch != AV_NOPTS_VALUE)
1096cabdff1aSopenharmony_ci        ts_relative -= wtv->epoch;
1097cabdff1aSopenharmony_ci
1098cabdff1aSopenharmony_ci    i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags);
1099cabdff1aSopenharmony_ci    if (i < 0) {
1100cabdff1aSopenharmony_ci        if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts) {
1101cabdff1aSopenharmony_ci            if (avio_seek(pb, 0, SEEK_SET) < 0)
1102cabdff1aSopenharmony_ci                return -1;
1103cabdff1aSopenharmony_ci        } else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries) {
1104cabdff1aSopenharmony_ci            if (avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET) < 0)
1105cabdff1aSopenharmony_ci                return -1;
1106cabdff1aSopenharmony_ci        }
1107cabdff1aSopenharmony_ci        if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0)
1108cabdff1aSopenharmony_ci            return AVERROR(ERANGE);
1109cabdff1aSopenharmony_ci        return 0;
1110cabdff1aSopenharmony_ci    }
1111cabdff1aSopenharmony_ci    if (avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET) < 0)
1112cabdff1aSopenharmony_ci        return -1;
1113cabdff1aSopenharmony_ci    wtv->pts = wtv->index_entries[i].timestamp;
1114cabdff1aSopenharmony_ci    if (wtv->epoch != AV_NOPTS_VALUE)
1115cabdff1aSopenharmony_ci        wtv->pts += wtv->epoch;
1116cabdff1aSopenharmony_ci    wtv->last_valid_pts = wtv->pts;
1117cabdff1aSopenharmony_ci    return 0;
1118cabdff1aSopenharmony_ci}
1119cabdff1aSopenharmony_ci
1120cabdff1aSopenharmony_cistatic int read_close(AVFormatContext *s)
1121cabdff1aSopenharmony_ci{
1122cabdff1aSopenharmony_ci    WtvContext *wtv = s->priv_data;
1123cabdff1aSopenharmony_ci    av_freep(&wtv->index_entries);
1124cabdff1aSopenharmony_ci    wtvfile_close(wtv->pb);
1125cabdff1aSopenharmony_ci    return 0;
1126cabdff1aSopenharmony_ci}
1127cabdff1aSopenharmony_ci
1128cabdff1aSopenharmony_ciconst AVInputFormat ff_wtv_demuxer = {
1129cabdff1aSopenharmony_ci    .name           = "wtv",
1130cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
1131cabdff1aSopenharmony_ci    .priv_data_size = sizeof(WtvContext),
1132cabdff1aSopenharmony_ci    .read_probe     = read_probe,
1133cabdff1aSopenharmony_ci    .read_header    = read_header,
1134cabdff1aSopenharmony_ci    .read_packet    = read_packet,
1135cabdff1aSopenharmony_ci    .read_seek      = read_seek,
1136cabdff1aSopenharmony_ci    .read_close     = read_close,
1137cabdff1aSopenharmony_ci    .flags          = AVFMT_SHOW_IDS,
1138cabdff1aSopenharmony_ci};
1139