1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2017
6 * All rights reserved
7 *
8 * This file is part of GPAC / AC3 reframer filter
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26 #include <gpac/avparse.h>
27 #include <gpac/constants.h>
28 #include <gpac/filters.h>
29
30 #ifndef GPAC_DISABLE_AV_PARSERS
31
32 typedef struct
33 {
34 u64 pos;
35 Double duration;
36 } AC3Idx;
37
38 #define AC3_FRAME_SIZE 1536
39
40 typedef struct
41 {
42 //filter args
43 Double index;
44
45 //only one input pid declared
46 GF_FilterPid *ipid;
47 //only one output pid declared
48 GF_FilterPid *opid;
49
50 GF_BitStream *bs;
51 u64 file_pos, cts;
52 u32 sample_rate, nb_ch;
53 GF_Fraction64 duration;
54 Double start_range;
55 Bool in_seek;
56 u32 timescale;
57
58 GF_AC3Header hdr;
59 u8 *ac3_buffer;
60 u32 ac3_buffer_size, ac3_buffer_alloc, resume_from;
61 u64 byte_offset;
62
63 Bool is_playing;
64 Bool is_file, file_loaded;
65 Bool initial_play_done;
66
67 Bool is_eac3;
68 Bool (*ac3_parser_bs)(GF_BitStream*, GF_AC3Header*, Bool);
69
70 GF_FilterPacket *src_pck;
71
72 AC3Idx *indexes;
73 u32 index_alloc_size, index_size;
74 } GF_AC3DmxCtx;
75
76
77
78
ac3dmx_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)79 GF_Err ac3dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
80 {
81 const GF_PropertyValue *p;
82 GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
83
84 if (is_remove) {
85 ctx->ipid = NULL;
86 gf_filter_pid_remove(ctx->opid);
87 return GF_OK;
88 }
89 if (! gf_filter_pid_check_caps(pid))
90 return GF_NOT_SUPPORTED;
91
92 ctx->ipid = pid;
93 p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
94 if (p) ctx->timescale = p->value.uint;
95
96 ctx->ac3_parser_bs = gf_ac3_parser_bs;
97
98 p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
99 if (p && p->value.uint==GF_CODECID_EAC3) ctx->is_eac3 = GF_TRUE;
100 else {
101 p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
102 if (p && p->value.string && strstr(p->value.string, "eac3")) ctx->is_eac3 = GF_TRUE;
103 else {
104 p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
105 if (p && p->value.string && strstr(p->value.string, "eac3")) ctx->is_eac3 = GF_TRUE;
106 }
107 }
108 if (ctx->is_eac3) {
109 ctx->ac3_parser_bs = gf_eac3_parser_bs;
110 }
111
112 if (ctx->timescale && !ctx->opid) {
113 ctx->opid = gf_filter_pid_new(filter);
114 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
115 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
116 }
117 return GF_OK;
118 }
119
ac3dmx_check_dur(GF_Filter * filter,GF_AC3DmxCtx * ctx)120 static void ac3dmx_check_dur(GF_Filter *filter, GF_AC3DmxCtx *ctx)
121 {
122 FILE *stream;
123 GF_BitStream *bs;
124 GF_AC3Header hdr;
125 u64 duration, cur_dur;
126 s32 sr = -1;
127 const GF_PropertyValue *p;
128 if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
129
130 if (ctx->index<=0) {
131 ctx->file_loaded = GF_TRUE;
132 return;
133 }
134
135 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
136 if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
137 ctx->is_file = GF_FALSE;
138 ctx->file_loaded = GF_TRUE;
139 return;
140 }
141 ctx->is_file = GF_TRUE;
142
143 stream = gf_fopen(p->value.string, "rb");
144 if (!stream) return;
145
146 ctx->index_size = 0;
147
148 bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
149 duration = 0;
150 cur_dur = 0;
151 while ( ctx->ac3_parser_bs(bs, &hdr, GF_FALSE) ) {
152 if ((sr>=0) && (sr != hdr.sample_rate)) {
153 duration *= hdr.sample_rate;
154 duration /= sr;
155
156 cur_dur *= hdr.sample_rate;
157 cur_dur /= sr;
158 }
159 sr = hdr.sample_rate;
160 duration += AC3_FRAME_SIZE;
161 cur_dur += AC3_FRAME_SIZE;
162 if (cur_dur > ctx->index * sr) {
163 if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
164 else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
165 ctx->indexes = gf_realloc(ctx->indexes, sizeof(AC3Idx)*ctx->index_alloc_size);
166 ctx->indexes[ctx->index_size].pos = gf_bs_get_position(bs);
167 ctx->indexes[ctx->index_size].duration = (Double) duration;
168 ctx->indexes[ctx->index_size].duration /= sr;
169 ctx->index_size ++;
170 cur_dur = 0;
171 }
172
173 gf_bs_skip_bytes(bs, hdr.framesize);
174 }
175 gf_bs_del(bs);
176 gf_fclose(stream);
177
178 if (!ctx->duration.num || (ctx->duration.num * sr != duration * ctx->duration.den)) {
179 ctx->duration.num = (s32) duration;
180 ctx->duration.den = sr;
181
182 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
183 }
184
185 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
186 if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
187 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
188 }
189
ac3dmx_check_pid(GF_Filter * filter,GF_AC3DmxCtx * ctx)190 static void ac3dmx_check_pid(GF_Filter *filter, GF_AC3DmxCtx *ctx)
191 {
192 GF_BitStream *bs;
193 u8 *data;
194 u32 size;
195 if (!ctx->opid) {
196 ctx->opid = gf_filter_pid_new(filter);
197 ac3dmx_check_dur(filter, ctx);
198 }
199 if ((ctx->sample_rate == ctx->hdr.sample_rate) && (ctx->nb_ch == ctx->hdr.channels) ) return;
200
201 //copy properties at init or reconfig
202 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
203 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
204 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(AC3_FRAME_SIZE) );
205 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
206
207 if (ctx->duration.num)
208 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
209
210
211 ctx->nb_ch = ctx->hdr.channels;
212 if (!ctx->timescale) {
213 //we change sample rate, change cts
214 if (ctx->cts && (ctx->sample_rate != ctx->hdr.sample_rate)) {
215 ctx->cts *= ctx->hdr.sample_rate;
216 ctx->cts /= ctx->sample_rate;
217 }
218 }
219 ctx->sample_rate = ctx->hdr.sample_rate;
220
221 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->sample_rate));
222 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
223 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
224
225 bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
226 if (ctx->is_eac3) {
227 u32 i;
228 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_EAC3) );
229
230 gf_bs_write_int(bs, ctx->hdr.data_rate, 13);
231 gf_bs_write_int(bs, ctx->hdr.nb_streams-1, 3);
232 for (i=0; i<ctx->hdr.nb_streams; i++) {
233 gf_bs_write_int(bs, ctx->hdr.streams[i].fscod, 2);
234 gf_bs_write_int(bs, ctx->hdr.streams[i].bsid, 5);
235 gf_bs_write_int(bs, 0, 1);
236 //TODO, expose asvc as an option of reframer, the info is not carried in the bitstream
237 gf_bs_write_int(bs, ctx->hdr.streams[i].asvc, 1);
238 gf_bs_write_int(bs, ctx->hdr.streams[i].bsmod, 3);
239 gf_bs_write_int(bs, ctx->hdr.streams[i].acmod, 3);
240 gf_bs_write_int(bs, ctx->hdr.streams[i].lfon, 1);
241 gf_bs_write_int(bs, 0, 3);
242 gf_bs_write_int(bs, ctx->hdr.streams[i].num_dep_sub, 4);
243 if (ctx->hdr.streams[i].num_dep_sub) {
244 gf_bs_write_int(bs, ctx->hdr.streams[i].chan_loc, 9);
245 } else {
246 gf_bs_write_int(bs, 0, 1);
247 }
248 }
249 } else {
250 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_AC3) );
251
252 gf_bs_write_int(bs, ctx->hdr.streams[0].fscod, 2);
253 gf_bs_write_int(bs, ctx->hdr.streams[0].bsid, 5);
254 gf_bs_write_int(bs, ctx->hdr.streams[0].bsmod, 3);
255 gf_bs_write_int(bs, ctx->hdr.streams[0].acmod, 3);
256 gf_bs_write_int(bs, ctx->hdr.streams[0].lfon, 1);
257 gf_bs_write_int(bs, ctx->hdr.streams[0].brcode, 5);
258 gf_bs_write_int(bs, 0, 5);
259 }
260
261 gf_bs_get_content(bs, &data, &size);
262 gf_bs_del(bs);
263 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(data, size) );
264
265 if (ctx->is_file && ctx->index) {
266 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
267 }
268 }
269
ac3dmx_process_event(GF_Filter * filter,const GF_FilterEvent * evt)270 static Bool ac3dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
271 {
272 u32 i;
273 GF_FilterEvent fevt;
274 GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
275
276 switch (evt->base.type) {
277 case GF_FEVT_PLAY:
278 if (!ctx->is_playing) {
279 ctx->is_playing = GF_TRUE;
280 ctx->cts = 0;
281 ctx->ac3_buffer_size = 0;
282 ctx->resume_from = 0;
283 }
284 if (! ctx->is_file) {
285 return GF_FALSE;
286 }
287 ctx->start_range = evt->play.start_range;
288 ctx->in_seek = GF_TRUE;
289 ctx->file_pos = 0;
290 if (ctx->start_range) {
291 for (i=1; i<ctx->index_size; i++) {
292 if (ctx->indexes[i].duration>ctx->start_range) {
293 ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
294 ctx->file_pos = ctx->indexes[i-1].pos;
295 break;
296 }
297 }
298 }
299 if (!ctx->initial_play_done) {
300 ctx->initial_play_done = GF_TRUE;
301 //seek will not change the current source state, don't send a seek
302 if (!ctx->file_pos)
303 return GF_TRUE;
304 }
305 ctx->ac3_buffer_size = 0;
306 ctx->resume_from = 0;
307 //post a seek
308 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
309 fevt.seek.start_offset = ctx->file_pos;
310 gf_filter_pid_send_event(ctx->ipid, &fevt);
311
312 //cancel event
313 return GF_TRUE;
314
315 case GF_FEVT_STOP:
316 //don't cancel event
317 ctx->is_playing = GF_FALSE;
318 return GF_FALSE;
319
320 case GF_FEVT_SET_SPEED:
321 //cancel event
322 return GF_TRUE;
323 default:
324 break;
325 }
326 //by default don't cancel event - to rework once we have downloading in place
327 return GF_FALSE;
328 }
329
ac3dmx_update_cts(GF_AC3DmxCtx * ctx)330 static GFINLINE void ac3dmx_update_cts(GF_AC3DmxCtx *ctx)
331 {
332 if (ctx->timescale) {
333 u64 inc = AC3_FRAME_SIZE;
334 inc *= ctx->timescale;
335 inc /= ctx->sample_rate;
336 ctx->cts += inc;
337 } else {
338 ctx->cts += AC3_FRAME_SIZE;
339 }
340 }
341
ac3dmx_process(GF_Filter * filter)342 GF_Err ac3dmx_process(GF_Filter *filter)
343 {
344 GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
345 GF_FilterPacket *pck, *dst_pck;
346 u8 *output;
347 u8 *start;
348 u32 pck_size, remain, prev_pck_size;
349 u64 cts = GF_FILTER_NO_TS;
350
351 //always reparse duration
352 if (!ctx->duration.num)
353 ac3dmx_check_dur(filter, ctx);
354
355 if (ctx->opid && !ctx->is_playing)
356 return GF_OK;
357
358 pck = gf_filter_pid_get_packet(ctx->ipid);
359 if (!pck) {
360 if (gf_filter_pid_is_eos(ctx->ipid)) {
361 if (!ctx->ac3_buffer_size) {
362 if (ctx->opid)
363 gf_filter_pid_set_eos(ctx->opid);
364 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
365 ctx->src_pck = NULL;
366 return GF_EOS;
367 }
368 } else {
369 return GF_OK;
370 }
371 }
372
373 prev_pck_size = ctx->ac3_buffer_size;
374 if (pck && !ctx->resume_from) {
375 const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
376 if (!pck_size) {
377 gf_filter_pid_drop_packet(ctx->ipid);
378 return GF_OK;
379 }
380
381 if (ctx->byte_offset != GF_FILTER_NO_BO) {
382 u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
383 if (!ctx->ac3_buffer_size) {
384 ctx->byte_offset = byte_offset;
385 } else if (ctx->byte_offset + ctx->ac3_buffer_size != byte_offset) {
386 ctx->byte_offset = GF_FILTER_NO_BO;
387 if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->ac3_buffer_size) ) {
388 ctx->byte_offset = byte_offset - ctx->ac3_buffer_size;
389 }
390 }
391 }
392
393 if (ctx->ac3_buffer_size + pck_size > ctx->ac3_buffer_alloc) {
394 ctx->ac3_buffer_alloc = ctx->ac3_buffer_size + pck_size;
395 ctx->ac3_buffer = gf_realloc(ctx->ac3_buffer, ctx->ac3_buffer_alloc);
396 }
397 memcpy(ctx->ac3_buffer + ctx->ac3_buffer_size, data, pck_size);
398 ctx->ac3_buffer_size += pck_size;
399 }
400
401 //input pid sets some timescale - we flushed pending data , update cts
402 if (ctx->timescale && pck) {
403 cts = gf_filter_pck_get_cts(pck);
404 }
405
406 if (cts == GF_FILTER_NO_TS) {
407 //avoids updating cts
408 prev_pck_size = 0;
409 }
410
411 remain = ctx->ac3_buffer_size;
412 start = ctx->ac3_buffer;
413
414 if (ctx->resume_from) {
415 start += ctx->resume_from - 1;
416 remain -= ctx->resume_from - 1;
417 ctx->resume_from = 0;
418 }
419
420 if (!ctx->bs) {
421 ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
422 } else {
423 gf_bs_reassign_buffer(ctx->bs, start, remain);
424 }
425 while (remain) {
426 u8 *sync;
427 Bool res;
428 u32 sync_pos, bytes_to_drop=0;
429
430
431 res = ctx->ac3_parser_bs(ctx->bs, &ctx->hdr, GF_TRUE);
432
433 sync_pos = (u32) gf_bs_get_position(ctx->bs);
434
435 //startcode not found or not enough bytes, gather more
436 if (!res || (remain < sync_pos + ctx->hdr.framesize))
437 break;
438
439 ac3dmx_check_pid(filter, ctx);
440
441 if (!ctx->is_playing) {
442 ctx->resume_from = 1 + ctx->ac3_buffer_size - remain;
443 return GF_OK;
444 }
445
446 if (sync_pos) {
447 GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[AC3Dmx] %d bytes unrecovered before sync word\n", sync_pos));
448 }
449 sync = start + sync_pos;
450
451 if (ctx->in_seek) {
452 u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->hdr.sample_rate);
453 if (ctx->cts + AC3_FRAME_SIZE >= nb_samples_at_seek) {
454 //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
455 ctx->in_seek = GF_FALSE;
456 }
457 }
458
459 bytes_to_drop = sync_pos + ctx->hdr.framesize;
460 if (ctx->timescale && !prev_pck_size && (cts != GF_FILTER_NO_TS) ) {
461 //trust input CTS if diff is more than one sec
462 if ((cts > ctx->cts + ctx->timescale) || (ctx->cts > cts + ctx->timescale))
463 ctx->cts = cts;
464 cts = GF_FILTER_NO_TS;
465 }
466
467 if (!ctx->in_seek) {
468 dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->hdr.framesize, &output);
469 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
470
471 memcpy(output, sync, ctx->hdr.framesize);
472 gf_filter_pck_set_dts(dst_pck, ctx->cts);
473 gf_filter_pck_set_cts(dst_pck, ctx->cts);
474 gf_filter_pck_set_duration(dst_pck, AC3_FRAME_SIZE);
475 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
476 gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
477
478 if (ctx->byte_offset != GF_FILTER_NO_BO) {
479 gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset + ctx->hdr.framesize);
480 }
481
482 gf_filter_pck_send(dst_pck);
483 }
484 ac3dmx_update_cts(ctx);
485
486 //truncated last frame
487 if (bytes_to_drop>remain) {
488 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ADTSDmx] truncated AC3 frame!\n"));
489 bytes_to_drop=remain;
490 }
491
492 if (!bytes_to_drop) {
493 bytes_to_drop = 1;
494 }
495 start += bytes_to_drop;
496 remain -= bytes_to_drop;
497 gf_bs_reassign_buffer(ctx->bs, start, remain);
498
499 if (prev_pck_size) {
500 if (prev_pck_size > bytes_to_drop) prev_pck_size -= bytes_to_drop;
501 else {
502 prev_pck_size=0;
503 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
504 ctx->src_pck = pck;
505 if (pck)
506 gf_filter_pck_ref_props(&ctx->src_pck);
507 }
508 }
509 if (ctx->byte_offset != GF_FILTER_NO_BO)
510 ctx->byte_offset += bytes_to_drop;
511 }
512
513 if (!pck) {
514 ctx->ac3_buffer_size = 0;
515 return ac3dmx_process(filter);
516 } else {
517 if (remain) {
518 memmove(ctx->ac3_buffer, start, remain);
519 }
520 ctx->ac3_buffer_size = remain;
521 gf_filter_pid_drop_packet(ctx->ipid);
522 }
523 return GF_OK;
524 }
525
ac3dmx_finalize(GF_Filter * filter)526 static void ac3dmx_finalize(GF_Filter *filter)
527 {
528 GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
529 if (ctx->bs) gf_bs_del(ctx->bs);
530 if (ctx->ac3_buffer) gf_free(ctx->ac3_buffer);
531 if (ctx->indexes) gf_free(ctx->indexes);
532 }
533
ac3dmx_probe_data(const u8 * data,u32 size,GF_FilterProbeScore * score)534 static const char *ac3dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
535 {
536 u32 nb_frames=0;
537 u32 pos=0;
538 while (1) {
539 GF_AC3Header ahdr;
540 if (! gf_ac3_parser((u8 *) data, size, &pos, &ahdr, GF_FALSE) )
541 break;
542 u32 fsize = ahdr.framesize;
543 if (pos) nb_frames=0;
544 nb_frames++;
545 if (fsize > size+pos) break;
546 if (nb_frames>4) break;
547 if (size < fsize+pos) break;
548 size -= fsize+pos;
549 data += fsize+pos;
550 }
551 if (nb_frames>2) {
552 *score = GF_FPROBE_SUPPORTED;
553 return "audio/ac3";
554 }
555 return NULL;
556 }
557
558 static const GF_FilterCapability AC3DmxCaps[] =
559 {
560 CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
561 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "ac3|eac3"),
562 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/x-ac3|audio/ac3|audio/x-eac3|audio/eac3"),
563 CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
564 CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AC3),
565 CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_EAC3),
566 CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
567 {0},
568 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
569 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AC3),
570 CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EAC3),
571 CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
572 };
573
574 #define OFFS(_n) #_n, offsetof(GF_AC3DmxCtx, _n)
575 static const GF_FilterArgs AC3DmxArgs[] =
576 {
577 { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
578 {0}
579 };
580
581
582 GF_FilterRegister AC3DmxRegister = {
583 .name = "rfac3",
584 GF_FS_SET_DESCRIPTION("AC3 reframer")
585 GF_FS_SET_HELP("This filter parses AC3 and E-AC3 files/data and outputs corresponding audio PID and frames.")
586 .private_size = sizeof(GF_AC3DmxCtx),
587 .args = AC3DmxArgs,
588 .finalize = ac3dmx_finalize,
589 SETCAPS(AC3DmxCaps),
590 .configure_pid = ac3dmx_configure_pid,
591 .process = ac3dmx_process,
592 .probe_data = ac3dmx_probe_data,
593 .process_event = ac3dmx_process_event
594 };
595
596
ac3dmx_register(GF_FilterSession * session)597 const GF_FilterRegister *ac3dmx_register(GF_FilterSession *session)
598 {
599 return &AC3DmxRegister;
600 }
601
602 #else
603
ac3dmx_register(GF_FilterSession * session)604 const GF_FilterRegister *ac3dmx_register(GF_FilterSession *session)
605 {
606 return NULL;
607 }
608 #endif // GPAC_DISABLE_AV_PARSERS
609