1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * BRSTM demuxer
3cabdff1aSopenharmony_ci * Copyright (c) 2012 Paul B Mahol
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#include "libavutil/intreadwrite.h"
23cabdff1aSopenharmony_ci#include "libavcodec/bytestream.h"
24cabdff1aSopenharmony_ci#include "avformat.h"
25cabdff1aSopenharmony_ci#include "demux.h"
26cabdff1aSopenharmony_ci#include "internal.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_citypedef struct BRSTMCoeffOffset {
29cabdff1aSopenharmony_ci    uint8_t  channel;
30cabdff1aSopenharmony_ci    uint32_t offset;
31cabdff1aSopenharmony_ci} BRSTMCoeffOffset;
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_citypedef struct BRSTMDemuxContext {
34cabdff1aSopenharmony_ci    uint32_t    block_size;
35cabdff1aSopenharmony_ci    uint32_t    block_count;
36cabdff1aSopenharmony_ci    uint32_t    current_block;
37cabdff1aSopenharmony_ci    uint32_t    samples_per_block;
38cabdff1aSopenharmony_ci    uint32_t    last_block_used_bytes;
39cabdff1aSopenharmony_ci    uint32_t    last_block_size;
40cabdff1aSopenharmony_ci    uint32_t    last_block_samples;
41cabdff1aSopenharmony_ci    uint32_t    data_start;
42cabdff1aSopenharmony_ci    uint8_t     table[256 * 32];
43cabdff1aSopenharmony_ci    uint8_t     *adpc;
44cabdff1aSopenharmony_ci    BRSTMCoeffOffset offsets[256];
45cabdff1aSopenharmony_ci    int         little_endian;
46cabdff1aSopenharmony_ci} BRSTMDemuxContext;
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_cistatic int probe(const AVProbeData *p)
49cabdff1aSopenharmony_ci{
50cabdff1aSopenharmony_ci    if (AV_RL32(p->buf) == MKTAG('R','S','T','M') &&
51cabdff1aSopenharmony_ci        (AV_RL16(p->buf + 4) == 0xFFFE ||
52cabdff1aSopenharmony_ci         AV_RL16(p->buf + 4) == 0xFEFF))
53cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX / 3 * 2;
54cabdff1aSopenharmony_ci    return 0;
55cabdff1aSopenharmony_ci}
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_cistatic int probe_bfstm(const AVProbeData *p)
58cabdff1aSopenharmony_ci{
59cabdff1aSopenharmony_ci    if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') ||
60cabdff1aSopenharmony_ci         AV_RL32(p->buf) == MKTAG('C','S','T','M')) &&
61cabdff1aSopenharmony_ci        (AV_RL16(p->buf + 4) == 0xFFFE ||
62cabdff1aSopenharmony_ci         AV_RL16(p->buf + 4) == 0xFEFF))
63cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX / 3 * 2;
64cabdff1aSopenharmony_ci    return 0;
65cabdff1aSopenharmony_ci}
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_cistatic int read_close(AVFormatContext *s)
68cabdff1aSopenharmony_ci{
69cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    av_freep(&b->adpc);
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    return 0;
74cabdff1aSopenharmony_ci}
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_cistatic int sort_offsets(const void *a, const void *b)
77cabdff1aSopenharmony_ci{
78cabdff1aSopenharmony_ci    const BRSTMCoeffOffset *s1 = a;
79cabdff1aSopenharmony_ci    const BRSTMCoeffOffset *s2 = b;
80cabdff1aSopenharmony_ci    return FFDIFFSIGN(s1->offset, s2->offset);
81cabdff1aSopenharmony_ci}
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_cistatic av_always_inline unsigned int read16(AVFormatContext *s)
84cabdff1aSopenharmony_ci{
85cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
86cabdff1aSopenharmony_ci    if (b->little_endian)
87cabdff1aSopenharmony_ci        return avio_rl16(s->pb);
88cabdff1aSopenharmony_ci    else
89cabdff1aSopenharmony_ci        return avio_rb16(s->pb);
90cabdff1aSopenharmony_ci}
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_cistatic av_always_inline unsigned int read32(AVFormatContext *s)
93cabdff1aSopenharmony_ci{
94cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
95cabdff1aSopenharmony_ci    if (b->little_endian)
96cabdff1aSopenharmony_ci        return avio_rl32(s->pb);
97cabdff1aSopenharmony_ci    else
98cabdff1aSopenharmony_ci        return avio_rb32(s->pb);
99cabdff1aSopenharmony_ci}
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_cistatic int read_header(AVFormatContext *s)
102cabdff1aSopenharmony_ci{
103cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
104cabdff1aSopenharmony_ci    int bom, major, minor, codec, chunk;
105cabdff1aSopenharmony_ci    int64_t h1offset, pos, toffset;
106cabdff1aSopenharmony_ci    uint32_t size, asize, start = 0;
107cabdff1aSopenharmony_ci    AVStream *st;
108cabdff1aSopenharmony_ci    int loop = 0;
109cabdff1aSopenharmony_ci    int bfstm = !strcmp("bfstm", s->iformat->name);
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    st = avformat_new_stream(s, NULL);
112cabdff1aSopenharmony_ci    if (!st)
113cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
114cabdff1aSopenharmony_ci    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    avio_skip(s->pb, 4);
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    bom = avio_rb16(s->pb);
119cabdff1aSopenharmony_ci    if (bom != 0xFEFF && bom != 0xFFFE) {
120cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "invalid byte order: %X\n", bom);
121cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
122cabdff1aSopenharmony_ci    }
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci    if (bom == 0xFFFE)
125cabdff1aSopenharmony_ci        b->little_endian = 1;
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci    if (!bfstm) {
128cabdff1aSopenharmony_ci        major = avio_r8(s->pb);
129cabdff1aSopenharmony_ci        minor = avio_r8(s->pb);
130cabdff1aSopenharmony_ci        avio_skip(s->pb, 4); // size of file
131cabdff1aSopenharmony_ci        size = read16(s);
132cabdff1aSopenharmony_ci        if (size < 14)
133cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci        avio_skip(s->pb, size - 14);
136cabdff1aSopenharmony_ci        pos = avio_tell(s->pb);
137cabdff1aSopenharmony_ci        if (avio_rl32(s->pb) != MKTAG('H','E','A','D'))
138cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
139cabdff1aSopenharmony_ci    } else {
140cabdff1aSopenharmony_ci        uint32_t info_offset = 0;
141cabdff1aSopenharmony_ci        uint16_t section_count, header_size, i;
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci        header_size = read16(s); // 6
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci        avio_skip(s->pb, 4); // Unknown constant 0x00030000
146cabdff1aSopenharmony_ci        avio_skip(s->pb, 4); // size of file
147cabdff1aSopenharmony_ci        section_count = read16(s);
148cabdff1aSopenharmony_ci        avio_skip(s->pb, 2); // padding
149cabdff1aSopenharmony_ci        for (i = 0; avio_tell(s->pb) < header_size
150cabdff1aSopenharmony_ci                    && !(start && info_offset)
151cabdff1aSopenharmony_ci                    && i < section_count; i++) {
152cabdff1aSopenharmony_ci            uint16_t flag = read16(s);
153cabdff1aSopenharmony_ci            avio_skip(s->pb, 2);
154cabdff1aSopenharmony_ci            switch (flag) {
155cabdff1aSopenharmony_ci            case 0x4000:
156cabdff1aSopenharmony_ci                info_offset = read32(s);
157cabdff1aSopenharmony_ci                /*info_size =*/ read32(s);
158cabdff1aSopenharmony_ci                break;
159cabdff1aSopenharmony_ci            case 0x4001:
160cabdff1aSopenharmony_ci                avio_skip(s->pb, 4); // seek offset
161cabdff1aSopenharmony_ci                avio_skip(s->pb, 4); // seek size
162cabdff1aSopenharmony_ci                break;
163cabdff1aSopenharmony_ci            case 0x4002:
164cabdff1aSopenharmony_ci                start = read32(s) + 8;
165cabdff1aSopenharmony_ci                avio_skip(s->pb, 4); //data_size = read32(s);
166cabdff1aSopenharmony_ci                break;
167cabdff1aSopenharmony_ci            case 0x4003:
168cabdff1aSopenharmony_ci                avio_skip(s->pb, 4); // REGN offset
169cabdff1aSopenharmony_ci                avio_skip(s->pb, 4); // REGN size
170cabdff1aSopenharmony_ci                break;
171cabdff1aSopenharmony_ci            }
172cabdff1aSopenharmony_ci        }
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_ci        if (!info_offset || !start)
175cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci        avio_skip(s->pb, info_offset - avio_tell(s->pb));
178cabdff1aSopenharmony_ci        pos = avio_tell(s->pb);
179cabdff1aSopenharmony_ci        if (avio_rl32(s->pb) != MKTAG('I','N','F','O'))
180cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
181cabdff1aSopenharmony_ci    }
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    size = read32(s);
184cabdff1aSopenharmony_ci    if (size < 40)
185cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
186cabdff1aSopenharmony_ci    avio_skip(s->pb, 4); // unknown
187cabdff1aSopenharmony_ci    h1offset = read32(s);
188cabdff1aSopenharmony_ci    if (h1offset > size)
189cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
190cabdff1aSopenharmony_ci    avio_skip(s->pb, 12);
191cabdff1aSopenharmony_ci    toffset = read32(s) + 16LL;
192cabdff1aSopenharmony_ci    if (toffset > size)
193cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    avio_skip(s->pb, pos + h1offset + 8 - avio_tell(s->pb));
196cabdff1aSopenharmony_ci    codec = avio_r8(s->pb);
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci    switch (codec) {
199cabdff1aSopenharmony_ci    case 0: codec = AV_CODEC_ID_PCM_S8_PLANAR;    break;
200cabdff1aSopenharmony_ci    case 1: codec = b->little_endian ?
201cabdff1aSopenharmony_ci                    AV_CODEC_ID_PCM_S16LE_PLANAR :
202cabdff1aSopenharmony_ci                    AV_CODEC_ID_PCM_S16BE_PLANAR; break;
203cabdff1aSopenharmony_ci    case 2: codec = b->little_endian ?
204cabdff1aSopenharmony_ci                    AV_CODEC_ID_ADPCM_THP_LE :
205cabdff1aSopenharmony_ci                    AV_CODEC_ID_ADPCM_THP;        break;
206cabdff1aSopenharmony_ci    default:
207cabdff1aSopenharmony_ci        avpriv_request_sample(s, "codec %d", codec);
208cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
209cabdff1aSopenharmony_ci    }
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci    loop = avio_r8(s->pb); // loop flag
212cabdff1aSopenharmony_ci    st->codecpar->codec_id = codec;
213cabdff1aSopenharmony_ci    st->codecpar->ch_layout.nb_channels = avio_r8(s->pb);
214cabdff1aSopenharmony_ci    if (!st->codecpar->ch_layout.nb_channels)
215cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci    avio_skip(s->pb, 1); // padding
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    st->codecpar->sample_rate = bfstm ? read32(s) : read16(s);
220cabdff1aSopenharmony_ci    if (st->codecpar->sample_rate <= 0)
221cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
222cabdff1aSopenharmony_ci
223cabdff1aSopenharmony_ci    if (!bfstm)
224cabdff1aSopenharmony_ci        avio_skip(s->pb, 2); // padding
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci    if (loop) {
227cabdff1aSopenharmony_ci        if (av_dict_set_int(&s->metadata, "loop_start",
228cabdff1aSopenharmony_ci                            av_rescale(read32(s), AV_TIME_BASE,
229cabdff1aSopenharmony_ci                                       st->codecpar->sample_rate),
230cabdff1aSopenharmony_ci                            0) < 0)
231cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
232cabdff1aSopenharmony_ci    } else {
233cabdff1aSopenharmony_ci        avio_skip(s->pb, 4);
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci
236cabdff1aSopenharmony_ci    st->start_time = 0;
237cabdff1aSopenharmony_ci    st->duration = read32(s);
238cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci    if (!bfstm)
241cabdff1aSopenharmony_ci        start = read32(s);
242cabdff1aSopenharmony_ci    b->current_block = 0;
243cabdff1aSopenharmony_ci    b->block_count = read32(s);
244cabdff1aSopenharmony_ci    if (b->block_count > UINT16_MAX) {
245cabdff1aSopenharmony_ci        av_log(s, AV_LOG_WARNING, "too many blocks: %"PRIu32"\n", b->block_count);
246cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
247cabdff1aSopenharmony_ci    }
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci    b->block_size = read32(s);
250cabdff1aSopenharmony_ci    if (b->block_size > UINT32_MAX / st->codecpar->ch_layout.nb_channels)
251cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci    b->samples_per_block = read32(s);
254cabdff1aSopenharmony_ci    b->last_block_used_bytes = read32(s);
255cabdff1aSopenharmony_ci    b->last_block_samples = read32(s);
256cabdff1aSopenharmony_ci    b->last_block_size = read32(s);
257cabdff1aSopenharmony_ci    if (b->last_block_size > UINT32_MAX / st->codecpar->ch_layout.nb_channels)
258cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
259cabdff1aSopenharmony_ci    if (b->last_block_used_bytes > b->last_block_size)
260cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    if (codec == AV_CODEC_ID_ADPCM_THP || codec == AV_CODEC_ID_ADPCM_THP_LE) {
264cabdff1aSopenharmony_ci        int ch;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci        avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
267cabdff1aSopenharmony_ci        if (!bfstm)
268cabdff1aSopenharmony_ci            toffset = read32(s) + 16LL;
269cabdff1aSopenharmony_ci        else
270cabdff1aSopenharmony_ci            toffset = toffset + read32(s) + st->codecpar->ch_layout.nb_channels * 8 - 8;
271cabdff1aSopenharmony_ci        if (toffset > size)
272cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
273cabdff1aSopenharmony_ci
274cabdff1aSopenharmony_ci        if (!bfstm) {
275cabdff1aSopenharmony_ci            avio_skip(s->pb, pos + toffset - avio_tell(s->pb) - 8LL * (st->codecpar->ch_layout.nb_channels + 1));
276cabdff1aSopenharmony_ci            for (ch = 0; ch < st->codecpar->ch_layout.nb_channels; ch++) {
277cabdff1aSopenharmony_ci                avio_skip(s->pb, 4);
278cabdff1aSopenharmony_ci                b->offsets[ch].channel = ch;
279cabdff1aSopenharmony_ci                b->offsets[ch].offset = read32(s);
280cabdff1aSopenharmony_ci            }
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci            qsort(b->offsets, st->codecpar->ch_layout.nb_channels, sizeof(*b->offsets), sort_offsets);
283cabdff1aSopenharmony_ci        }
284cabdff1aSopenharmony_ci
285cabdff1aSopenharmony_ci        avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci        for (ch = 0; ch < st->codecpar->ch_layout.nb_channels; ch++) {
288cabdff1aSopenharmony_ci            if (!bfstm)
289cabdff1aSopenharmony_ci                avio_skip(s->pb, pos + 16LL + b->offsets[ch].offset - avio_tell(s->pb));
290cabdff1aSopenharmony_ci
291cabdff1aSopenharmony_ci            if (avio_read(s->pb, b->table + ch * 32, 32) != 32)
292cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
293cabdff1aSopenharmony_ci
294cabdff1aSopenharmony_ci            if (bfstm)
295cabdff1aSopenharmony_ci                avio_skip(s->pb, 14);
296cabdff1aSopenharmony_ci        }
297cabdff1aSopenharmony_ci    }
298cabdff1aSopenharmony_ci
299cabdff1aSopenharmony_ci    if (size < (avio_tell(s->pb) - pos))
300cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
301cabdff1aSopenharmony_ci
302cabdff1aSopenharmony_ci    avio_skip(s->pb, size - (avio_tell(s->pb) - pos));
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    while (!avio_feof(s->pb)) {
305cabdff1aSopenharmony_ci        chunk = avio_rl32(s->pb);
306cabdff1aSopenharmony_ci        size  = read32(s);
307cabdff1aSopenharmony_ci        if (size < 8)
308cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
309cabdff1aSopenharmony_ci        size -= 8;
310cabdff1aSopenharmony_ci        switch (chunk) {
311cabdff1aSopenharmony_ci        case MKTAG('S','E','E','K'):
312cabdff1aSopenharmony_ci        case MKTAG('A','D','P','C'):
313cabdff1aSopenharmony_ci            if (codec != AV_CODEC_ID_ADPCM_THP &&
314cabdff1aSopenharmony_ci                codec != AV_CODEC_ID_ADPCM_THP_LE)
315cabdff1aSopenharmony_ci                goto skip;
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci            asize = b->block_count * st->codecpar->ch_layout.nb_channels * 4;
318cabdff1aSopenharmony_ci            if (size < asize)
319cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
320cabdff1aSopenharmony_ci            if (b->adpc) {
321cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "skipping additional ADPC chunk\n");
322cabdff1aSopenharmony_ci                goto skip;
323cabdff1aSopenharmony_ci            } else {
324cabdff1aSopenharmony_ci                b->adpc = av_mallocz(asize);
325cabdff1aSopenharmony_ci                if (!b->adpc)
326cabdff1aSopenharmony_ci                    return AVERROR(ENOMEM);
327cabdff1aSopenharmony_ci                if (bfstm && codec != AV_CODEC_ID_ADPCM_THP_LE) {
328cabdff1aSopenharmony_ci                    // Big-endian BFSTMs have little-endian SEEK tables
329cabdff1aSopenharmony_ci                    // for some strange reason.
330cabdff1aSopenharmony_ci                    int i;
331cabdff1aSopenharmony_ci                    for (i = 0; i < asize; i += 2) {
332cabdff1aSopenharmony_ci                        b->adpc[i+1] = avio_r8(s->pb);
333cabdff1aSopenharmony_ci                        b->adpc[i]   = avio_r8(s->pb);
334cabdff1aSopenharmony_ci                    }
335cabdff1aSopenharmony_ci                } else {
336cabdff1aSopenharmony_ci                    avio_read(s->pb, b->adpc, asize);
337cabdff1aSopenharmony_ci                }
338cabdff1aSopenharmony_ci                avio_skip(s->pb, size - asize);
339cabdff1aSopenharmony_ci            }
340cabdff1aSopenharmony_ci            break;
341cabdff1aSopenharmony_ci        case MKTAG('D','A','T','A'):
342cabdff1aSopenharmony_ci            if ((start < avio_tell(s->pb)) ||
343cabdff1aSopenharmony_ci                (!b->adpc && (codec == AV_CODEC_ID_ADPCM_THP ||
344cabdff1aSopenharmony_ci                              codec == AV_CODEC_ID_ADPCM_THP_LE)))
345cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
346cabdff1aSopenharmony_ci            avio_skip(s->pb, start - avio_tell(s->pb));
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci            if (bfstm && (codec == AV_CODEC_ID_ADPCM_THP ||
349cabdff1aSopenharmony_ci                          codec == AV_CODEC_ID_ADPCM_THP_LE))
350cabdff1aSopenharmony_ci                avio_skip(s->pb, 24);
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci            b->data_start = avio_tell(s->pb);
353cabdff1aSopenharmony_ci
354cabdff1aSopenharmony_ci            if (!bfstm && (major != 1 || minor))
355cabdff1aSopenharmony_ci                avpriv_request_sample(s, "Version %d.%d", major, minor);
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci            return 0;
358cabdff1aSopenharmony_ci        default:
359cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "skipping unknown chunk: %X\n", chunk);
360cabdff1aSopenharmony_ciskip:
361cabdff1aSopenharmony_ci            avio_skip(s->pb, size);
362cabdff1aSopenharmony_ci        }
363cabdff1aSopenharmony_ci    }
364cabdff1aSopenharmony_ci
365cabdff1aSopenharmony_ci    return AVERROR_EOF;
366cabdff1aSopenharmony_ci}
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_cistatic int read_packet(AVFormatContext *s, AVPacket *pkt)
369cabdff1aSopenharmony_ci{
370cabdff1aSopenharmony_ci    AVCodecParameters *par = s->streams[0]->codecpar;
371cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
372cabdff1aSopenharmony_ci    uint32_t samples, size, skip = 0;
373cabdff1aSopenharmony_ci    int channels = par->ch_layout.nb_channels;
374cabdff1aSopenharmony_ci    int ret, i;
375cabdff1aSopenharmony_ci
376cabdff1aSopenharmony_ci    if (avio_feof(s->pb))
377cabdff1aSopenharmony_ci        return AVERROR_EOF;
378cabdff1aSopenharmony_ci    b->current_block++;
379cabdff1aSopenharmony_ci    if (b->current_block == b->block_count) {
380cabdff1aSopenharmony_ci        size    = b->last_block_used_bytes;
381cabdff1aSopenharmony_ci        samples = b->last_block_samples;
382cabdff1aSopenharmony_ci        skip    = b->last_block_size - b->last_block_used_bytes;
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci        if (samples < size * 14 / 8) {
385cabdff1aSopenharmony_ci            uint32_t adjusted_size = samples / 14 * 8;
386cabdff1aSopenharmony_ci            if (samples % 14)
387cabdff1aSopenharmony_ci                adjusted_size += (samples % 14 + 1) / 2 + 1;
388cabdff1aSopenharmony_ci
389cabdff1aSopenharmony_ci            skip += size - adjusted_size;
390cabdff1aSopenharmony_ci            size = adjusted_size;
391cabdff1aSopenharmony_ci        }
392cabdff1aSopenharmony_ci    } else if (b->current_block < b->block_count) {
393cabdff1aSopenharmony_ci        size    = b->block_size;
394cabdff1aSopenharmony_ci        samples = b->samples_per_block;
395cabdff1aSopenharmony_ci    } else {
396cabdff1aSopenharmony_ci        return AVERROR_EOF;
397cabdff1aSopenharmony_ci    }
398cabdff1aSopenharmony_ci
399cabdff1aSopenharmony_ci    if (par->codec_id == AV_CODEC_ID_ADPCM_THP ||
400cabdff1aSopenharmony_ci        par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) {
401cabdff1aSopenharmony_ci        uint8_t *dst;
402cabdff1aSopenharmony_ci
403cabdff1aSopenharmony_ci        if (!b->adpc) {
404cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "adpcm_thp requires ADPC chunk, but none was found.\n");
405cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
406cabdff1aSopenharmony_ci        }
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci        if (size > (INT_MAX - 32 - 4) ||
409cabdff1aSopenharmony_ci            (32 + 4 + size) > (INT_MAX / channels) ||
410cabdff1aSopenharmony_ci            (32 + 4 + size) * channels > INT_MAX - 8)
411cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
412cabdff1aSopenharmony_ci        if ((ret = av_new_packet(pkt, 8 + (32 + 4 + size) * channels)) < 0)
413cabdff1aSopenharmony_ci            return ret;
414cabdff1aSopenharmony_ci        dst = pkt->data;
415cabdff1aSopenharmony_ci        if (par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) {
416cabdff1aSopenharmony_ci            bytestream_put_le32(&dst, size * channels);
417cabdff1aSopenharmony_ci            bytestream_put_le32(&dst, samples);
418cabdff1aSopenharmony_ci        } else {
419cabdff1aSopenharmony_ci            bytestream_put_be32(&dst, size * channels);
420cabdff1aSopenharmony_ci            bytestream_put_be32(&dst, samples);
421cabdff1aSopenharmony_ci        }
422cabdff1aSopenharmony_ci        bytestream_put_buffer(&dst, b->table, 32 * channels);
423cabdff1aSopenharmony_ci        bytestream_put_buffer(&dst, b->adpc + 4 * channels *
424cabdff1aSopenharmony_ci                                    (b->current_block - 1), 4 * channels);
425cabdff1aSopenharmony_ci
426cabdff1aSopenharmony_ci        for (i = 0; i < channels; i++) {
427cabdff1aSopenharmony_ci            ret = avio_read(s->pb, dst, size);
428cabdff1aSopenharmony_ci            dst += size;
429cabdff1aSopenharmony_ci            avio_skip(s->pb, skip);
430cabdff1aSopenharmony_ci            if (ret != size) {
431cabdff1aSopenharmony_ci                return AVERROR(EIO);
432cabdff1aSopenharmony_ci            }
433cabdff1aSopenharmony_ci        }
434cabdff1aSopenharmony_ci        pkt->duration = samples;
435cabdff1aSopenharmony_ci    } else {
436cabdff1aSopenharmony_ci        size *= channels;
437cabdff1aSopenharmony_ci        ret = av_get_packet(s->pb, pkt, size);
438cabdff1aSopenharmony_ci    }
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    pkt->stream_index = 0;
441cabdff1aSopenharmony_ci
442cabdff1aSopenharmony_ci    if (ret != size)
443cabdff1aSopenharmony_ci        ret = AVERROR(EIO);
444cabdff1aSopenharmony_ci
445cabdff1aSopenharmony_ci    return ret;
446cabdff1aSopenharmony_ci}
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_cistatic int read_seek(AVFormatContext *s, int stream_index,
449cabdff1aSopenharmony_ci                     int64_t timestamp, int flags)
450cabdff1aSopenharmony_ci{
451cabdff1aSopenharmony_ci    AVStream *st = s->streams[stream_index];
452cabdff1aSopenharmony_ci    BRSTMDemuxContext *b = s->priv_data;
453cabdff1aSopenharmony_ci    int64_t ret = 0;
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_ci    if (timestamp < 0)
456cabdff1aSopenharmony_ci        timestamp = 0;
457cabdff1aSopenharmony_ci    timestamp /= b->samples_per_block;
458cabdff1aSopenharmony_ci    if (timestamp >= b->block_count)
459cabdff1aSopenharmony_ci        timestamp = b->block_count - 1;
460cabdff1aSopenharmony_ci    ret = avio_seek(s->pb, b->data_start + timestamp * b->block_size *
461cabdff1aSopenharmony_ci                           st->codecpar->ch_layout.nb_channels, SEEK_SET);
462cabdff1aSopenharmony_ci    if (ret < 0)
463cabdff1aSopenharmony_ci        return ret;
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci    b->current_block = timestamp;
466cabdff1aSopenharmony_ci    avpriv_update_cur_dts(s, st, timestamp * b->samples_per_block);
467cabdff1aSopenharmony_ci    return 0;
468cabdff1aSopenharmony_ci}
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_ciconst AVInputFormat ff_brstm_demuxer = {
471cabdff1aSopenharmony_ci    .name           = "brstm",
472cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("BRSTM (Binary Revolution Stream)"),
473cabdff1aSopenharmony_ci    .priv_data_size = sizeof(BRSTMDemuxContext),
474cabdff1aSopenharmony_ci    .flags_internal = FF_FMT_INIT_CLEANUP,
475cabdff1aSopenharmony_ci    .read_probe     = probe,
476cabdff1aSopenharmony_ci    .read_header    = read_header,
477cabdff1aSopenharmony_ci    .read_packet    = read_packet,
478cabdff1aSopenharmony_ci    .read_close     = read_close,
479cabdff1aSopenharmony_ci    .read_seek      = read_seek,
480cabdff1aSopenharmony_ci    .extensions     = "brstm",
481cabdff1aSopenharmony_ci};
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ciconst AVInputFormat ff_bfstm_demuxer = {
484cabdff1aSopenharmony_ci    .name           = "bfstm",
485cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("BFSTM (Binary Cafe Stream)"),
486cabdff1aSopenharmony_ci    .priv_data_size = sizeof(BRSTMDemuxContext),
487cabdff1aSopenharmony_ci    .flags_internal = FF_FMT_INIT_CLEANUP,
488cabdff1aSopenharmony_ci    .read_probe     = probe_bfstm,
489cabdff1aSopenharmony_ci    .read_header    = read_header,
490cabdff1aSopenharmony_ci    .read_packet    = read_packet,
491cabdff1aSopenharmony_ci    .read_close     = read_close,
492cabdff1aSopenharmony_ci    .read_seek      = read_seek,
493cabdff1aSopenharmony_ci    .extensions     = "bfstm,bcstm",
494cabdff1aSopenharmony_ci};
495