FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/brstm.c
Date: 2024-04-24 02:45:42
Exec Total Coverage
Lines: 224 292 76.7%
Functions: 8 9 88.9%
Branches: 125 190 65.8%

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