/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 | 964k | { |
52 | 964k | if (AV_RL32(p->buf) == MKTAG('R','S','T','M') && |
53 | 423 | (AV_RL16(p->buf + 4) == 0xFFFE || |
54 | 285 | AV_RL16(p->buf + 4) == 0xFEFF)) |
55 | 237 | return AVPROBE_SCORE_MAX / 3 * 2; |
56 | 964k | return 0; |
57 | 964k | } |
58 | | |
59 | | static int probe_bfstm(const AVProbeData *p) |
60 | 964k | { |
61 | 964k | if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') || |
62 | 964k | AV_RL32(p->buf) == MKTAG('C','S','T','M')) && |
63 | 782 | (AV_RL16(p->buf + 4) == 0xFFFE || |
64 | 521 | AV_RL16(p->buf + 4) == 0xFEFF)) |
65 | 479 | return AVPROBE_SCORE_MAX / 3 * 2; |
66 | 964k | return 0; |
67 | 964k | } |
68 | | |
69 | | static int read_close(AVFormatContext *s) |
70 | 6.02k | { |
71 | 6.02k | BRSTMDemuxContext *b = s->priv_data; |
72 | | |
73 | 6.02k | av_freep(&b->adpc); |
74 | | |
75 | 6.02k | return 0; |
76 | 6.02k | } |
77 | | |
78 | | static int sort_offsets(const void *a, const void *b) |
79 | 109k | { |
80 | 109k | const BRSTMCoeffOffset *s1 = a; |
81 | 109k | const BRSTMCoeffOffset *s2 = b; |
82 | 109k | return FFDIFFSIGN(s1->offset, s2->offset); |
83 | 109k | } |
84 | | |
85 | | static av_always_inline unsigned int read16(AVFormatContext *s) |
86 | 7.17M | { |
87 | 7.17M | BRSTMDemuxContext *b = s->priv_data; |
88 | 7.17M | if (b->little_endian) |
89 | 2.45M | return avio_rl16(s->pb); |
90 | 4.72M | else |
91 | 4.72M | return avio_rb16(s->pb); |
92 | 7.17M | } |
93 | | |
94 | | static av_always_inline unsigned int read32(AVFormatContext *s) |
95 | 926k | { |
96 | 926k | BRSTMDemuxContext *b = s->priv_data; |
97 | 926k | if (b->little_endian) |
98 | 892k | return avio_rl32(s->pb); |
99 | 34.6k | else |
100 | 34.6k | return avio_rb32(s->pb); |
101 | 926k | } |
102 | | |
103 | | static int read_header(AVFormatContext *s) |
104 | 6.02k | { |
105 | 6.02k | BRSTMDemuxContext *b = s->priv_data; |
106 | 6.02k | int bom, major, minor, codec, chunk; |
107 | 6.02k | int64_t h1offset, pos, toffset; |
108 | 6.02k | uint32_t size, asize, start = 0; |
109 | 6.02k | AVStream *st; |
110 | 6.02k | int loop = 0; |
111 | 6.02k | int bfstm = !strcmp("bfstm", s->iformat->name); |
112 | | |
113 | 6.02k | st = avformat_new_stream(s, NULL); |
114 | 6.02k | if (!st) |
115 | 0 | return AVERROR(ENOMEM); |
116 | 6.02k | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
117 | | |
118 | 6.02k | avio_skip(s->pb, 4); |
119 | | |
120 | 6.02k | bom = avio_rb16(s->pb); |
121 | 6.02k | if (bom != 0xFEFF && bom != 0xFFFE) { |
122 | 315 | av_log(s, AV_LOG_ERROR, "invalid byte order: %X\n", bom); |
123 | 315 | return AVERROR_INVALIDDATA; |
124 | 315 | } |
125 | | |
126 | 5.71k | if (bom == 0xFFFE) |
127 | 3.97k | b->little_endian = 1; |
128 | | |
129 | 5.71k | if (!bfstm) { |
130 | 2.79k | major = avio_r8(s->pb); |
131 | 2.79k | minor = avio_r8(s->pb); |
132 | 2.79k | avio_skip(s->pb, 4); // size of file |
133 | 2.79k | size = read16(s); |
134 | 2.79k | if (size < 14) |
135 | 18 | return AVERROR_INVALIDDATA; |
136 | | |
137 | 2.78k | avio_skip(s->pb, size - 14); |
138 | 2.78k | pos = avio_tell(s->pb); |
139 | 2.78k | if (avio_rl32(s->pb) != MKTAG('H','E','A','D')) |
140 | 159 | return AVERROR_INVALIDDATA; |
141 | 2.91k | } else { |
142 | 2.91k | uint32_t info_offset = 0; |
143 | 2.91k | uint16_t section_count, header_size, i; |
144 | | |
145 | 2.91k | header_size = read16(s); // 6 |
146 | | |
147 | 2.91k | avio_skip(s->pb, 4); // Unknown constant 0x00030000 |
148 | 2.91k | avio_skip(s->pb, 4); // size of file |
149 | 2.91k | section_count = read16(s); |
150 | 2.91k | avio_skip(s->pb, 2); // padding |
151 | 7.16M | for (i = 0; avio_tell(s->pb) < header_size |
152 | 7.16M | && !(start && info_offset) |
153 | 7.16M | && i < section_count; i++) { |
154 | 7.16M | uint16_t flag = read16(s); |
155 | 7.16M | avio_skip(s->pb, 2); |
156 | 7.16M | switch (flag) { |
157 | 4.28k | case 0x4000: |
158 | 4.28k | info_offset = read32(s); |
159 | 4.28k | /*info_size =*/ read32(s); |
160 | 4.28k | break; |
161 | 413 | case 0x4001: |
162 | 413 | avio_skip(s->pb, 4); // seek offset |
163 | 413 | avio_skip(s->pb, 4); // seek size |
164 | 413 | break; |
165 | 2.99k | case 0x4002: |
166 | 2.99k | start = read32(s) + 8; |
167 | 2.99k | avio_skip(s->pb, 4); //data_size = read32(s); |
168 | 2.99k | break; |
169 | 222 | case 0x4003: |
170 | 222 | avio_skip(s->pb, 4); // REGN offset |
171 | 222 | avio_skip(s->pb, 4); // REGN size |
172 | 222 | break; |
173 | 7.16M | } |
174 | 7.16M | } |
175 | | |
176 | 2.91k | if (!info_offset || !start) |
177 | 369 | return AVERROR_INVALIDDATA; |
178 | | |
179 | 2.54k | avio_skip(s->pb, info_offset - avio_tell(s->pb)); |
180 | 2.54k | pos = avio_tell(s->pb); |
181 | 2.54k | if (avio_rl32(s->pb) != MKTAG('I','N','F','O')) |
182 | 273 | return AVERROR_INVALIDDATA; |
183 | 2.54k | } |
184 | | |
185 | 4.89k | size = read32(s); |
186 | 4.89k | if (size < 40) |
187 | 16 | return AVERROR_INVALIDDATA; |
188 | 4.87k | avio_skip(s->pb, 4); // unknown |
189 | 4.87k | h1offset = read32(s); |
190 | 4.87k | if (h1offset > size) |
191 | 12 | return AVERROR_INVALIDDATA; |
192 | 4.86k | avio_skip(s->pb, 12); |
193 | 4.86k | toffset = read32(s) + 16LL; |
194 | 4.86k | if (toffset > size) |
195 | 68 | return AVERROR_INVALIDDATA; |
196 | | |
197 | 4.79k | avio_skip(s->pb, pos + h1offset + 8 - avio_tell(s->pb)); |
198 | 4.79k | codec = avio_r8(s->pb); |
199 | | |
200 | 4.79k | switch (codec) { |
201 | 2.68k | case 0: codec = AV_CODEC_ID_PCM_S8_PLANAR; break; |
202 | 695 | case 1: codec = b->little_endian ? |
203 | 622 | AV_CODEC_ID_PCM_S16LE_PLANAR : |
204 | 695 | AV_CODEC_ID_PCM_S16BE_PLANAR; break; |
205 | 1.38k | case 2: codec = b->little_endian ? |
206 | 894 | AV_CODEC_ID_ADPCM_THP_LE : |
207 | 1.38k | AV_CODEC_ID_ADPCM_THP; break; |
208 | 36 | default: |
209 | 36 | avpriv_request_sample(s, "codec %d", codec); |
210 | 36 | return AVERROR_PATCHWELCOME; |
211 | 4.79k | } |
212 | | |
213 | 4.76k | loop = avio_r8(s->pb); // loop flag |
214 | 4.76k | st->codecpar->codec_id = codec; |
215 | 4.76k | st->codecpar->ch_layout.nb_channels = avio_r8(s->pb); |
216 | 4.76k | if (!st->codecpar->ch_layout.nb_channels) |
217 | 206 | return AVERROR_INVALIDDATA; |
218 | | |
219 | 4.55k | avio_skip(s->pb, 1); // padding |
220 | | |
221 | 4.55k | st->codecpar->sample_rate = bfstm ? read32(s) : read16(s); |
222 | 4.55k | if (st->codecpar->sample_rate <= 0) |
223 | 63 | return AVERROR_INVALIDDATA; |
224 | | |
225 | 4.49k | if (!bfstm) |
226 | 2.40k | avio_skip(s->pb, 2); // padding |
227 | | |
228 | 4.49k | if (loop) { |
229 | 3.39k | if (av_dict_set_int(&s->metadata, "loop_start", |
230 | 3.39k | av_rescale(read32(s), AV_TIME_BASE, |
231 | 3.39k | st->codecpar->sample_rate), |
232 | 3.39k | 0) < 0) |
233 | 0 | return AVERROR(ENOMEM); |
234 | 3.39k | } else { |
235 | 1.09k | avio_skip(s->pb, 4); |
236 | 1.09k | } |
237 | | |
238 | 4.49k | st->start_time = 0; |
239 | 4.49k | st->duration = read32(s); |
240 | 4.49k | avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); |
241 | | |
242 | 4.49k | if (!bfstm) |
243 | 2.40k | start = read32(s); |
244 | 4.49k | b->current_block = 0; |
245 | 4.49k | b->block_count = read32(s); |
246 | 4.49k | if (b->block_count > UINT16_MAX) { |
247 | 58 | av_log(s, AV_LOG_WARNING, "too many blocks: %"PRIu32"\n", b->block_count); |
248 | 58 | return AVERROR_INVALIDDATA; |
249 | 58 | } |
250 | | |
251 | 4.43k | b->block_size = read32(s); |
252 | 4.43k | if (b->block_size > UINT32_MAX / st->codecpar->ch_layout.nb_channels) |
253 | 5 | return AVERROR_INVALIDDATA; |
254 | | |
255 | 4.42k | b->samples_per_block = read32(s); |
256 | 4.42k | b->last_block_used_bytes = read32(s); |
257 | 4.42k | b->last_block_samples = read32(s); |
258 | 4.42k | b->last_block_size = read32(s); |
259 | 4.42k | if (b->last_block_size > UINT32_MAX / st->codecpar->ch_layout.nb_channels) |
260 | 4 | return AVERROR_INVALIDDATA; |
261 | 4.42k | if (b->last_block_used_bytes > b->last_block_size) |
262 | 82 | return AVERROR_INVALIDDATA; |
263 | | |
264 | | |
265 | 4.34k | if (codec == AV_CODEC_ID_ADPCM_THP || codec == AV_CODEC_ID_ADPCM_THP_LE) { |
266 | 1.35k | int ch; |
267 | | |
268 | 1.35k | avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); |
269 | 1.35k | if (!bfstm) |
270 | 782 | toffset = read32(s) + 16LL; |
271 | 575 | else |
272 | 575 | toffset = toffset + read32(s) + st->codecpar->ch_layout.nb_channels * 8 - 8; |
273 | 1.35k | if (toffset > size) |
274 | 81 | return AVERROR_INVALIDDATA; |
275 | | |
276 | 1.27k | if (!bfstm) { |
277 | 749 | avio_skip(s->pb, pos + toffset - avio_tell(s->pb) - 8LL * (st->codecpar->ch_layout.nb_channels + 1)); |
278 | 27.9k | for (ch = 0; ch < st->codecpar->ch_layout.nb_channels; ch++) { |
279 | 27.1k | avio_skip(s->pb, 4); |
280 | 27.1k | b->offsets[ch].channel = ch; |
281 | 27.1k | b->offsets[ch].offset = read32(s); |
282 | 27.1k | } |
283 | | |
284 | 749 | qsort(b->offsets, st->codecpar->ch_layout.nb_channels, sizeof(*b->offsets), sort_offsets); |
285 | 749 | } |
286 | | |
287 | 1.27k | avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); |
288 | | |
289 | 10.3k | for (ch = 0; ch < st->codecpar->ch_layout.nb_channels; ch++) { |
290 | 9.41k | if (!bfstm) |
291 | 8.25k | avio_skip(s->pb, pos + 16LL + b->offsets[ch].offset - avio_tell(s->pb)); |
292 | | |
293 | 9.41k | if (avio_read(s->pb, b->table + ch * 32, 32) != 32) |
294 | 360 | return AVERROR_INVALIDDATA; |
295 | | |
296 | 9.05k | if (bfstm) |
297 | 1.05k | avio_skip(s->pb, 14); |
298 | 9.05k | } |
299 | 1.27k | } |
300 | | |
301 | 3.90k | if (size < (avio_tell(s->pb) - pos)) |
302 | 44 | return AVERROR_INVALIDDATA; |
303 | | |
304 | 3.85k | avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); |
305 | | |
306 | 834k | while (!avio_feof(s->pb)) { |
307 | 833k | chunk = avio_rl32(s->pb); |
308 | 833k | size = read32(s); |
309 | 833k | if (size < 8) |
310 | 115 | return AVERROR_INVALIDDATA; |
311 | 832k | size -= 8; |
312 | 832k | switch (chunk) { |
313 | 2.50k | case MKTAG('S','E','E','K'): |
314 | 3.24k | case MKTAG('A','D','P','C'): |
315 | 3.24k | if (codec != AV_CODEC_ID_ADPCM_THP && |
316 | 2.49k | codec != AV_CODEC_ID_ADPCM_THP_LE) |
317 | 1.31k | goto skip; |
318 | | |
319 | 1.93k | asize = b->block_count * st->codecpar->ch_layout.nb_channels * 4; |
320 | 1.93k | if (size < asize) |
321 | 3 | return AVERROR_INVALIDDATA; |
322 | 1.92k | if (b->adpc) { |
323 | 1.14k | av_log(s, AV_LOG_WARNING, "skipping additional ADPC chunk\n"); |
324 | 1.14k | goto skip; |
325 | 1.14k | } else { |
326 | 784 | b->adpc = av_mallocz(asize); |
327 | 784 | if (!b->adpc) |
328 | 0 | return AVERROR(ENOMEM); |
329 | 784 | if (bfstm && codec != AV_CODEC_ID_ADPCM_THP_LE) { |
330 | | // Big-endian BFSTMs have little-endian SEEK tables |
331 | | // for some strange reason. |
332 | 35 | 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 | 749 | } else { |
338 | 749 | avio_read(s->pb, b->adpc, asize); |
339 | 749 | } |
340 | 784 | avio_skip(s->pb, size - asize); |
341 | 784 | } |
342 | 784 | break; |
343 | 2.77k | case MKTAG('D','A','T','A'): |
344 | 2.77k | if ((start < avio_tell(s->pb)) || |
345 | 2.65k | (!b->adpc && (codec == AV_CODEC_ID_ADPCM_THP || |
346 | 1.97k | codec == AV_CODEC_ID_ADPCM_THP_LE))) |
347 | 119 | return AVERROR_INVALIDDATA; |
348 | 2.65k | avio_skip(s->pb, start - avio_tell(s->pb)); |
349 | | |
350 | 2.65k | if (bfstm && (codec == AV_CODEC_ID_ADPCM_THP || |
351 | 1.23k | codec == AV_CODEC_ID_ADPCM_THP_LE)) |
352 | 326 | avio_skip(s->pb, 24); |
353 | | |
354 | 2.65k | b->data_start = avio_tell(s->pb); |
355 | | |
356 | 2.65k | if (!bfstm && (major != 1 || minor)) |
357 | 1.37k | avpriv_request_sample(s, "Version %d.%d", major, minor); |
358 | | |
359 | 2.65k | return 0; |
360 | 826k | default: |
361 | 826k | av_log(s, AV_LOG_WARNING, "skipping unknown chunk: %X\n", chunk); |
362 | 829k | skip: |
363 | 829k | avio_skip(s->pb, size); |
364 | 832k | } |
365 | 832k | } |
366 | | |
367 | 969 | return AVERROR_EOF; |
368 | 3.85k | } |
369 | | |
370 | | static int read_packet(AVFormatContext *s, AVPacket *pkt) |
371 | 371k | { |
372 | 371k | AVCodecParameters *par = s->streams[0]->codecpar; |
373 | 371k | BRSTMDemuxContext *b = s->priv_data; |
374 | 371k | uint32_t samples, size, skip = 0; |
375 | 371k | int channels = par->ch_layout.nb_channels; |
376 | 371k | int ret, i; |
377 | | |
378 | 371k | if (avio_feof(s->pb)) |
379 | 1.58k | return AVERROR_EOF; |
380 | 369k | b->current_block++; |
381 | 369k | if (b->current_block == b->block_count) { |
382 | 1.07k | size = b->last_block_used_bytes; |
383 | 1.07k | samples = b->last_block_samples; |
384 | 1.07k | skip = b->last_block_size - b->last_block_used_bytes; |
385 | | |
386 | 1.07k | if (samples < size * 14 / 8) { |
387 | 150 | uint32_t adjusted_size = samples / 14 * 8; |
388 | 150 | if (samples % 14) |
389 | 93 | adjusted_size += (samples % 14 + 1) / 2 + 1; |
390 | | |
391 | 150 | skip += size - adjusted_size; |
392 | 150 | size = adjusted_size; |
393 | 150 | } |
394 | 368k | } else if (b->current_block < b->block_count) { |
395 | 367k | size = b->block_size; |
396 | 367k | samples = b->samples_per_block; |
397 | 367k | } else { |
398 | 692 | return AVERROR_EOF; |
399 | 692 | } |
400 | | |
401 | 368k | if (par->codec_id == AV_CODEC_ID_ADPCM_THP || |
402 | 366k | par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { |
403 | 7.93k | uint8_t *dst; |
404 | | |
405 | 7.93k | 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 | 7.93k | if (size > (INT_MAX - 32 - 4) || |
411 | 7.91k | (32 + 4 + size) > (INT_MAX / channels) || |
412 | 7.88k | (32 + 4 + size) * channels > INT_MAX - 8) |
413 | 57 | return AVERROR_INVALIDDATA; |
414 | 7.87k | if ((ret = av_new_packet(pkt, 8 + (32 + 4 + size) * channels)) < 0) |
415 | 18 | return ret; |
416 | 7.85k | dst = pkt->data; |
417 | 7.85k | if (par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { |
418 | 5.28k | bytestream_put_le32(&dst, size * channels); |
419 | 5.28k | bytestream_put_le32(&dst, samples); |
420 | 5.28k | } else { |
421 | 2.57k | bytestream_put_be32(&dst, size * channels); |
422 | 2.57k | bytestream_put_be32(&dst, samples); |
423 | 2.57k | } |
424 | 7.85k | bytestream_put_buffer(&dst, b->table, 32 * channels); |
425 | 7.85k | bytestream_put_buffer(&dst, b->adpc + 4 * channels * |
426 | 7.85k | (b->current_block - 1), 4 * channels); |
427 | | |
428 | 16.2k | for (i = 0; i < channels; i++) { |
429 | 8.81k | ret = ffio_read_size(s->pb, dst, size); |
430 | 8.81k | dst += size; |
431 | 8.81k | avio_skip(s->pb, skip); |
432 | 8.81k | if (ret < 0) { |
433 | 422 | return ret; |
434 | 422 | } |
435 | 8.81k | } |
436 | 7.43k | pkt->duration = samples; |
437 | 360k | } else { |
438 | 360k | size *= channels; |
439 | 360k | ret = av_get_packet(s->pb, pkt, size); |
440 | 360k | } |
441 | | |
442 | 368k | pkt->stream_index = 0; |
443 | | |
444 | 368k | if (ret != size) |
445 | 1.82k | ret = AVERROR_INVALIDDATA; |
446 | | |
447 | 368k | return ret; |
448 | 368k | } |
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 | | }; |