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