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