FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/argo_asf.c
Date: 2023-10-02 11:06:47
Exec Total Coverage
Lines: 151 206 73.3%
Functions: 14 15 93.3%
Branches: 49 100 49.0%

Line Branch Exec Source
1 /*
2 * Argonaut Games ASF (de)muxer
3 *
4 * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "config_components.h"
24
25 #include "libavutil/avstring.h"
26 #include "avformat.h"
27 #include "internal.h"
28 #include "mux.h"
29 #include "libavutil/channel_layout.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/avassert.h"
32 #include "libavutil/opt.h"
33 #include "argo_asf.h"
34
35 /* Maximum number of blocks to read at once. */
36 #define ASF_NB_BLOCKS 32
37
38 typedef struct ArgoASFDemuxContext {
39 ArgoASFFileHeader fhdr;
40 ArgoASFChunkHeader ckhdr;
41 uint32_t blocks_read;
42 } ArgoASFDemuxContext;
43
44 typedef struct ArgoASFMuxContext {
45 const AVClass *class;
46 int version_major;
47 int version_minor;
48 const char *name;
49 int64_t nb_blocks;
50 } ArgoASFMuxContext;
51
52 6919 void ff_argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf)
53 {
54 6919 hdr->magic = AV_RL32(buf + 0);
55 6919 hdr->version_major = AV_RL16(buf + 4);
56 6919 hdr->version_minor = AV_RL16(buf + 6);
57 6919 hdr->num_chunks = AV_RL32(buf + 8);
58 6919 hdr->chunk_offset = AV_RL32(buf + 12);
59 6919 memcpy(hdr->name, buf + 16, ASF_NAME_SIZE);
60 6919 hdr->name[ASF_NAME_SIZE] = '\0';
61 6919 }
62
63 3 int ff_argo_asf_validate_file_header(AVFormatContext *s, const ArgoASFFileHeader *hdr)
64 {
65
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (hdr->magic != ASF_TAG || hdr->num_chunks == 0)
66 return AVERROR_INVALIDDATA;
67
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (hdr->chunk_offset < ASF_FILE_HEADER_SIZE)
69 return AVERROR_INVALIDDATA;
70
71 3 return 0;
72 }
73
74 3 void ff_argo_asf_parse_chunk_header(ArgoASFChunkHeader *hdr, const uint8_t *buf)
75 {
76 3 hdr->num_blocks = AV_RL32(buf + 0);
77 3 hdr->num_samples = AV_RL32(buf + 4);
78 3 hdr->unk1 = AV_RL32(buf + 8);
79 3 hdr->sample_rate = AV_RL16(buf + 12);
80 3 hdr->unk2 = AV_RL16(buf + 14);
81 3 hdr->flags = AV_RL32(buf + 16);
82 3 }
83
84 3 int ff_argo_asf_fill_stream(AVFormatContext *s, AVStream *st, const ArgoASFFileHeader *fhdr,
85 const ArgoASFChunkHeader *ckhdr)
86 {
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ckhdr->num_samples != ASF_SAMPLE_COUNT) {
88 av_log(s, AV_LOG_ERROR, "Invalid sample count. Got %u, expected %d\n",
89 ckhdr->num_samples, ASF_SAMPLE_COUNT);
90 return AVERROR_INVALIDDATA;
91 }
92
93
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if ((ckhdr->flags & ASF_CF_ALWAYS1) != ASF_CF_ALWAYS1 || (ckhdr->flags & ASF_CF_ALWAYS0) != 0) {
94 avpriv_request_sample(s, "Nonstandard flags (0x%08X)", ckhdr->flags);
95 return AVERROR_PATCHWELCOME;
96 }
97
98 3 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
99 3 st->codecpar->codec_id = AV_CODEC_ID_ADPCM_ARGO;
100 3 st->codecpar->format = AV_SAMPLE_FMT_S16P;
101
102
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (ckhdr->flags & ASF_CF_STEREO) {
103 2 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
104 } else {
105 1 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
106 }
107
108 /* v1.1 files (FX Fighter) are all marked as 44100, but are actually 22050. */
109
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 if (fhdr->version_major == 1 && fhdr->version_minor == 1)
110 1 st->codecpar->sample_rate = 22050;
111 else
112 2 st->codecpar->sample_rate = ckhdr->sample_rate;
113
114 3 st->codecpar->bits_per_coded_sample = 4;
115
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!(ckhdr->flags & ASF_CF_BITS_PER_SAMPLE)) {
117 /* The header allows for these, but I've never seen any files with them. */
118 avpriv_request_sample(s, "Non 16-bit samples");
119 return AVERROR_PATCHWELCOME;
120 }
121
122 /*
123 * (nchannel control bytes) + ((bytes_per_channel) * nchannel)
124 * For mono, this is 17. For stereo, this is 34.
125 */
126 3 st->codecpar->block_align = st->codecpar->ch_layout.nb_channels +
127 3 (ckhdr->num_samples / 2) *
128 st->codecpar->ch_layout.nb_channels;
129
130 3 st->codecpar->bit_rate = st->codecpar->ch_layout.nb_channels *
131 3 st->codecpar->sample_rate *
132 3 st->codecpar->bits_per_coded_sample;
133
134 3 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
135 3 st->start_time = 0;
136
137
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (fhdr->num_chunks == 1) {
138 3 st->duration = ckhdr->num_blocks * ckhdr->num_samples;
139 3 st->nb_frames = ckhdr->num_blocks;
140 }
141
142 3 return 0;
143 }
144
145 #if CONFIG_ARGO_ASF_DEMUXER
146 /*
147 * Known versions:
148 * 1.1: https://samples.ffmpeg.org/game-formats/brender/part2.zip
149 * FX Fighter
150 * 1.2: Croc! Legend of the Gobbos
151 * 2.1: Croc 2
152 * The Emperor's New Groove
153 * Disney's Aladdin in Nasira's Revenge
154 */
155 3 static int argo_asf_is_known_version(const ArgoASFFileHeader *hdr)
156 {
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 return (hdr->version_major == 1 && hdr->version_minor == 1) ||
158
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 (hdr->version_major == 1 && hdr->version_minor == 2) ||
159
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 (hdr->version_major == 2 && hdr->version_minor == 1);
160 }
161
162 6916 static int argo_asf_probe(const AVProbeData *p)
163 {
164 ArgoASFFileHeader hdr;
165
166 av_assert0(AVPROBE_PADDING_SIZE >= ASF_FILE_HEADER_SIZE);
167
168 6916 ff_argo_asf_parse_file_header(&hdr, p->buf);
169
170
2/2
✓ Branch 0 taken 6913 times.
✓ Branch 1 taken 3 times.
6916 if (hdr.magic != ASF_TAG)
171 6913 return 0;
172
173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!argo_asf_is_known_version(&hdr))
174 return AVPROBE_SCORE_EXTENSION / 2;
175
176 3 return AVPROBE_SCORE_EXTENSION + 1;
177 }
178
179 3 static int argo_asf_read_header(AVFormatContext *s)
180 {
181 int64_t ret;
182 3 AVIOContext *pb = s->pb;
183 AVStream *st;
184 3 ArgoASFDemuxContext *asf = s->priv_data;
185 uint8_t buf[ASF_MIN_BUFFER_SIZE];
186
187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!(st = avformat_new_stream(s, NULL)))
188 return AVERROR(ENOMEM);
189
190
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((ret = avio_read(pb, buf, ASF_FILE_HEADER_SIZE)) < 0)
191 return ret;
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (ret != ASF_FILE_HEADER_SIZE)
193 return AVERROR(EIO);
194
195 3 ff_argo_asf_parse_file_header(&asf->fhdr, buf);
196
197
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((ret = ff_argo_asf_validate_file_header(s, &asf->fhdr)) < 0)
198 return ret;
199
200 /* This should only be 1 in ASF files. >1 is fine if in BRP. */
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (asf->fhdr.num_chunks != 1)
202 return AVERROR_INVALIDDATA;
203
204
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((ret = avio_skip(pb, asf->fhdr.chunk_offset - ASF_FILE_HEADER_SIZE)) < 0)
205 return ret;
206
207
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((ret = avio_read(pb, buf, ASF_CHUNK_HEADER_SIZE)) < 0)
208 return ret;
209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (ret != ASF_CHUNK_HEADER_SIZE)
210 return AVERROR(EIO);
211
212 3 ff_argo_asf_parse_chunk_header(&asf->ckhdr, buf);
213
214 3 av_dict_set(&s->metadata, "title", asf->fhdr.name, 0);
215
216 3 return ff_argo_asf_fill_stream(s, st, &asf->fhdr, &asf->ckhdr);
217 }
218
219 949 static int argo_asf_read_packet(AVFormatContext *s, AVPacket *pkt)
220 {
221 949 ArgoASFDemuxContext *asf = s->priv_data;
222
223 949 AVStream *st = s->streams[0];
224 949 AVIOContext *pb = s->pb;
225 int ret;
226
227
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 946 times.
949 if (asf->blocks_read >= asf->ckhdr.num_blocks)
228 3 return AVERROR_EOF;
229
230 946 ret = av_get_packet(pb, pkt, st->codecpar->block_align *
231 946 FFMIN(ASF_NB_BLOCKS, asf->ckhdr.num_blocks - asf->blocks_read));
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 946 times.
946 if (ret < 0)
233 return ret;
234
235 /* Something real screwy is going on. */
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 946 times.
946 if (ret % st->codecpar->block_align != 0)
237 return AVERROR_INVALIDDATA;
238
239
240 946 pkt->stream_index = st->index;
241 946 pkt->duration = asf->ckhdr.num_samples * (ret / st->codecpar->block_align);
242 946 pkt->pts = asf->blocks_read * asf->ckhdr.num_samples;
243 946 asf->blocks_read += (ret / st->codecpar->block_align);
244
245 946 pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
246 946 return 0;
247 }
248
249 static int argo_asf_seek(AVFormatContext *s, int stream_index,
250 int64_t pts, int flags)
251 {
252 ArgoASFDemuxContext *asf = s->priv_data;
253 AVStream *st = s->streams[stream_index];
254 int64_t offset;
255 uint32_t block = pts / asf->ckhdr.num_samples;
256
257 if (block >= asf->ckhdr.num_blocks)
258 return -1;
259
260 offset = asf->fhdr.chunk_offset + ASF_CHUNK_HEADER_SIZE +
261 (block * st->codecpar->block_align);
262
263 if ((offset = avio_seek(s->pb, offset, SEEK_SET)) < 0)
264 return offset;
265
266 asf->blocks_read = block;
267 return 0;
268 }
269
270 /*
271 * Not actually sure what ASF stands for.
272 * - Argonaut Sound File?
273 * - Audio Stream File?
274 */
275 const AVInputFormat ff_argo_asf_demuxer = {
276 .name = "argo_asf",
277 .long_name = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"),
278 .priv_data_size = sizeof(ArgoASFDemuxContext),
279 .read_probe = argo_asf_probe,
280 .read_header = argo_asf_read_header,
281 .read_packet = argo_asf_read_packet,
282 .read_seek = argo_asf_seek,
283 };
284 #endif
285
286 #if CONFIG_ARGO_ASF_MUXER
287 1 static int argo_asf_write_init(AVFormatContext *s)
288 {
289 1 ArgoASFMuxContext *ctx = s->priv_data;
290 const AVCodecParameters *par;
291
292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (s->nb_streams != 1) {
293 av_log(s, AV_LOG_ERROR, "ASF files have exactly one stream\n");
294 return AVERROR(EINVAL);
295 }
296
297 1 par = s->streams[0]->codecpar;
298
299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (par->codec_id != AV_CODEC_ID_ADPCM_ARGO) {
300 av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
301 avcodec_get_name(par->codec_id));
302 return AVERROR(EINVAL);
303 }
304
305
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (ctx->version_major == 1 && ctx->version_minor == 1 && par->sample_rate != 22050) {
306 av_log(s, AV_LOG_ERROR, "ASF v1.1 files only support a sample rate of 22050\n");
307 return AVERROR(EINVAL);
308 }
309
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (par->ch_layout.nb_channels > 2) {
311 av_log(s, AV_LOG_ERROR, "ASF files only support up to 2 channels\n");
312 return AVERROR(EINVAL);
313 }
314
315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (par->block_align != 17 * par->ch_layout.nb_channels)
316 return AVERROR(EINVAL);
317
318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (par->sample_rate > UINT16_MAX) {
319 av_log(s, AV_LOG_ERROR, "Sample rate too large\n");
320 return AVERROR(EINVAL);
321 }
322
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
324 av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n");
325 return AVERROR(EINVAL);
326 }
327
328 1 return 0;
329 }
330
331 1 static void argo_asf_write_file_header(const ArgoASFFileHeader *fhdr, AVIOContext *pb)
332 {
333 1 avio_wl32( pb, fhdr->magic);
334 1 avio_wl16( pb, fhdr->version_major);
335 1 avio_wl16( pb, fhdr->version_minor);
336 1 avio_wl32( pb, fhdr->num_chunks);
337 1 avio_wl32( pb, fhdr->chunk_offset);
338 1 avio_write(pb, fhdr->name, ASF_NAME_SIZE);
339 1 }
340
341 1 static void argo_asf_write_chunk_header(const ArgoASFChunkHeader *ckhdr, AVIOContext *pb)
342 {
343 1 avio_wl32(pb, ckhdr->num_blocks);
344 1 avio_wl32(pb, ckhdr->num_samples);
345 1 avio_wl32(pb, ckhdr->unk1);
346 1 avio_wl16(pb, ckhdr->sample_rate);
347 1 avio_wl16(pb, ckhdr->unk2);
348 1 avio_wl32(pb, ckhdr->flags);
349 1 }
350
351 1 static int argo_asf_write_header(AVFormatContext *s)
352 {
353 1 const AVCodecParameters *par = s->streams[0]->codecpar;
354 1 ArgoASFMuxContext *ctx = s->priv_data;
355 ArgoASFChunkHeader chdr;
356 1 ArgoASFFileHeader fhdr = {
357 .magic = ASF_TAG,
358 1 .version_major = (uint16_t)ctx->version_major,
359 1 .version_minor = (uint16_t)ctx->version_minor,
360 .num_chunks = 1,
361 .chunk_offset = ASF_FILE_HEADER_SIZE
362 };
363 AVDictionaryEntry *t;
364 const char *name, *end;
365 size_t len;
366
367 /*
368 * If the user specified a name, use it as is. Otherwise,
369 * try to use metadata (if present), then fall back to the
370 * filename (minus extension).
371 */
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ctx->name) {
373 name = ctx->name;
374 len = strlen(ctx->name);
375
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 } else if ((t = av_dict_get(s->metadata, "title", NULL, 0))) {
376 name = t->value;
377 len = strlen(t->value);
378
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 } else if (!(end = strrchr((name = av_basename(s->url)), '.'))) {
379 len = strlen(name);
380 } else {
381 1 len = end - name;
382 }
383 1 memcpy(fhdr.name, name, FFMIN(len, ASF_NAME_SIZE));
384
385 1 chdr.num_blocks = 0;
386 1 chdr.num_samples = ASF_SAMPLE_COUNT;
387 1 chdr.unk1 = 0;
388
389
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (ctx->version_major == 1 && ctx->version_minor == 1)
390 chdr.sample_rate = 44100;
391 else
392 1 chdr.sample_rate = par->sample_rate;
393
394 1 chdr.unk2 = ~0;
395 1 chdr.flags = ASF_CF_BITS_PER_SAMPLE | ASF_CF_ALWAYS1;
396
397
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (par->ch_layout.nb_channels == 2)
398 1 chdr.flags |= ASF_CF_STEREO;
399
400 1 argo_asf_write_file_header(&fhdr, s->pb);
401 1 argo_asf_write_chunk_header(&chdr, s->pb);
402 1 return 0;
403 }
404
405 8269 static int argo_asf_write_packet(AVFormatContext *s, AVPacket *pkt)
406 {
407 8269 ArgoASFMuxContext *ctx = s->priv_data;
408 8269 AVCodecParameters *par = s->streams[0]->codecpar;
409 8269 int nb_blocks = pkt->size / par->block_align;
410
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8269 times.
8269 if (pkt->size % par->block_align != 0)
412 return AVERROR_INVALIDDATA;
413
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8269 times.
8269 if (ctx->nb_blocks + nb_blocks > UINT32_MAX)
415 return AVERROR_INVALIDDATA;
416
417 8269 avio_write(s->pb, pkt->data, pkt->size);
418
419 8269 ctx->nb_blocks += nb_blocks;
420 8269 return 0;
421 }
422
423 1 static int argo_asf_write_trailer(AVFormatContext *s)
424 {
425 1 ArgoASFMuxContext *ctx = s->priv_data;
426 int64_t ret;
427
428
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = avio_seek(s->pb, ASF_FILE_HEADER_SIZE, SEEK_SET)) < 0)
429 return ret;
430
431 1 avio_wl32(s->pb, (uint32_t)ctx->nb_blocks);
432 1 return 0;
433 }
434
435 static const AVOption argo_asf_options[] = {
436 {
437 .name = "version_major",
438 .help = "override file major version",
439 .offset = offsetof(ArgoASFMuxContext, version_major),
440 .type = AV_OPT_TYPE_INT,
441 .default_val = {.i64 = 2},
442 .min = 0,
443 .max = UINT16_MAX,
444 .flags = AV_OPT_FLAG_ENCODING_PARAM
445 },
446 {
447 .name = "version_minor",
448 .help = "override file minor version",
449 .offset = offsetof(ArgoASFMuxContext, version_minor),
450 .type = AV_OPT_TYPE_INT,
451 .default_val = {.i64 = 1},
452 .min = 0,
453 .max = UINT16_MAX,
454 .flags = AV_OPT_FLAG_ENCODING_PARAM
455 },
456 {
457 .name = "name",
458 .help = "embedded file name (max 8 characters)",
459 .offset = offsetof(ArgoASFMuxContext, name),
460 .type = AV_OPT_TYPE_STRING,
461 .default_val = {.str = NULL},
462 .flags = AV_OPT_FLAG_ENCODING_PARAM
463 },
464 { NULL }
465 };
466
467 static const AVClass argo_asf_muxer_class = {
468 .class_name = "argo_asf_muxer",
469 .item_name = av_default_item_name,
470 .option = argo_asf_options,
471 .version = LIBAVUTIL_VERSION_INT
472 };
473
474 const FFOutputFormat ff_argo_asf_muxer = {
475 .p.name = "argo_asf",
476 .p.long_name = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"),
477 /*
478 * NB: Can't do this as it conflicts with the actual ASF format.
479 * .p.extensions = "asf",
480 */
481 .p.audio_codec = AV_CODEC_ID_ADPCM_ARGO,
482 .p.video_codec = AV_CODEC_ID_NONE,
483 .p.priv_class = &argo_asf_muxer_class,
484 .init = argo_asf_write_init,
485 .write_header = argo_asf_write_header,
486 .write_packet = argo_asf_write_packet,
487 .write_trailer = argo_asf_write_trailer,
488 .priv_data_size = sizeof(ArgoASFMuxContext)
489 };
490 #endif
491