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