xref: /third_party/ffmpeg/libavformat/wavdec.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * WAV demuxer
3cabdff1aSopenharmony_ci * Copyright (c) 2001, 2002 Fabrice Bellard
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * Sony Wave64 demuxer
6cabdff1aSopenharmony_ci * RF64 demuxer
7cabdff1aSopenharmony_ci * Copyright (c) 2009 Daniel Verkamp
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * BW64 demuxer
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * This file is part of FFmpeg.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
14cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
16cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
19cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
20cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21cabdff1aSopenharmony_ci * Lesser General Public License for more details.
22cabdff1aSopenharmony_ci *
23cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
24cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
25cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include <stdint.h>
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "config_components.h"
31cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
32cabdff1aSopenharmony_ci#include "libavutil/dict.h"
33cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
34cabdff1aSopenharmony_ci#include "libavutil/log.h"
35cabdff1aSopenharmony_ci#include "libavutil/mathematics.h"
36cabdff1aSopenharmony_ci#include "libavutil/opt.h"
37cabdff1aSopenharmony_ci#include "avformat.h"
38cabdff1aSopenharmony_ci#include "avio.h"
39cabdff1aSopenharmony_ci#include "avio_internal.h"
40cabdff1aSopenharmony_ci#include "demux.h"
41cabdff1aSopenharmony_ci#include "id3v2.h"
42cabdff1aSopenharmony_ci#include "internal.h"
43cabdff1aSopenharmony_ci#include "metadata.h"
44cabdff1aSopenharmony_ci#include "pcm.h"
45cabdff1aSopenharmony_ci#include "riff.h"
46cabdff1aSopenharmony_ci#include "w64.h"
47cabdff1aSopenharmony_ci#include "spdif.h"
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_citypedef struct WAVDemuxContext {
50cabdff1aSopenharmony_ci    const AVClass *class;
51cabdff1aSopenharmony_ci    int64_t data_end;
52cabdff1aSopenharmony_ci    int w64;
53cabdff1aSopenharmony_ci    AVStream *vst;
54cabdff1aSopenharmony_ci    int64_t smv_data_ofs;
55cabdff1aSopenharmony_ci    int smv_block_size;
56cabdff1aSopenharmony_ci    int smv_frames_per_jpeg;
57cabdff1aSopenharmony_ci    int smv_block;
58cabdff1aSopenharmony_ci    int smv_last_stream;
59cabdff1aSopenharmony_ci    int smv_eof;
60cabdff1aSopenharmony_ci    int audio_eof;
61cabdff1aSopenharmony_ci    int ignore_length;
62cabdff1aSopenharmony_ci    int max_size;
63cabdff1aSopenharmony_ci    int spdif;
64cabdff1aSopenharmony_ci    int smv_given_first;
65cabdff1aSopenharmony_ci    int unaligned; // e.g. if an odd number of bytes ID3 tag was prepended
66cabdff1aSopenharmony_ci    int rifx; // RIFX: integer byte order for parameters is big endian
67cabdff1aSopenharmony_ci} WAVDemuxContext;
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(WAVDemuxContext, x)
70cabdff1aSopenharmony_ci#define DEC AV_OPT_FLAG_DECODING_PARAM
71cabdff1aSopenharmony_cistatic const AVOption demux_options[] = {
72cabdff1aSopenharmony_ci#define W64_DEMUXER_OPTIONS_OFFSET (1 * CONFIG_WAV_DEMUXER)
73cabdff1aSopenharmony_ci#if CONFIG_WAV_DEMUXER
74cabdff1aSopenharmony_ci    { "ignore_length", "Ignore length", OFFSET(ignore_length), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC },
75cabdff1aSopenharmony_ci#endif
76cabdff1aSopenharmony_ci    { "max_size",      "max size of single packet", OFFSET(max_size), AV_OPT_TYPE_INT, { .i64 = 4096 }, 1024, 1 << 22, DEC },
77cabdff1aSopenharmony_ci    { NULL },
78cabdff1aSopenharmony_ci};
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_cistatic void set_spdif(AVFormatContext *s, WAVDemuxContext *wav)
81cabdff1aSopenharmony_ci{
82cabdff1aSopenharmony_ci    if (CONFIG_SPDIF_DEMUXER && s->streams[0]->codecpar->codec_tag == 1) {
83cabdff1aSopenharmony_ci        enum AVCodecID codec;
84cabdff1aSopenharmony_ci        int len = 1<<16;
85cabdff1aSopenharmony_ci        int ret = ffio_ensure_seekback(s->pb, len);
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci        if (ret >= 0) {
88cabdff1aSopenharmony_ci            uint8_t *buf = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE);
89cabdff1aSopenharmony_ci            if (!buf) {
90cabdff1aSopenharmony_ci                ret = AVERROR(ENOMEM);
91cabdff1aSopenharmony_ci            } else {
92cabdff1aSopenharmony_ci                int64_t pos = avio_tell(s->pb);
93cabdff1aSopenharmony_ci                len = ret = avio_read(s->pb, buf, len);
94cabdff1aSopenharmony_ci                if (len >= 0) {
95cabdff1aSopenharmony_ci                    ret = ff_spdif_probe(buf, len, &codec);
96cabdff1aSopenharmony_ci                    if (ret > AVPROBE_SCORE_EXTENSION) {
97cabdff1aSopenharmony_ci                        s->streams[0]->codecpar->codec_id = codec;
98cabdff1aSopenharmony_ci                        wav->spdif = 1;
99cabdff1aSopenharmony_ci                    }
100cabdff1aSopenharmony_ci                }
101cabdff1aSopenharmony_ci                avio_seek(s->pb, pos, SEEK_SET);
102cabdff1aSopenharmony_ci                av_free(buf);
103cabdff1aSopenharmony_ci            }
104cabdff1aSopenharmony_ci        }
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_ci        if (ret < 0)
107cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "Cannot check for SPDIF\n");
108cabdff1aSopenharmony_ci    }
109cabdff1aSopenharmony_ci}
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci#if CONFIG_WAV_DEMUXER
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_cistatic int64_t next_tag(AVIOContext *pb, uint32_t *tag, int big_endian)
114cabdff1aSopenharmony_ci{
115cabdff1aSopenharmony_ci    *tag = avio_rl32(pb);
116cabdff1aSopenharmony_ci    if (!big_endian) {
117cabdff1aSopenharmony_ci        return avio_rl32(pb);
118cabdff1aSopenharmony_ci    } else {
119cabdff1aSopenharmony_ci        return avio_rb32(pb);
120cabdff1aSopenharmony_ci    }
121cabdff1aSopenharmony_ci}
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci/* RIFF chunks are always at even offsets relative to where they start. */
124cabdff1aSopenharmony_cistatic int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offset, int whence)
125cabdff1aSopenharmony_ci{
126cabdff1aSopenharmony_ci    offset += offset < INT64_MAX && offset + wav->unaligned & 1;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    return avio_seek(s, offset, whence);
129cabdff1aSopenharmony_ci}
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci/* return the size of the found tag */
132cabdff1aSopenharmony_cistatic int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
133cabdff1aSopenharmony_ci{
134cabdff1aSopenharmony_ci    unsigned int tag;
135cabdff1aSopenharmony_ci    int64_t size;
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci    for (;;) {
138cabdff1aSopenharmony_ci        if (avio_feof(pb))
139cabdff1aSopenharmony_ci            return AVERROR_EOF;
140cabdff1aSopenharmony_ci        size = next_tag(pb, &tag, wav->rifx);
141cabdff1aSopenharmony_ci        if (tag == tag1)
142cabdff1aSopenharmony_ci            break;
143cabdff1aSopenharmony_ci        wav_seek_tag(wav, pb, size, SEEK_CUR);
144cabdff1aSopenharmony_ci    }
145cabdff1aSopenharmony_ci    return size;
146cabdff1aSopenharmony_ci}
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_cistatic int wav_probe(const AVProbeData *p)
149cabdff1aSopenharmony_ci{
150cabdff1aSopenharmony_ci    /* check file header */
151cabdff1aSopenharmony_ci    if (p->buf_size <= 32)
152cabdff1aSopenharmony_ci        return 0;
153cabdff1aSopenharmony_ci    if (!memcmp(p->buf + 8, "WAVE", 4)) {
154cabdff1aSopenharmony_ci        if (!memcmp(p->buf, "RIFF", 4) || !memcmp(p->buf, "RIFX", 4))
155cabdff1aSopenharmony_ci            /* Since the ACT demuxer has a standard WAV header at the top of
156cabdff1aSopenharmony_ci             * its own, the returned score is decreased to avoid a probe
157cabdff1aSopenharmony_ci             * conflict between ACT and WAV. */
158cabdff1aSopenharmony_ci            return AVPROBE_SCORE_MAX - 1;
159cabdff1aSopenharmony_ci        else if ((!memcmp(p->buf,      "RF64", 4) ||
160cabdff1aSopenharmony_ci                  !memcmp(p->buf,      "BW64", 4)) &&
161cabdff1aSopenharmony_ci                 !memcmp(p->buf + 12, "ds64", 4))
162cabdff1aSopenharmony_ci            return AVPROBE_SCORE_MAX;
163cabdff1aSopenharmony_ci    }
164cabdff1aSopenharmony_ci    return 0;
165cabdff1aSopenharmony_ci}
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_cistatic void handle_stream_probing(AVStream *st)
168cabdff1aSopenharmony_ci{
169cabdff1aSopenharmony_ci    if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16LE) {
170cabdff1aSopenharmony_ci        FFStream *const sti = ffstream(st);
171cabdff1aSopenharmony_ci        sti->request_probe = AVPROBE_SCORE_EXTENSION;
172cabdff1aSopenharmony_ci        sti->probe_packets = FFMIN(sti->probe_packets, 32);
173cabdff1aSopenharmony_ci    }
174cabdff1aSopenharmony_ci}
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_cistatic int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream *st)
177cabdff1aSopenharmony_ci{
178cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
179cabdff1aSopenharmony_ci    WAVDemuxContext *wav = s->priv_data;
180cabdff1aSopenharmony_ci    int ret;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    /* parse fmt header */
183cabdff1aSopenharmony_ci    ret = ff_get_wav_header(s, pb, st->codecpar, size, wav->rifx);
184cabdff1aSopenharmony_ci    if (ret < 0)
185cabdff1aSopenharmony_ci        return ret;
186cabdff1aSopenharmony_ci    handle_stream_probing(st);
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_ci    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
189cabdff1aSopenharmony_ci
190cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    return 0;
193cabdff1aSopenharmony_ci}
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_cistatic int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream *st)
196cabdff1aSopenharmony_ci{
197cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
198cabdff1aSopenharmony_ci    int version, num_streams, i, channels = 0, ret;
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci    if (size < 36)
201cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
204cabdff1aSopenharmony_ci    st->codecpar->codec_id   = AV_CODEC_ID_XMA2;
205cabdff1aSopenharmony_ci    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    version = avio_r8(pb);
208cabdff1aSopenharmony_ci    if (version != 3 && version != 4)
209cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
210cabdff1aSopenharmony_ci    num_streams = avio_r8(pb);
211cabdff1aSopenharmony_ci    if (size != (32 + ((version==3)?0:8) + 4*num_streams))
212cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
213cabdff1aSopenharmony_ci    avio_skip(pb, 10);
214cabdff1aSopenharmony_ci    st->codecpar->sample_rate = avio_rb32(pb);
215cabdff1aSopenharmony_ci    if (version == 4)
216cabdff1aSopenharmony_ci        avio_skip(pb, 8);
217cabdff1aSopenharmony_ci    avio_skip(pb, 4);
218cabdff1aSopenharmony_ci    st->duration = avio_rb32(pb);
219cabdff1aSopenharmony_ci    avio_skip(pb, 8);
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    for (i = 0; i < num_streams; i++) {
222cabdff1aSopenharmony_ci        channels += avio_r8(pb);
223cabdff1aSopenharmony_ci        avio_skip(pb, 3);
224cabdff1aSopenharmony_ci    }
225cabdff1aSopenharmony_ci    av_channel_layout_uninit(&st->codecpar->ch_layout);
226cabdff1aSopenharmony_ci    st->codecpar->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
227cabdff1aSopenharmony_ci    st->codecpar->ch_layout.nb_channels = channels;
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_ci    if (st->codecpar->ch_layout.nb_channels <= 0 || st->codecpar->sample_rate <= 0)
230cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
233cabdff1aSopenharmony_ci
234cabdff1aSopenharmony_ci    avio_seek(pb, -size, SEEK_CUR);
235cabdff1aSopenharmony_ci    if ((ret = ff_get_extradata(s, st->codecpar, pb, size)) < 0)
236cabdff1aSopenharmony_ci        return ret;
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    return 0;
239cabdff1aSopenharmony_ci}
240cabdff1aSopenharmony_ci
241cabdff1aSopenharmony_cistatic inline int wav_parse_bext_string(AVFormatContext *s, const char *key,
242cabdff1aSopenharmony_ci                                        int length)
243cabdff1aSopenharmony_ci{
244cabdff1aSopenharmony_ci    char temp[257];
245cabdff1aSopenharmony_ci    int ret;
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci    av_assert0(length < sizeof(temp));
248cabdff1aSopenharmony_ci    if ((ret = ffio_read_size(s->pb, temp, length)) < 0)
249cabdff1aSopenharmony_ci        return ret;
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci    temp[length] = 0;
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci    if (strlen(temp))
254cabdff1aSopenharmony_ci        return av_dict_set(&s->metadata, key, temp, 0);
255cabdff1aSopenharmony_ci
256cabdff1aSopenharmony_ci    return 0;
257cabdff1aSopenharmony_ci}
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_cistatic int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
260cabdff1aSopenharmony_ci{
261cabdff1aSopenharmony_ci    char temp[131], *coding_history;
262cabdff1aSopenharmony_ci    int ret, x;
263cabdff1aSopenharmony_ci    uint64_t time_reference;
264cabdff1aSopenharmony_ci    int64_t umid_parts[8], umid_mask = 0;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    if ((ret = wav_parse_bext_string(s, "description", 256)) < 0 ||
267cabdff1aSopenharmony_ci        (ret = wav_parse_bext_string(s, "originator", 32)) < 0 ||
268cabdff1aSopenharmony_ci        (ret = wav_parse_bext_string(s, "originator_reference", 32)) < 0 ||
269cabdff1aSopenharmony_ci        (ret = wav_parse_bext_string(s, "origination_date", 10)) < 0 ||
270cabdff1aSopenharmony_ci        (ret = wav_parse_bext_string(s, "origination_time", 8)) < 0)
271cabdff1aSopenharmony_ci        return ret;
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci    time_reference = avio_rl64(s->pb);
274cabdff1aSopenharmony_ci    snprintf(temp, sizeof(temp), "%"PRIu64, time_reference);
275cabdff1aSopenharmony_ci    if ((ret = av_dict_set(&s->metadata, "time_reference", temp, 0)) < 0)
276cabdff1aSopenharmony_ci        return ret;
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci    /* check if version is >= 1, in which case an UMID may be present */
279cabdff1aSopenharmony_ci    if (avio_rl16(s->pb) >= 1) {
280cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
281cabdff1aSopenharmony_ci            umid_mask |= umid_parts[x] = avio_rb64(s->pb);
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci        if (umid_mask) {
284cabdff1aSopenharmony_ci            /* the string formatting below is per SMPTE 330M-2004 Annex C */
285cabdff1aSopenharmony_ci            if (umid_parts[4] == 0 && umid_parts[5] == 0 &&
286cabdff1aSopenharmony_ci                umid_parts[6] == 0 && umid_parts[7] == 0) {
287cabdff1aSopenharmony_ci                /* basic UMID */
288cabdff1aSopenharmony_ci                snprintf(temp, sizeof(temp),
289cabdff1aSopenharmony_ci                         "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
290cabdff1aSopenharmony_ci                         umid_parts[0], umid_parts[1],
291cabdff1aSopenharmony_ci                         umid_parts[2], umid_parts[3]);
292cabdff1aSopenharmony_ci            } else {
293cabdff1aSopenharmony_ci                /* extended UMID */
294cabdff1aSopenharmony_ci                snprintf(temp, sizeof(temp),
295cabdff1aSopenharmony_ci                         "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64
296cabdff1aSopenharmony_ci                         "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
297cabdff1aSopenharmony_ci                         umid_parts[0], umid_parts[1],
298cabdff1aSopenharmony_ci                         umid_parts[2], umid_parts[3],
299cabdff1aSopenharmony_ci                         umid_parts[4], umid_parts[5],
300cabdff1aSopenharmony_ci                         umid_parts[6], umid_parts[7]);
301cabdff1aSopenharmony_ci            }
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci            if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0)
304cabdff1aSopenharmony_ci                return ret;
305cabdff1aSopenharmony_ci        }
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_ci        avio_skip(s->pb, 190);
308cabdff1aSopenharmony_ci    } else
309cabdff1aSopenharmony_ci        avio_skip(s->pb, 254);
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci    if (size > 602) {
312cabdff1aSopenharmony_ci        /* CodingHistory present */
313cabdff1aSopenharmony_ci        size -= 602;
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci        if (!(coding_history = av_malloc(size + 1)))
316cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_ci        if ((ret = ffio_read_size(s->pb, coding_history, size)) < 0) {
319cabdff1aSopenharmony_ci            av_free(coding_history);
320cabdff1aSopenharmony_ci            return ret;
321cabdff1aSopenharmony_ci        }
322cabdff1aSopenharmony_ci
323cabdff1aSopenharmony_ci        coding_history[size] = 0;
324cabdff1aSopenharmony_ci        if ((ret = av_dict_set(&s->metadata, "coding_history", coding_history,
325cabdff1aSopenharmony_ci                               AV_DICT_DONT_STRDUP_VAL)) < 0)
326cabdff1aSopenharmony_ci            return ret;
327cabdff1aSopenharmony_ci    }
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_ci    return 0;
330cabdff1aSopenharmony_ci}
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_cistatic const AVMetadataConv wav_metadata_conv[] = {
333cabdff1aSopenharmony_ci    { "description",      "comment"       },
334cabdff1aSopenharmony_ci    { "originator",       "encoded_by"    },
335cabdff1aSopenharmony_ci    { "origination_date", "date"          },
336cabdff1aSopenharmony_ci    { "origination_time", "creation_time" },
337cabdff1aSopenharmony_ci    { 0 },
338cabdff1aSopenharmony_ci};
339cabdff1aSopenharmony_ci
340cabdff1aSopenharmony_ci/* wav input */
341cabdff1aSopenharmony_cistatic int wav_read_header(AVFormatContext *s)
342cabdff1aSopenharmony_ci{
343cabdff1aSopenharmony_ci    int64_t size, av_uninit(data_size);
344cabdff1aSopenharmony_ci    int64_t sample_count = 0;
345cabdff1aSopenharmony_ci    int rf64 = 0, bw64 = 0;
346cabdff1aSopenharmony_ci    uint32_t tag;
347cabdff1aSopenharmony_ci    AVIOContext *pb      = s->pb;
348cabdff1aSopenharmony_ci    AVStream *st         = NULL;
349cabdff1aSopenharmony_ci    WAVDemuxContext *wav = s->priv_data;
350cabdff1aSopenharmony_ci    int ret, got_fmt = 0, got_xma2 = 0;
351cabdff1aSopenharmony_ci    int64_t next_tag_ofs, data_ofs = -1;
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci    wav->unaligned = avio_tell(s->pb) & 1;
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    wav->smv_data_ofs = -1;
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci    /* read chunk ID */
358cabdff1aSopenharmony_ci    tag = avio_rl32(pb);
359cabdff1aSopenharmony_ci    switch (tag) {
360cabdff1aSopenharmony_ci    case MKTAG('R', 'I', 'F', 'F'):
361cabdff1aSopenharmony_ci        break;
362cabdff1aSopenharmony_ci    case MKTAG('R', 'I', 'F', 'X'):
363cabdff1aSopenharmony_ci        wav->rifx = 1;
364cabdff1aSopenharmony_ci        break;
365cabdff1aSopenharmony_ci    case MKTAG('R', 'F', '6', '4'):
366cabdff1aSopenharmony_ci        rf64 = 1;
367cabdff1aSopenharmony_ci        break;
368cabdff1aSopenharmony_ci    case MKTAG('B', 'W', '6', '4'):
369cabdff1aSopenharmony_ci        bw64 = 1;
370cabdff1aSopenharmony_ci        break;
371cabdff1aSopenharmony_ci    default:
372cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "invalid start code %s in RIFF header\n",
373cabdff1aSopenharmony_ci               av_fourcc2str(tag));
374cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
375cabdff1aSopenharmony_ci    }
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    /* read chunk size */
378cabdff1aSopenharmony_ci    avio_rl32(pb);
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_ci    /* read format */
381cabdff1aSopenharmony_ci    if (avio_rl32(pb) != MKTAG('W', 'A', 'V', 'E')) {
382cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "invalid format in RIFF header\n");
383cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
384cabdff1aSopenharmony_ci    }
385cabdff1aSopenharmony_ci
386cabdff1aSopenharmony_ci    if (rf64 || bw64) {
387cabdff1aSopenharmony_ci        if (avio_rl32(pb) != MKTAG('d', 's', '6', '4'))
388cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
389cabdff1aSopenharmony_ci        size = avio_rl32(pb);
390cabdff1aSopenharmony_ci        if (size < 24)
391cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
392cabdff1aSopenharmony_ci        avio_rl64(pb); /* RIFF size */
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci        data_size    = avio_rl64(pb);
395cabdff1aSopenharmony_ci        sample_count = avio_rl64(pb);
396cabdff1aSopenharmony_ci
397cabdff1aSopenharmony_ci        if (data_size < 0 || sample_count < 0) {
398cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in "
399cabdff1aSopenharmony_ci                   "ds64: data_size = %"PRId64", sample_count = %"PRId64"\n",
400cabdff1aSopenharmony_ci                   data_size, sample_count);
401cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
402cabdff1aSopenharmony_ci        }
403cabdff1aSopenharmony_ci        avio_skip(pb, size - 24); /* skip rest of ds64 chunk */
404cabdff1aSopenharmony_ci
405cabdff1aSopenharmony_ci    }
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci    /* Create the audio stream now so that its index is always zero */
408cabdff1aSopenharmony_ci    st = avformat_new_stream(s, NULL);
409cabdff1aSopenharmony_ci    if (!st)
410cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
411cabdff1aSopenharmony_ci
412cabdff1aSopenharmony_ci    for (;;) {
413cabdff1aSopenharmony_ci        AVStream *vst;
414cabdff1aSopenharmony_ci        size         = next_tag(pb, &tag, wav->rifx);
415cabdff1aSopenharmony_ci        next_tag_ofs = avio_tell(pb) + size;
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_ci        if (avio_feof(pb))
418cabdff1aSopenharmony_ci            break;
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_ci        switch (tag) {
421cabdff1aSopenharmony_ci        case MKTAG('f', 'm', 't', ' '):
422cabdff1aSopenharmony_ci            /* only parse the first 'fmt ' tag found */
423cabdff1aSopenharmony_ci            if (!got_xma2 && !got_fmt && (ret = wav_parse_fmt_tag(s, size, st)) < 0) {
424cabdff1aSopenharmony_ci                return ret;
425cabdff1aSopenharmony_ci            } else if (got_fmt)
426cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n");
427cabdff1aSopenharmony_ci
428cabdff1aSopenharmony_ci            got_fmt = 1;
429cabdff1aSopenharmony_ci            break;
430cabdff1aSopenharmony_ci        case MKTAG('X', 'M', 'A', '2'):
431cabdff1aSopenharmony_ci            /* only parse the first 'XMA2' tag found */
432cabdff1aSopenharmony_ci            if (!got_fmt && !got_xma2 && (ret = wav_parse_xma2_tag(s, size, st)) < 0) {
433cabdff1aSopenharmony_ci                return ret;
434cabdff1aSopenharmony_ci            } else if (got_xma2)
435cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "found more than one 'XMA2' tag\n");
436cabdff1aSopenharmony_ci
437cabdff1aSopenharmony_ci            got_xma2 = 1;
438cabdff1aSopenharmony_ci            break;
439cabdff1aSopenharmony_ci        case MKTAG('d', 'a', 't', 'a'):
440cabdff1aSopenharmony_ci            if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) && !got_fmt && !got_xma2) {
441cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR,
442cabdff1aSopenharmony_ci                       "found no 'fmt ' tag before the 'data' tag\n");
443cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
444cabdff1aSopenharmony_ci            }
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci            if (rf64 || bw64) {
447cabdff1aSopenharmony_ci                next_tag_ofs = wav->data_end = avio_tell(pb) + data_size;
448cabdff1aSopenharmony_ci            } else if (size != 0xFFFFFFFF) {
449cabdff1aSopenharmony_ci                data_size    = size;
450cabdff1aSopenharmony_ci                next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX;
451cabdff1aSopenharmony_ci            } else {
452cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "Ignoring maximum wav data size, "
453cabdff1aSopenharmony_ci                       "file may be invalid\n");
454cabdff1aSopenharmony_ci                data_size    = 0;
455cabdff1aSopenharmony_ci                next_tag_ofs = wav->data_end = INT64_MAX;
456cabdff1aSopenharmony_ci            }
457cabdff1aSopenharmony_ci
458cabdff1aSopenharmony_ci            data_ofs = avio_tell(pb);
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci            /* don't look for footer metadata if we can't seek or if we don't
461cabdff1aSopenharmony_ci             * know where the data tag ends
462cabdff1aSopenharmony_ci             */
463cabdff1aSopenharmony_ci            if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || (!(rf64 && !bw64) && !size))
464cabdff1aSopenharmony_ci                goto break_loop;
465cabdff1aSopenharmony_ci            break;
466cabdff1aSopenharmony_ci        case MKTAG('f', 'a', 'c', 't'):
467cabdff1aSopenharmony_ci            if (!sample_count)
468cabdff1aSopenharmony_ci                sample_count = (!wav->rifx ? avio_rl32(pb) : avio_rb32(pb));
469cabdff1aSopenharmony_ci            break;
470cabdff1aSopenharmony_ci        case MKTAG('b', 'e', 'x', 't'):
471cabdff1aSopenharmony_ci            if ((ret = wav_parse_bext_tag(s, size)) < 0)
472cabdff1aSopenharmony_ci                return ret;
473cabdff1aSopenharmony_ci            break;
474cabdff1aSopenharmony_ci        case MKTAG('S','M','V','0'):
475cabdff1aSopenharmony_ci            if (!got_fmt) {
476cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'SMV0' tag\n");
477cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
478cabdff1aSopenharmony_ci            }
479cabdff1aSopenharmony_ci            // SMV file, a wav file with video appended.
480cabdff1aSopenharmony_ci            if (size != MKTAG('0','2','0','0')) {
481cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "Unknown SMV version found\n");
482cabdff1aSopenharmony_ci                goto break_loop;
483cabdff1aSopenharmony_ci            }
484cabdff1aSopenharmony_ci            av_log(s, AV_LOG_DEBUG, "Found SMV data\n");
485cabdff1aSopenharmony_ci            wav->smv_given_first = 0;
486cabdff1aSopenharmony_ci            vst = avformat_new_stream(s, NULL);
487cabdff1aSopenharmony_ci            if (!vst)
488cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
489cabdff1aSopenharmony_ci            wav->vst = vst;
490cabdff1aSopenharmony_ci            avio_r8(pb);
491cabdff1aSopenharmony_ci            vst->id = 1;
492cabdff1aSopenharmony_ci            vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
493cabdff1aSopenharmony_ci            vst->codecpar->codec_id = AV_CODEC_ID_SMVJPEG;
494cabdff1aSopenharmony_ci            vst->codecpar->width  = avio_rl24(pb);
495cabdff1aSopenharmony_ci            vst->codecpar->height = avio_rl24(pb);
496cabdff1aSopenharmony_ci            if ((ret = ff_alloc_extradata(vst->codecpar, 4)) < 0) {
497cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n");
498cabdff1aSopenharmony_ci                return ret;
499cabdff1aSopenharmony_ci            }
500cabdff1aSopenharmony_ci            size = avio_rl24(pb);
501cabdff1aSopenharmony_ci            wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3;
502cabdff1aSopenharmony_ci            avio_rl24(pb);
503cabdff1aSopenharmony_ci            wav->smv_block_size = avio_rl24(pb);
504cabdff1aSopenharmony_ci            if (!wav->smv_block_size)
505cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
506cabdff1aSopenharmony_ci            avpriv_set_pts_info(vst, 32, 1, avio_rl24(pb));
507cabdff1aSopenharmony_ci            vst->duration = avio_rl24(pb);
508cabdff1aSopenharmony_ci            avio_rl24(pb);
509cabdff1aSopenharmony_ci            avio_rl24(pb);
510cabdff1aSopenharmony_ci            wav->smv_frames_per_jpeg = avio_rl24(pb);
511cabdff1aSopenharmony_ci            if (wav->smv_frames_per_jpeg > 65536) {
512cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "too many frames per jpeg\n");
513cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
514cabdff1aSopenharmony_ci            }
515cabdff1aSopenharmony_ci            AV_WL32(vst->codecpar->extradata, wav->smv_frames_per_jpeg);
516cabdff1aSopenharmony_ci            goto break_loop;
517cabdff1aSopenharmony_ci        case MKTAG('L', 'I', 'S', 'T'):
518cabdff1aSopenharmony_ci        case MKTAG('l', 'i', 's', 't'):
519cabdff1aSopenharmony_ci            if (size < 4) {
520cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "too short LIST tag\n");
521cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
522cabdff1aSopenharmony_ci            }
523cabdff1aSopenharmony_ci            switch (avio_rl32(pb)) {
524cabdff1aSopenharmony_ci            case MKTAG('I', 'N', 'F', 'O'):
525cabdff1aSopenharmony_ci                ff_read_riff_info(s, size - 4);
526cabdff1aSopenharmony_ci                break;
527cabdff1aSopenharmony_ci            case MKTAG('a', 'd', 't', 'l'):
528cabdff1aSopenharmony_ci                if (s->nb_chapters > 0) {
529cabdff1aSopenharmony_ci                    while (avio_tell(pb) < next_tag_ofs &&
530cabdff1aSopenharmony_ci                           !avio_feof(pb)) {
531cabdff1aSopenharmony_ci                        char cue_label[512];
532cabdff1aSopenharmony_ci                        unsigned id, sub_size;
533cabdff1aSopenharmony_ci
534cabdff1aSopenharmony_ci                        if (avio_rl32(pb) != MKTAG('l', 'a', 'b', 'l'))
535cabdff1aSopenharmony_ci                            break;
536cabdff1aSopenharmony_ci
537cabdff1aSopenharmony_ci                        sub_size = avio_rl32(pb);
538cabdff1aSopenharmony_ci                        if (sub_size < 5)
539cabdff1aSopenharmony_ci                            break;
540cabdff1aSopenharmony_ci                        id       = avio_rl32(pb);
541cabdff1aSopenharmony_ci                        avio_get_str(pb, sub_size - 4, cue_label, sizeof(cue_label));
542cabdff1aSopenharmony_ci                        avio_skip(pb, avio_tell(pb) & 1);
543cabdff1aSopenharmony_ci
544cabdff1aSopenharmony_ci                        for (int i = 0; i < s->nb_chapters; i++) {
545cabdff1aSopenharmony_ci                            if (s->chapters[i]->id == id) {
546cabdff1aSopenharmony_ci                                av_dict_set(&s->chapters[i]->metadata, "title", cue_label, 0);
547cabdff1aSopenharmony_ci                                break;
548cabdff1aSopenharmony_ci                            }
549cabdff1aSopenharmony_ci                        }
550cabdff1aSopenharmony_ci                    }
551cabdff1aSopenharmony_ci                }
552cabdff1aSopenharmony_ci                break;
553cabdff1aSopenharmony_ci            }
554cabdff1aSopenharmony_ci            break;
555cabdff1aSopenharmony_ci        case MKTAG('I', 'D', '3', ' '):
556cabdff1aSopenharmony_ci        case MKTAG('i', 'd', '3', ' '): {
557cabdff1aSopenharmony_ci            ID3v2ExtraMeta *id3v2_extra_meta;
558cabdff1aSopenharmony_ci            ff_id3v2_read_dict(pb, &ffformatcontext(s)->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
559cabdff1aSopenharmony_ci            if (id3v2_extra_meta) {
560cabdff1aSopenharmony_ci                ff_id3v2_parse_apic(s, id3v2_extra_meta);
561cabdff1aSopenharmony_ci                ff_id3v2_parse_chapters(s, id3v2_extra_meta);
562cabdff1aSopenharmony_ci                ff_id3v2_parse_priv(s, id3v2_extra_meta);
563cabdff1aSopenharmony_ci            }
564cabdff1aSopenharmony_ci            ff_id3v2_free_extra_meta(&id3v2_extra_meta);
565cabdff1aSopenharmony_ci            }
566cabdff1aSopenharmony_ci            break;
567cabdff1aSopenharmony_ci        case MKTAG('c', 'u', 'e', ' '):
568cabdff1aSopenharmony_ci            if (size >= 4 && got_fmt && st->codecpar->sample_rate > 0) {
569cabdff1aSopenharmony_ci                AVRational tb = {1, st->codecpar->sample_rate};
570cabdff1aSopenharmony_ci                unsigned nb_cues = avio_rl32(pb);
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ci                if (size >= nb_cues * 24LL + 4LL) {
573cabdff1aSopenharmony_ci                    for (int i = 0; i < nb_cues; i++) {
574cabdff1aSopenharmony_ci                        unsigned offset, id = avio_rl32(pb);
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_ci                        if (avio_feof(pb))
577cabdff1aSopenharmony_ci                            return AVERROR_INVALIDDATA;
578cabdff1aSopenharmony_ci
579cabdff1aSopenharmony_ci                        avio_skip(pb, 16);
580cabdff1aSopenharmony_ci                        offset = avio_rl32(pb);
581cabdff1aSopenharmony_ci
582cabdff1aSopenharmony_ci                        if (!avpriv_new_chapter(s, id, tb, offset, AV_NOPTS_VALUE, NULL))
583cabdff1aSopenharmony_ci                            return AVERROR(ENOMEM);
584cabdff1aSopenharmony_ci                    }
585cabdff1aSopenharmony_ci                }
586cabdff1aSopenharmony_ci            }
587cabdff1aSopenharmony_ci            break;
588cabdff1aSopenharmony_ci        }
589cabdff1aSopenharmony_ci
590cabdff1aSopenharmony_ci        /* seek to next tag unless we know that we'll run into EOF */
591cabdff1aSopenharmony_ci        if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) ||
592cabdff1aSopenharmony_ci            wav_seek_tag(wav, pb, next_tag_ofs, SEEK_SET) < 0) {
593cabdff1aSopenharmony_ci            break;
594cabdff1aSopenharmony_ci        }
595cabdff1aSopenharmony_ci    }
596cabdff1aSopenharmony_ci
597cabdff1aSopenharmony_cibreak_loop:
598cabdff1aSopenharmony_ci    if (!got_fmt && !got_xma2) {
599cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "no 'fmt ' or 'XMA2' tag found\n");
600cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
601cabdff1aSopenharmony_ci    }
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ci    if (data_ofs < 0) {
604cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "no 'data' tag found\n");
605cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
606cabdff1aSopenharmony_ci    }
607cabdff1aSopenharmony_ci
608cabdff1aSopenharmony_ci    avio_seek(pb, data_ofs, SEEK_SET);
609cabdff1aSopenharmony_ci
610cabdff1aSopenharmony_ci    if (data_size > (INT64_MAX>>3)) {
611cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "Data size %"PRId64" is too large\n", data_size);
612cabdff1aSopenharmony_ci        data_size = 0;
613cabdff1aSopenharmony_ci    }
614cabdff1aSopenharmony_ci
615cabdff1aSopenharmony_ci    if (   st->codecpar->bit_rate > 0 && data_size > 0
616cabdff1aSopenharmony_ci        && st->codecpar->sample_rate > 0
617cabdff1aSopenharmony_ci        && sample_count > 0 && st->codecpar->ch_layout.nb_channels > 1
618cabdff1aSopenharmony_ci        && sample_count % st->codecpar->ch_layout.nb_channels == 0) {
619cabdff1aSopenharmony_ci        if (fabs(8.0 * data_size * st->codecpar->ch_layout.nb_channels * st->codecpar->sample_rate /
620cabdff1aSopenharmony_ci            sample_count /st->codecpar->bit_rate - 1.0) < 0.3)
621cabdff1aSopenharmony_ci            sample_count /= st->codecpar->ch_layout.nb_channels;
622cabdff1aSopenharmony_ci    }
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci    if (data_size > 0 && sample_count && st->codecpar->ch_layout.nb_channels &&
625cabdff1aSopenharmony_ci        (data_size << 3) / sample_count / st->codecpar->ch_layout.nb_channels > st->codecpar->bits_per_coded_sample  + 1) {
626cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "ignoring wrong sample_count %"PRId64"\n", sample_count);
627cabdff1aSopenharmony_ci        sample_count = 0;
628cabdff1aSopenharmony_ci    }
629cabdff1aSopenharmony_ci
630cabdff1aSopenharmony_ci    /* G.729 hack (for Ticket4577)
631cabdff1aSopenharmony_ci     * FIXME: Come up with cleaner, more general solution */
632cabdff1aSopenharmony_ci    if (st->codecpar->codec_id == AV_CODEC_ID_G729 && sample_count && (data_size << 3) > sample_count) {
633cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "ignoring wrong sample_count %"PRId64"\n", sample_count);
634cabdff1aSopenharmony_ci        sample_count = 0;
635cabdff1aSopenharmony_ci    }
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_ci    if (!sample_count || av_get_exact_bits_per_sample(st->codecpar->codec_id) > 0)
638cabdff1aSopenharmony_ci        if (   st->codecpar->ch_layout.nb_channels
639cabdff1aSopenharmony_ci            && data_size
640cabdff1aSopenharmony_ci            && av_get_bits_per_sample(st->codecpar->codec_id)
641cabdff1aSopenharmony_ci            && wav->data_end <= avio_size(pb))
642cabdff1aSopenharmony_ci            sample_count = (data_size << 3)
643cabdff1aSopenharmony_ci                                  /
644cabdff1aSopenharmony_ci                (st->codecpar->ch_layout.nb_channels * (uint64_t)av_get_bits_per_sample(st->codecpar->codec_id));
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci    if (sample_count)
647cabdff1aSopenharmony_ci        st->duration = sample_count;
648cabdff1aSopenharmony_ci
649cabdff1aSopenharmony_ci    if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S32LE &&
650cabdff1aSopenharmony_ci        st->codecpar->block_align == st->codecpar->ch_layout.nb_channels * 4 &&
651cabdff1aSopenharmony_ci        st->codecpar->bits_per_coded_sample == 32 &&
652cabdff1aSopenharmony_ci        st->codecpar->extradata_size == 2 &&
653cabdff1aSopenharmony_ci        AV_RL16(st->codecpar->extradata) == 1) {
654cabdff1aSopenharmony_ci        st->codecpar->codec_id = AV_CODEC_ID_PCM_F16LE;
655cabdff1aSopenharmony_ci        st->codecpar->bits_per_coded_sample = 16;
656cabdff1aSopenharmony_ci    } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S24LE &&
657cabdff1aSopenharmony_ci               st->codecpar->block_align == st->codecpar->ch_layout.nb_channels * 4 &&
658cabdff1aSopenharmony_ci               st->codecpar->bits_per_coded_sample == 24) {
659cabdff1aSopenharmony_ci        st->codecpar->codec_id = AV_CODEC_ID_PCM_F24LE;
660cabdff1aSopenharmony_ci    } else if (st->codecpar->codec_id == AV_CODEC_ID_XMA1 ||
661cabdff1aSopenharmony_ci               st->codecpar->codec_id == AV_CODEC_ID_XMA2) {
662cabdff1aSopenharmony_ci        st->codecpar->block_align = 2048;
663cabdff1aSopenharmony_ci    } else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS && st->codecpar->ch_layout.nb_channels > 2 &&
664cabdff1aSopenharmony_ci               st->codecpar->block_align < INT_MAX / st->codecpar->ch_layout.nb_channels) {
665cabdff1aSopenharmony_ci        st->codecpar->block_align *= st->codecpar->ch_layout.nb_channels;
666cabdff1aSopenharmony_ci    }
667cabdff1aSopenharmony_ci
668cabdff1aSopenharmony_ci    ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
669cabdff1aSopenharmony_ci    ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);
670cabdff1aSopenharmony_ci
671cabdff1aSopenharmony_ci    set_spdif(s, wav);
672cabdff1aSopenharmony_ci
673cabdff1aSopenharmony_ci#ifdef OHOS_OPT_COMPAT
674cabdff1aSopenharmony_ci    if (ffformatcontext(s)->id3v2_meta && s->metadata) {
675cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "Discarding fmt metadata because ID3 tag is found.\n");
676cabdff1aSopenharmony_ci        av_dict_free(&s->metadata);
677cabdff1aSopenharmony_ci        s->metadata = NULL;
678cabdff1aSopenharmony_ci    }
679cabdff1aSopenharmony_ci#endif
680cabdff1aSopenharmony_ci
681cabdff1aSopenharmony_ci    return 0;
682cabdff1aSopenharmony_ci}
683cabdff1aSopenharmony_ci
684cabdff1aSopenharmony_ci/**
685cabdff1aSopenharmony_ci * Find chunk with w64 GUID by skipping over other chunks.
686cabdff1aSopenharmony_ci * @return the size of the found chunk
687cabdff1aSopenharmony_ci */
688cabdff1aSopenharmony_cistatic int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16])
689cabdff1aSopenharmony_ci{
690cabdff1aSopenharmony_ci    uint8_t guid[16];
691cabdff1aSopenharmony_ci    int64_t size;
692cabdff1aSopenharmony_ci
693cabdff1aSopenharmony_ci    while (!avio_feof(pb)) {
694cabdff1aSopenharmony_ci        avio_read(pb, guid, 16);
695cabdff1aSopenharmony_ci        size = avio_rl64(pb);
696cabdff1aSopenharmony_ci        if (size <= 24 || size > INT64_MAX - 8)
697cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
698cabdff1aSopenharmony_ci        if (!memcmp(guid, guid1, 16))
699cabdff1aSopenharmony_ci            return size;
700cabdff1aSopenharmony_ci        avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
701cabdff1aSopenharmony_ci    }
702cabdff1aSopenharmony_ci    return AVERROR_EOF;
703cabdff1aSopenharmony_ci}
704cabdff1aSopenharmony_ci
705cabdff1aSopenharmony_cistatic int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
706cabdff1aSopenharmony_ci{
707cabdff1aSopenharmony_ci    int ret, size;
708cabdff1aSopenharmony_ci    int64_t left;
709cabdff1aSopenharmony_ci    WAVDemuxContext *wav = s->priv_data;
710cabdff1aSopenharmony_ci    AVStream *st = s->streams[0];
711cabdff1aSopenharmony_ci
712cabdff1aSopenharmony_ci    if (CONFIG_SPDIF_DEMUXER && wav->spdif == 1)
713cabdff1aSopenharmony_ci        return ff_spdif_read_packet(s, pkt);
714cabdff1aSopenharmony_ci
715cabdff1aSopenharmony_ci    if (wav->smv_data_ofs > 0) {
716cabdff1aSopenharmony_ci        int64_t audio_dts, video_dts;
717cabdff1aSopenharmony_ci        AVStream *vst = wav->vst;
718cabdff1aSopenharmony_cismv_retry:
719cabdff1aSopenharmony_ci        audio_dts = (int32_t)ffstream( st)->cur_dts;
720cabdff1aSopenharmony_ci        video_dts = (int32_t)ffstream(vst)->cur_dts;
721cabdff1aSopenharmony_ci
722cabdff1aSopenharmony_ci        if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) {
723cabdff1aSopenharmony_ci            /*We always return a video frame first to get the pixel format first*/
724cabdff1aSopenharmony_ci            wav->smv_last_stream = wav->smv_given_first ?
725cabdff1aSopenharmony_ci                av_compare_ts(video_dts, vst->time_base,
726cabdff1aSopenharmony_ci                              audio_dts,  st->time_base) > 0 : 0;
727cabdff1aSopenharmony_ci            wav->smv_given_first = 1;
728cabdff1aSopenharmony_ci        }
729cabdff1aSopenharmony_ci        wav->smv_last_stream = !wav->smv_last_stream;
730cabdff1aSopenharmony_ci        wav->smv_last_stream |= wav->audio_eof;
731cabdff1aSopenharmony_ci        wav->smv_last_stream &= !wav->smv_eof;
732cabdff1aSopenharmony_ci        if (wav->smv_last_stream) {
733cabdff1aSopenharmony_ci            uint64_t old_pos = avio_tell(s->pb);
734cabdff1aSopenharmony_ci            uint64_t new_pos = wav->smv_data_ofs +
735cabdff1aSopenharmony_ci                wav->smv_block * (int64_t)wav->smv_block_size;
736cabdff1aSopenharmony_ci            if (avio_seek(s->pb, new_pos, SEEK_SET) < 0) {
737cabdff1aSopenharmony_ci                ret = AVERROR_EOF;
738cabdff1aSopenharmony_ci                goto smv_out;
739cabdff1aSopenharmony_ci            }
740cabdff1aSopenharmony_ci            size = avio_rl24(s->pb);
741cabdff1aSopenharmony_ci            if (size > wav->smv_block_size) {
742cabdff1aSopenharmony_ci                ret = AVERROR_EOF;
743cabdff1aSopenharmony_ci                goto smv_out;
744cabdff1aSopenharmony_ci            }
745cabdff1aSopenharmony_ci            ret  = av_get_packet(s->pb, pkt, size);
746cabdff1aSopenharmony_ci            if (ret < 0)
747cabdff1aSopenharmony_ci                goto smv_out;
748cabdff1aSopenharmony_ci            pkt->pos -= 3;
749cabdff1aSopenharmony_ci            pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg;
750cabdff1aSopenharmony_ci            pkt->duration = wav->smv_frames_per_jpeg;
751cabdff1aSopenharmony_ci            wav->smv_block++;
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci            pkt->stream_index = vst->index;
754cabdff1aSopenharmony_cismv_out:
755cabdff1aSopenharmony_ci            avio_seek(s->pb, old_pos, SEEK_SET);
756cabdff1aSopenharmony_ci            if (ret == AVERROR_EOF) {
757cabdff1aSopenharmony_ci                wav->smv_eof = 1;
758cabdff1aSopenharmony_ci                goto smv_retry;
759cabdff1aSopenharmony_ci            }
760cabdff1aSopenharmony_ci            return ret;
761cabdff1aSopenharmony_ci        }
762cabdff1aSopenharmony_ci    }
763cabdff1aSopenharmony_ci
764cabdff1aSopenharmony_ci    left = wav->data_end - avio_tell(s->pb);
765cabdff1aSopenharmony_ci    if (wav->ignore_length)
766cabdff1aSopenharmony_ci        left = INT_MAX;
767cabdff1aSopenharmony_ci    if (left <= 0) {
768cabdff1aSopenharmony_ci        if (CONFIG_W64_DEMUXER && wav->w64)
769cabdff1aSopenharmony_ci            left = find_guid(s->pb, ff_w64_guid_data) - 24;
770cabdff1aSopenharmony_ci        else
771cabdff1aSopenharmony_ci            left = find_tag(wav, s->pb, MKTAG('d', 'a', 't', 'a'));
772cabdff1aSopenharmony_ci        if (left < 0) {
773cabdff1aSopenharmony_ci            wav->audio_eof = 1;
774cabdff1aSopenharmony_ci            if (wav->smv_data_ofs > 0 && !wav->smv_eof)
775cabdff1aSopenharmony_ci                goto smv_retry;
776cabdff1aSopenharmony_ci            return AVERROR_EOF;
777cabdff1aSopenharmony_ci        }
778cabdff1aSopenharmony_ci        if (INT64_MAX - left < avio_tell(s->pb))
779cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
780cabdff1aSopenharmony_ci        wav->data_end = avio_tell(s->pb) + left;
781cabdff1aSopenharmony_ci    }
782cabdff1aSopenharmony_ci
783cabdff1aSopenharmony_ci    size = wav->max_size;
784cabdff1aSopenharmony_ci    if (st->codecpar->block_align > 1) {
785cabdff1aSopenharmony_ci        if (size < st->codecpar->block_align)
786cabdff1aSopenharmony_ci            size = st->codecpar->block_align;
787cabdff1aSopenharmony_ci        size = (size / st->codecpar->block_align) * st->codecpar->block_align;
788cabdff1aSopenharmony_ci    }
789cabdff1aSopenharmony_ci    size = FFMIN(size, left);
790cabdff1aSopenharmony_ci    ret  = av_get_packet(s->pb, pkt, size);
791cabdff1aSopenharmony_ci    if (ret < 0)
792cabdff1aSopenharmony_ci        return ret;
793cabdff1aSopenharmony_ci    pkt->stream_index = 0;
794cabdff1aSopenharmony_ci
795cabdff1aSopenharmony_ci    return ret;
796cabdff1aSopenharmony_ci}
797cabdff1aSopenharmony_ci
798cabdff1aSopenharmony_cistatic int wav_read_seek(AVFormatContext *s,
799cabdff1aSopenharmony_ci                         int stream_index, int64_t timestamp, int flags)
800cabdff1aSopenharmony_ci{
801cabdff1aSopenharmony_ci    WAVDemuxContext *wav = s->priv_data;
802cabdff1aSopenharmony_ci    AVStream *ast = s->streams[0], *vst = wav->vst;
803cabdff1aSopenharmony_ci    wav->smv_eof = 0;
804cabdff1aSopenharmony_ci    wav->audio_eof = 0;
805cabdff1aSopenharmony_ci
806cabdff1aSopenharmony_ci    if (stream_index != 0 && (!vst || stream_index != vst->index))
807cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
808cabdff1aSopenharmony_ci    if (wav->smv_data_ofs > 0) {
809cabdff1aSopenharmony_ci        int64_t smv_timestamp = timestamp;
810cabdff1aSopenharmony_ci        if (stream_index == 0)
811cabdff1aSopenharmony_ci            smv_timestamp = av_rescale_q(timestamp, ast->time_base, vst->time_base);
812cabdff1aSopenharmony_ci        else
813cabdff1aSopenharmony_ci            timestamp = av_rescale_q(smv_timestamp, vst->time_base, ast->time_base);
814cabdff1aSopenharmony_ci        if (wav->smv_frames_per_jpeg > 0) {
815cabdff1aSopenharmony_ci            wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
816cabdff1aSopenharmony_ci        }
817cabdff1aSopenharmony_ci    }
818cabdff1aSopenharmony_ci
819cabdff1aSopenharmony_ci    switch (ast->codecpar->codec_id) {
820cabdff1aSopenharmony_ci    case AV_CODEC_ID_MP2:
821cabdff1aSopenharmony_ci    case AV_CODEC_ID_MP3:
822cabdff1aSopenharmony_ci    case AV_CODEC_ID_AC3:
823cabdff1aSopenharmony_ci    case AV_CODEC_ID_DTS:
824cabdff1aSopenharmony_ci    case AV_CODEC_ID_XMA2:
825cabdff1aSopenharmony_ci        /* use generic seeking with dynamically generated indexes */
826cabdff1aSopenharmony_ci        return -1;
827cabdff1aSopenharmony_ci    default:
828cabdff1aSopenharmony_ci        break;
829cabdff1aSopenharmony_ci    }
830cabdff1aSopenharmony_ci    return ff_pcm_read_seek(s, 0, timestamp, flags);
831cabdff1aSopenharmony_ci}
832cabdff1aSopenharmony_ci
833cabdff1aSopenharmony_cistatic const AVClass wav_demuxer_class = {
834cabdff1aSopenharmony_ci    .class_name = "WAV demuxer",
835cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
836cabdff1aSopenharmony_ci    .option     = demux_options,
837cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
838cabdff1aSopenharmony_ci};
839cabdff1aSopenharmony_ciconst AVInputFormat ff_wav_demuxer = {
840cabdff1aSopenharmony_ci    .name           = "wav",
841cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"),
842cabdff1aSopenharmony_ci    .priv_data_size = sizeof(WAVDemuxContext),
843cabdff1aSopenharmony_ci    .read_probe     = wav_probe,
844cabdff1aSopenharmony_ci    .read_header    = wav_read_header,
845cabdff1aSopenharmony_ci    .read_packet    = wav_read_packet,
846cabdff1aSopenharmony_ci    .read_seek      = wav_read_seek,
847cabdff1aSopenharmony_ci    .flags          = AVFMT_GENERIC_INDEX,
848cabdff1aSopenharmony_ci    .codec_tag      = ff_wav_codec_tags_list,
849cabdff1aSopenharmony_ci    .priv_class     = &wav_demuxer_class,
850cabdff1aSopenharmony_ci};
851cabdff1aSopenharmony_ci#endif /* CONFIG_WAV_DEMUXER */
852cabdff1aSopenharmony_ci
853cabdff1aSopenharmony_ci#if CONFIG_W64_DEMUXER
854cabdff1aSopenharmony_cistatic int w64_probe(const AVProbeData *p)
855cabdff1aSopenharmony_ci{
856cabdff1aSopenharmony_ci    if (p->buf_size <= 40)
857cabdff1aSopenharmony_ci        return 0;
858cabdff1aSopenharmony_ci    if (!memcmp(p->buf,      ff_w64_guid_riff, 16) &&
859cabdff1aSopenharmony_ci        !memcmp(p->buf + 24, ff_w64_guid_wave, 16))
860cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX;
861cabdff1aSopenharmony_ci    else
862cabdff1aSopenharmony_ci        return 0;
863cabdff1aSopenharmony_ci}
864cabdff1aSopenharmony_ci
865cabdff1aSopenharmony_cistatic int w64_read_header(AVFormatContext *s)
866cabdff1aSopenharmony_ci{
867cabdff1aSopenharmony_ci    int64_t size, data_ofs = 0;
868cabdff1aSopenharmony_ci    AVIOContext *pb      = s->pb;
869cabdff1aSopenharmony_ci    WAVDemuxContext *wav = s->priv_data;
870cabdff1aSopenharmony_ci    AVStream *st;
871cabdff1aSopenharmony_ci    uint8_t guid[16];
872cabdff1aSopenharmony_ci    int ret;
873cabdff1aSopenharmony_ci
874cabdff1aSopenharmony_ci    if (avio_read(pb, guid, 16) != 16 || memcmp(guid, ff_w64_guid_riff, 16))
875cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
876cabdff1aSopenharmony_ci
877cabdff1aSopenharmony_ci    /* riff + wave + fmt + sizes */
878cabdff1aSopenharmony_ci    if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8)
879cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
880cabdff1aSopenharmony_ci
881cabdff1aSopenharmony_ci    avio_read(pb, guid, 16);
882cabdff1aSopenharmony_ci    if (memcmp(guid, ff_w64_guid_wave, 16)) {
883cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "could not find wave guid\n");
884cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
885cabdff1aSopenharmony_ci    }
886cabdff1aSopenharmony_ci
887cabdff1aSopenharmony_ci    wav->w64 = 1;
888cabdff1aSopenharmony_ci
889cabdff1aSopenharmony_ci    st = avformat_new_stream(s, NULL);
890cabdff1aSopenharmony_ci    if (!st)
891cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
892cabdff1aSopenharmony_ci
893cabdff1aSopenharmony_ci    while (!avio_feof(pb)) {
894cabdff1aSopenharmony_ci        if (avio_read(pb, guid, 16) != 16)
895cabdff1aSopenharmony_ci            break;
896cabdff1aSopenharmony_ci        size = avio_rl64(pb);
897cabdff1aSopenharmony_ci        if (size <= 24 || INT64_MAX - size < avio_tell(pb))
898cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
899cabdff1aSopenharmony_ci
900cabdff1aSopenharmony_ci        if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
901cabdff1aSopenharmony_ci            /* subtract chunk header size - normal wav file doesn't count it */
902cabdff1aSopenharmony_ci            ret = ff_get_wav_header(s, pb, st->codecpar, size - 24, 0);
903cabdff1aSopenharmony_ci            if (ret < 0)
904cabdff1aSopenharmony_ci                return ret;
905cabdff1aSopenharmony_ci            avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
906cabdff1aSopenharmony_ci
907cabdff1aSopenharmony_ci            avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
908cabdff1aSopenharmony_ci        } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
909cabdff1aSopenharmony_ci            int64_t samples;
910cabdff1aSopenharmony_ci
911cabdff1aSopenharmony_ci            samples = avio_rl64(pb);
912cabdff1aSopenharmony_ci            if (samples > 0)
913cabdff1aSopenharmony_ci                st->duration = samples;
914cabdff1aSopenharmony_ci            avio_skip(pb, FFALIGN(size, INT64_C(8)) - 32);
915cabdff1aSopenharmony_ci        } else if (!memcmp(guid, ff_w64_guid_data, 16)) {
916cabdff1aSopenharmony_ci            wav->data_end = avio_tell(pb) + size - 24;
917cabdff1aSopenharmony_ci
918cabdff1aSopenharmony_ci            data_ofs = avio_tell(pb);
919cabdff1aSopenharmony_ci            if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
920cabdff1aSopenharmony_ci                break;
921cabdff1aSopenharmony_ci
922cabdff1aSopenharmony_ci            avio_skip(pb, size - 24);
923cabdff1aSopenharmony_ci        } else if (!memcmp(guid, ff_w64_guid_summarylist, 16)) {
924cabdff1aSopenharmony_ci            int64_t start, end, cur;
925cabdff1aSopenharmony_ci            uint32_t count, chunk_size, i;
926cabdff1aSopenharmony_ci            int64_t filesize  = avio_size(s->pb);
927cabdff1aSopenharmony_ci
928cabdff1aSopenharmony_ci            start = avio_tell(pb);
929cabdff1aSopenharmony_ci            end = start + FFALIGN(size, INT64_C(8)) - 24;
930cabdff1aSopenharmony_ci            count = avio_rl32(pb);
931cabdff1aSopenharmony_ci
932cabdff1aSopenharmony_ci            for (i = 0; i < count; i++) {
933cabdff1aSopenharmony_ci                char chunk_key[5], *value;
934cabdff1aSopenharmony_ci
935cabdff1aSopenharmony_ci                if (avio_feof(pb) || (cur = avio_tell(pb)) < 0 || cur > end - 8 /* = tag + size */)
936cabdff1aSopenharmony_ci                    break;
937cabdff1aSopenharmony_ci
938cabdff1aSopenharmony_ci                chunk_key[4] = 0;
939cabdff1aSopenharmony_ci                avio_read(pb, chunk_key, 4);
940cabdff1aSopenharmony_ci                chunk_size = avio_rl32(pb);
941cabdff1aSopenharmony_ci                if (chunk_size == UINT32_MAX || (filesize >= 0 && chunk_size > filesize))
942cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
943cabdff1aSopenharmony_ci
944cabdff1aSopenharmony_ci                value = av_malloc(chunk_size + 1);
945cabdff1aSopenharmony_ci                if (!value)
946cabdff1aSopenharmony_ci                    return AVERROR(ENOMEM);
947cabdff1aSopenharmony_ci
948cabdff1aSopenharmony_ci                ret = avio_get_str16le(pb, chunk_size, value, chunk_size);
949cabdff1aSopenharmony_ci                if (ret < 0) {
950cabdff1aSopenharmony_ci                    av_free(value);
951cabdff1aSopenharmony_ci                    return ret;
952cabdff1aSopenharmony_ci                }
953cabdff1aSopenharmony_ci                avio_skip(pb, chunk_size - ret);
954cabdff1aSopenharmony_ci
955cabdff1aSopenharmony_ci                av_dict_set(&s->metadata, chunk_key, value, AV_DICT_DONT_STRDUP_VAL);
956cabdff1aSopenharmony_ci            }
957cabdff1aSopenharmony_ci
958cabdff1aSopenharmony_ci            avio_skip(pb, end - avio_tell(pb));
959cabdff1aSopenharmony_ci        } else {
960cabdff1aSopenharmony_ci            av_log(s, AV_LOG_DEBUG, "unknown guid: "FF_PRI_GUID"\n", FF_ARG_GUID(guid));
961cabdff1aSopenharmony_ci            avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
962cabdff1aSopenharmony_ci        }
963cabdff1aSopenharmony_ci    }
964cabdff1aSopenharmony_ci
965cabdff1aSopenharmony_ci    if (!data_ofs)
966cabdff1aSopenharmony_ci        return AVERROR_EOF;
967cabdff1aSopenharmony_ci
968cabdff1aSopenharmony_ci    ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
969cabdff1aSopenharmony_ci    ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);
970cabdff1aSopenharmony_ci
971cabdff1aSopenharmony_ci    handle_stream_probing(st);
972cabdff1aSopenharmony_ci    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
973cabdff1aSopenharmony_ci
974cabdff1aSopenharmony_ci    avio_seek(pb, data_ofs, SEEK_SET);
975cabdff1aSopenharmony_ci
976cabdff1aSopenharmony_ci    set_spdif(s, wav);
977cabdff1aSopenharmony_ci
978cabdff1aSopenharmony_ci    return 0;
979cabdff1aSopenharmony_ci}
980cabdff1aSopenharmony_ci
981cabdff1aSopenharmony_cistatic const AVClass w64_demuxer_class = {
982cabdff1aSopenharmony_ci    .class_name = "W64 demuxer",
983cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
984cabdff1aSopenharmony_ci    .option     = &demux_options[W64_DEMUXER_OPTIONS_OFFSET],
985cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
986cabdff1aSopenharmony_ci};
987cabdff1aSopenharmony_ci
988cabdff1aSopenharmony_ciconst AVInputFormat ff_w64_demuxer = {
989cabdff1aSopenharmony_ci    .name           = "w64",
990cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Sony Wave64"),
991cabdff1aSopenharmony_ci    .priv_data_size = sizeof(WAVDemuxContext),
992cabdff1aSopenharmony_ci    .read_probe     = w64_probe,
993cabdff1aSopenharmony_ci    .read_header    = w64_read_header,
994cabdff1aSopenharmony_ci    .read_packet    = wav_read_packet,
995cabdff1aSopenharmony_ci    .read_seek      = wav_read_seek,
996cabdff1aSopenharmony_ci    .flags          = AVFMT_GENERIC_INDEX,
997cabdff1aSopenharmony_ci    .codec_tag      = ff_wav_codec_tags_list,
998cabdff1aSopenharmony_ci    .priv_class     = &w64_demuxer_class,
999cabdff1aSopenharmony_ci};
1000cabdff1aSopenharmony_ci#endif /* CONFIG_W64_DEMUXER */
1001