Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / AAC ADTS 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 : enum
33 : {
34 : AAC_SIGNAL_NONE=0,
35 : AAC_SIGNAL_IMPLICIT,
36 : AAC_SIGNAL_EXPLICIT
37 : };
38 :
39 : typedef struct
40 : {
41 : Bool is_mp2, no_crc;
42 : u32 profile, sr_idx, nb_ch, frame_size, hdr_size;
43 : } ADTSHeader;
44 :
45 : typedef struct
46 : {
47 : u64 pos;
48 : Double duration;
49 : } ADTSIdx;
50 :
51 : typedef struct
52 : {
53 : //filter args
54 : u32 frame_size;
55 : Double index;
56 : u32 sbr;
57 : u32 ps;
58 : // Bool mpeg4;
59 : Bool ovsbr;
60 : Bool expart;
61 : s32 aacchcfg;
62 :
63 : //only one input pid declared
64 : GF_FilterPid *ipid;
65 : //output pid for audio
66 : GF_FilterPid *opid;
67 :
68 : //video pid for cover art
69 : GF_FilterPid *vpid;
70 :
71 : GF_BitStream *bs;
72 : u64 file_pos, cts;
73 : u32 sr_idx, nb_ch, is_mp2, profile;
74 : GF_Fraction64 duration;
75 : Double start_range;
76 : Bool in_seek;
77 : u32 timescale;
78 :
79 : ADTSHeader hdr;
80 : u32 dts_inc;
81 :
82 : Bool is_playing;
83 : Bool is_file, file_loaded;
84 : Bool initial_play_done;
85 :
86 : GF_FilterPacket *src_pck;
87 :
88 : ADTSIdx *indexes;
89 : u32 index_alloc_size, index_size;
90 :
91 : u8 *adts_buffer;
92 : u32 adts_buffer_size, adts_buffer_alloc, resume_from;
93 : u64 byte_offset;
94 :
95 : u32 tag_size;
96 : u8 *id3_buffer;
97 : u32 id3_buffer_size, id3_buffer_alloc;
98 : u32 nb_frames;
99 :
100 : GF_M4ADecSpecInfo acfg;
101 : u32 bitrate;
102 : } GF_ADTSDmxCtx;
103 :
104 :
105 29200 : static Bool adts_dmx_sync_frame_bs(GF_BitStream *bs, ADTSHeader *hdr)
106 : {
107 : u32 val;
108 : u64 pos;
109 :
110 8246856 : while (gf_bs_available(bs)>7) {
111 : u32 nb_blocks_per_frame;
112 8215565 : val = gf_bs_read_u8(bs);
113 8215565 : if (val!=0xFF) continue;
114 206670 : val = gf_bs_read_int(bs, 4);
115 206670 : if (val != 0x0F) {
116 106506 : gf_bs_read_int(bs, 4);
117 106506 : continue;
118 : }
119 100164 : hdr->is_mp2 = (Bool)gf_bs_read_int(bs, 1);
120 100164 : gf_bs_read_int(bs, 2);
121 100164 : hdr->no_crc = (Bool)gf_bs_read_int(bs, 1);
122 100164 : pos = gf_bs_get_position(bs) - 2;
123 :
124 100164 : hdr->profile = 1 + gf_bs_read_int(bs, 2);
125 100164 : hdr->sr_idx = gf_bs_read_int(bs, 4);
126 100164 : gf_bs_read_int(bs, 1);
127 100164 : hdr->nb_ch = gf_bs_read_int(bs, 3);
128 : //value 1->6 match channel number, value 7 is 7.1
129 100164 : if (hdr->nb_ch==7)
130 60801 : hdr->nb_ch = 8;
131 :
132 100164 : gf_bs_read_int(bs, 4);
133 100164 : hdr->frame_size = gf_bs_read_int(bs, 13);
134 100164 : gf_bs_read_int(bs, 11);
135 :
136 100164 : nb_blocks_per_frame = gf_bs_read_int(bs, 2);
137 100164 : hdr->hdr_size = 7;
138 :
139 100164 : if ((!hdr->nb_ch && (nb_blocks_per_frame<2)) || (nb_blocks_per_frame>2)) {
140 63574 : hdr->frame_size = 0;
141 63574 : gf_bs_seek(bs, pos+1);
142 63574 : continue;
143 : }
144 :
145 36590 : if (!hdr->no_crc) {
146 : u32 skip;
147 2178 : if (!nb_blocks_per_frame) {
148 : skip = 2;
149 : } else {
150 1735 : skip = 2 + 2*nb_blocks_per_frame; //and we have 2 bytes per raw_data_block
151 : }
152 2178 : hdr->hdr_size += skip;
153 2178 : gf_bs_skip_bytes(bs, skip);
154 : }
155 :
156 36590 : if (!GF_M4ASampleRates[hdr->sr_idx] || (hdr->frame_size < hdr->hdr_size)) {
157 8771 : hdr->frame_size = 0;
158 8771 : gf_bs_seek(bs, pos+1);
159 8771 : continue;
160 : }
161 27819 : hdr->frame_size -= hdr->hdr_size;
162 :
163 27819 : if (gf_bs_available(bs) == hdr->frame_size) {
164 : return GF_TRUE;
165 : }
166 27773 : if (gf_bs_available(bs) < hdr->frame_size) {
167 : break;
168 : }
169 :
170 26904 : gf_bs_skip_bytes(bs, hdr->frame_size);
171 26904 : val = gf_bs_read_u8(bs);
172 26904 : if (val!=0xFF) {
173 709 : hdr->frame_size = 0;
174 709 : gf_bs_seek(bs, pos+1);
175 709 : continue;
176 : }
177 26195 : val = gf_bs_read_int(bs, 4);
178 26195 : if (val!=0x0F) {
179 1 : hdr->frame_size = 0;
180 1 : gf_bs_read_int(bs, 4);
181 1 : gf_bs_seek(bs, pos+1);
182 1 : continue;
183 : }
184 26194 : gf_bs_seek(bs, pos+hdr->hdr_size);
185 26194 : return GF_TRUE;
186 : }
187 : return GF_FALSE;
188 : }
189 :
190 : void id3dmx_flush(GF_Filter *filter, u8 *id3_buf, u32 id3_buf_size, GF_FilterPid *audio_pid, GF_FilterPid **video_pid_p);
191 :
192 :
193 187 : GF_Err adts_dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
194 : {
195 : const GF_PropertyValue *p;
196 187 : GF_ADTSDmxCtx *ctx = gf_filter_get_udta(filter);
197 :
198 187 : if (is_remove) {
199 0 : ctx->ipid = NULL;
200 0 : if (ctx->opid) {
201 0 : gf_filter_pid_remove(ctx->opid);
202 0 : ctx->opid = NULL;
203 : }
204 : return GF_OK;
205 : }
206 187 : if (! gf_filter_pid_check_caps(pid))
207 : return GF_NOT_SUPPORTED;
208 :
209 187 : ctx->ipid = pid;
210 187 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
211 187 : if (p) ctx->timescale = p->value.uint;
212 :
213 187 : if (ctx->timescale && !ctx->opid) {
214 12 : ctx->opid = gf_filter_pid_new(filter);
215 12 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
216 12 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
217 : //we don't update copy props on output for now - if we decide we need it, we will need to also force resengin the decoder config
218 : }
219 :
220 : return GF_OK;
221 : }
222 :
223 11434 : static void adts_dmx_check_dur(GF_Filter *filter, GF_ADTSDmxCtx *ctx)
224 : {
225 : FILE *stream;
226 : GF_BitStream *bs;
227 : ADTSHeader hdr;
228 : u64 duration, cur_dur, rate;
229 : s32 sr_idx = -1;
230 : const GF_PropertyValue *p;
231 22819 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
232 :
233 137 : if (ctx->index<=0) {
234 82 : ctx->file_loaded = GF_TRUE;
235 : return;
236 : }
237 :
238 55 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
239 55 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
240 6 : ctx->is_file = GF_FALSE;
241 6 : ctx->file_loaded = GF_TRUE;
242 : return;
243 : }
244 49 : ctx->is_file = GF_TRUE;
245 :
246 49 : stream = gf_fopen(p->value.string, "rb");
247 49 : if (!stream) return;
248 :
249 49 : ctx->index_size = 0;
250 :
251 49 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
252 : duration = 0;
253 : cur_dur = 0;
254 25265 : while (adts_dmx_sync_frame_bs(bs, &hdr)) {
255 25216 : if ((sr_idx>=0) && (sr_idx != hdr.sr_idx)) {
256 0 : duration *= GF_M4ASampleRates[hdr.sr_idx];
257 0 : duration /= GF_M4ASampleRates[sr_idx];
258 :
259 0 : cur_dur *= GF_M4ASampleRates[hdr.sr_idx];
260 0 : cur_dur /= GF_M4ASampleRates[sr_idx];
261 : }
262 25216 : sr_idx = hdr.sr_idx;
263 25216 : duration += ctx->frame_size;
264 25216 : cur_dur += ctx->frame_size;
265 25216 : if (cur_dur > ctx->index * GF_M4ASampleRates[sr_idx]) {
266 556 : if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
267 509 : else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
268 556 : ctx->indexes = gf_realloc(ctx->indexes, sizeof(ADTSIdx)*ctx->index_alloc_size);
269 556 : ctx->indexes[ctx->index_size].pos = gf_bs_get_position(bs) - hdr.hdr_size;
270 556 : ctx->indexes[ctx->index_size].duration = (Double) duration;
271 556 : ctx->indexes[ctx->index_size].duration /= GF_M4ASampleRates[sr_idx];
272 556 : ctx->index_size ++;
273 : cur_dur = 0;
274 : }
275 :
276 25216 : gf_bs_skip_bytes(bs, hdr.frame_size);
277 : }
278 49 : rate = gf_bs_get_position(bs);
279 49 : gf_bs_del(bs);
280 49 : gf_fclose(stream);
281 :
282 49 : if (sr_idx>=0) {
283 49 : if (!ctx->duration.num || (ctx->duration.num * GF_M4ASampleRates[sr_idx] != duration * ctx->duration.den)) {
284 49 : ctx->duration.num = (s32) duration;
285 49 : ctx->duration.den = GF_M4ASampleRates[sr_idx];
286 :
287 49 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
288 :
289 49 : if (duration && !gf_sys_is_test_mode() ) {
290 0 : rate *= 8 * ctx->duration.den;
291 0 : rate /= ctx->duration.num;
292 0 : ctx->bitrate = (u32) rate;
293 : }
294 : }
295 : }
296 :
297 49 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
298 49 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
299 49 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
300 : }
301 :
302 83493 : static void adts_dmx_check_pid(GF_Filter *filter, GF_ADTSDmxCtx *ctx)
303 : {
304 : GF_BitStream *dsi;
305 : Bool use_implicit=GF_FALSE;
306 : u8 *dsi_b;
307 : u32 i, sbr_sr_idx, dsi_s, sr, sbr_sr, codecid, timescale=0;
308 :
309 83493 : if (!ctx->opid) {
310 137 : ctx->opid = gf_filter_pid_new(filter);
311 137 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
312 137 : adts_dmx_check_dur(filter, ctx);
313 : }
314 :
315 83493 : if ((ctx->sr_idx == ctx->hdr.sr_idx) && (ctx->nb_ch == ctx->hdr.nb_ch)
316 166688 : && (ctx->is_mp2 == ctx->hdr.is_mp2) && (ctx->profile == ctx->hdr.profile) ) return;
317 :
318 : //copy properties at init or reconfig
319 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
320 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT( GF_CODECID_AAC_MPEG4));
321 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->frame_size) );
322 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
323 149 : if (ctx->is_file && ctx->index) {
324 49 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
325 : }
326 :
327 149 : if (ctx->duration.num)
328 49 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
329 :
330 :
331 149 : ctx->is_mp2 = ctx->hdr.is_mp2;
332 149 : ctx->nb_ch = ctx->hdr.nb_ch;
333 149 : ctx->profile = ctx->hdr.profile;
334 :
335 149 : sr = GF_M4ASampleRates[ctx->hdr.sr_idx];
336 149 : if (!ctx->timescale) {
337 : //we change sample rate, change cts
338 137 : if (ctx->cts && (ctx->sr_idx != ctx->hdr.sr_idx)) {
339 0 : ctx->cts *= sr;
340 0 : ctx->cts /= GF_M4ASampleRates[ctx->sr_idx];
341 : }
342 : }
343 149 : ctx->sr_idx = ctx->hdr.sr_idx;
344 :
345 : /*keep MPEG-2 AAC codecid even for HE-SBR (that's correct according to latest MPEG-4 audio spec)*/
346 149 : codecid = ctx->hdr.is_mp2 ? ctx->hdr.profile+GF_CODECID_AAC_MPEG2_MP-1 : GF_CODECID_AAC_MPEG4;
347 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(codecid) );
348 :
349 : //force explicit SBR if explicit PS
350 149 : if (ctx->ps==AAC_SIGNAL_EXPLICIT) {
351 3 : ctx->sbr = AAC_SIGNAL_EXPLICIT;
352 : }
353 : /*no provision for explicit indication of MPEG-2 AAC through MPEG-4 PLs, so force implicit*/
354 149 : if (ctx->hdr.is_mp2) {
355 0 : if (ctx->sbr == AAC_SIGNAL_EXPLICIT) ctx->sbr = AAC_SIGNAL_IMPLICIT;
356 0 : if (ctx->ps == AAC_SIGNAL_EXPLICIT) ctx->ps = AAC_SIGNAL_IMPLICIT;
357 : }
358 :
359 149 : dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
360 149 : ctx->dts_inc = ctx->frame_size;
361 :
362 149 : if (!ctx->ovsbr) {
363 : sbr_sr = 0;
364 : sbr_sr_idx = 0;
365 132 : for (i=0; i<16; i++) {
366 281 : if (GF_M4ASampleRates[i] == (u32) 2*sr) {
367 : sbr_sr_idx = i;
368 : sbr_sr = 2*sr;
369 : break;
370 : }
371 : }
372 : } else {
373 : sbr_sr = sr;
374 0 : sbr_sr_idx = ctx->hdr.sr_idx;
375 : }
376 :
377 149 : ctx->acfg.base_object_type = ctx->hdr.profile;
378 149 : ctx->acfg.base_sr = sr;
379 149 : ctx->acfg.base_sr_index = ctx->hdr.sr_idx;
380 149 : ctx->acfg.nb_chan = ctx->hdr.nb_ch;
381 149 : ctx->acfg.sbr_object_type = 0;
382 :
383 : /*explicit PS signal (non backward-compatible), only for stereo ADTS*/
384 149 : if (ctx->acfg.nb_chan<=2) {
385 141 : if (ctx->ps==AAC_SIGNAL_EXPLICIT) {
386 3 : ctx->acfg.base_object_type = 29;
387 3 : ctx->acfg.sbr_object_type = ctx->hdr.profile;
388 3 : ctx->acfg.sbr_sr = sr;
389 3 : ctx->acfg.sbr_sr_index = ctx->acfg.base_sr_index;
390 138 : } else if (ctx->ps==AAC_SIGNAL_IMPLICIT) {
391 : use_implicit = GF_TRUE;
392 : }
393 : }
394 :
395 149 : if (ctx->sbr==AAC_SIGNAL_EXPLICIT) {
396 : //don't overwrite obj type if explicit PS is used
397 5 : if (ctx->acfg.base_object_type != 29)
398 2 : ctx->acfg.base_object_type = 5;
399 5 : ctx->acfg.sbr_object_type = ctx->hdr.profile;
400 5 : ctx->acfg.sbr_sr = sbr_sr;
401 5 : ctx->acfg.sbr_sr_index = sbr_sr_idx;
402 144 : } else if (ctx->sbr==AAC_SIGNAL_IMPLICIT) {
403 : sbr_sr = 0;
404 : use_implicit = GF_TRUE;
405 : } else {
406 : sbr_sr = 0;
407 : }
408 149 : ctx->acfg.audioPL = gf_m4a_get_profile(&ctx->acfg);
409 :
410 : /*for better interop, always store using full SR when using explict signaling*/
411 149 : if (sbr_sr) {
412 5 : ctx->dts_inc *= 2;
413 : sr = sbr_sr;
414 : }
415 :
416 149 : gf_m4a_write_config_bs(dsi, &ctx->acfg);
417 149 : gf_bs_align(dsi);
418 :
419 : //implicit signaling, not written by gf_m4a_write_config_bs
420 149 : if (use_implicit) {
421 4 : gf_bs_write_int(dsi, 0x2b7, 11); /*sync extension type*/
422 4 : gf_bs_write_int(dsi, 5, 5); /*audio objectType*/
423 : /*implicit AAC SBR signal*/
424 4 : if (ctx->sbr==AAC_SIGNAL_IMPLICIT) {
425 2 : gf_bs_write_int(dsi, 1, 1); /*SBR present flag*/
426 2 : gf_bs_write_int(dsi, sbr_sr_idx, 4);
427 : } else {
428 2 : gf_bs_write_int(dsi, 0, 1); /*SBR present flag*/
429 : }
430 4 : if (ctx->ps==AAC_SIGNAL_IMPLICIT) {
431 3 : gf_bs_write_int(dsi, 0x548, 11); /*sync extension type*/
432 3 : gf_bs_write_int(dsi, 1, 1); /* PS present flag */
433 : }
434 4 : gf_bs_align(dsi);
435 : }
436 :
437 149 : gf_bs_get_content(dsi, &dsi_b, &dsi_s);
438 149 : gf_bs_del(dsi);
439 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dsi_b, dsi_s) );
440 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PROFILE_LEVEL, & PROP_UINT (ctx->acfg.audioPL) );
441 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(sr));
442 :
443 : timescale = sr;
444 149 : if (ctx->ovsbr) timescale = 2*sr;
445 :
446 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : timescale));
447 149 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
448 :
449 149 : if (ctx->bitrate) {
450 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
451 : }
452 :
453 149 : if (ctx->id3_buffer_size) {
454 0 : id3dmx_flush(filter, ctx->id3_buffer, ctx->id3_buffer_size, ctx->opid, ctx->expart ? &ctx->vpid : NULL);
455 0 : ctx->id3_buffer_size = 0;
456 : }
457 :
458 : }
459 :
460 6681 : static Bool adts_dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
461 : {
462 : u32 i;
463 : GF_FilterEvent fevt;
464 6681 : GF_ADTSDmxCtx *ctx = gf_filter_get_udta(filter);
465 :
466 6681 : switch (evt->base.type) {
467 154 : case GF_FEVT_PLAY:
468 154 : if (!ctx->is_playing) {
469 154 : ctx->is_playing = GF_TRUE;
470 154 : ctx->cts = 0;
471 : }
472 154 : ctx->nb_frames = 0;
473 154 : ctx->id3_buffer_size = 0;
474 :
475 154 : if (! ctx->is_file) {
476 100 : if (evt->play.start_range || ctx->initial_play_done) {
477 0 : ctx->adts_buffer_size = 0;
478 0 : ctx->resume_from = 0;
479 : }
480 :
481 100 : ctx->initial_play_done = GF_TRUE;
482 100 : return GF_FALSE;
483 : }
484 54 : ctx->start_range = evt->play.start_range;
485 54 : ctx->in_seek = GF_TRUE;
486 54 : ctx->file_pos = 0;
487 54 : if (ctx->start_range) {
488 2 : for (i=1; i<ctx->index_size; i++) {
489 3 : if (ctx->indexes[i].duration>ctx->start_range) {
490 1 : ctx->cts = (u64) (ctx->indexes[i-1].duration * GF_M4ASampleRates[ctx->sr_idx]);
491 1 : ctx->file_pos = ctx->indexes[i-1].pos;
492 1 : break;
493 : }
494 : }
495 : }
496 54 : if (!ctx->initial_play_done) {
497 49 : ctx->initial_play_done = GF_TRUE;
498 : //seek will not change the current source state, don't send a seek
499 49 : if (!ctx->file_pos)
500 : return GF_TRUE;
501 : }
502 5 : ctx->resume_from = 0;
503 5 : ctx->adts_buffer_size = 0;
504 : //post a seek
505 5 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
506 5 : fevt.seek.start_offset = ctx->file_pos;
507 5 : gf_filter_pid_send_event(ctx->ipid, &fevt);
508 :
509 : //cancel event
510 5 : return GF_TRUE;
511 :
512 53 : case GF_FEVT_STOP:
513 : //don't cancel event
514 53 : ctx->is_playing = GF_FALSE;
515 53 : return GF_FALSE;
516 :
517 : case GF_FEVT_SET_SPEED:
518 : //cancel event
519 : return GF_TRUE;
520 : default:
521 : break;
522 : }
523 : //by default don't cancel event - to rework once we have downloading in place
524 6473 : return GF_FALSE;
525 : }
526 :
527 : static GFINLINE void adts_dmx_update_cts(GF_ADTSDmxCtx *ctx)
528 : {
529 : assert(ctx->dts_inc);
530 :
531 83356 : if (ctx->timescale) {
532 6205 : u64 inc = ctx->dts_inc;
533 6205 : inc *= ctx->timescale;
534 6205 : inc /= GF_M4ASampleRates[ctx->sr_idx];
535 6205 : ctx->cts += inc;
536 : } else {
537 77151 : ctx->cts += ctx->dts_inc;
538 : }
539 : }
540 :
541 3279306 : GF_Err adts_dmx_process(GF_Filter *filter)
542 : {
543 3279306 : GF_ADTSDmxCtx *ctx = gf_filter_get_udta(filter);
544 : GF_FilterPacket *pck, *dst_pck;
545 : u8 *data, *output;
546 : u8 *start;
547 : u32 pck_size, remain, prev_pck_size;
548 : u64 cts = GF_FILTER_NO_TS;
549 :
550 : //always reparse duration
551 3279306 : if (!ctx->duration.num)
552 11297 : adts_dmx_check_dur(filter, ctx);
553 :
554 3279306 : if (ctx->opid && !ctx->is_playing)
555 : return GF_OK;
556 :
557 12331 : pck = gf_filter_pid_get_packet(ctx->ipid);
558 12331 : if (!pck) {
559 536 : if (gf_filter_pid_is_eos(ctx->ipid)) {
560 252 : if (!ctx->adts_buffer_size) {
561 138 : if (ctx->opid)
562 138 : gf_filter_pid_set_eos(ctx->opid);
563 138 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
564 138 : ctx->src_pck = NULL;
565 138 : return GF_EOS;
566 : }
567 : } else {
568 : return GF_OK;
569 : }
570 : }
571 :
572 11909 : prev_pck_size = ctx->adts_buffer_size;
573 11909 : if (pck && !ctx->resume_from) {
574 11658 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
575 11658 : if (!pck_size) {
576 0 : gf_filter_pid_drop_packet(ctx->ipid);
577 0 : return GF_OK;
578 : }
579 :
580 11658 : if (ctx->byte_offset != GF_FILTER_NO_BO) {
581 5390 : u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
582 5390 : if (!ctx->adts_buffer_size) {
583 155 : ctx->byte_offset = byte_offset;
584 5235 : } else if (ctx->byte_offset + ctx->adts_buffer_size != byte_offset) {
585 0 : ctx->byte_offset = GF_FILTER_NO_BO;
586 0 : if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->adts_buffer_size) ) {
587 0 : ctx->byte_offset = byte_offset - ctx->adts_buffer_size;
588 : }
589 : }
590 : }
591 :
592 11658 : if (ctx->adts_buffer_size + pck_size > ctx->adts_buffer_alloc) {
593 851 : ctx->adts_buffer_alloc = ctx->adts_buffer_size + pck_size;
594 851 : ctx->adts_buffer = gf_realloc(ctx->adts_buffer, ctx->adts_buffer_alloc);
595 : }
596 11658 : memcpy(ctx->adts_buffer + ctx->adts_buffer_size, data, pck_size);
597 11658 : ctx->adts_buffer_size += pck_size;
598 : }
599 :
600 : //input pid sets some timescale - we flushed pending data , update cts
601 11909 : if (ctx->timescale && pck) {
602 6207 : cts = gf_filter_pck_get_cts(pck);
603 : }
604 :
605 6207 : if (cts == GF_FILTER_NO_TS) {
606 : //avoids updating cts
607 : prev_pck_size = 0;
608 : }
609 :
610 11909 : remain = ctx->adts_buffer_size;
611 11909 : start = ctx->adts_buffer;
612 :
613 11909 : if (ctx->resume_from) {
614 137 : start += ctx->resume_from - 1;
615 137 : remain -= ctx->resume_from - 1;
616 137 : ctx->resume_from = 0;
617 : }
618 :
619 95265 : while (remain) {
620 : u8 *sync;
621 : u32 sync_pos, size, offset, bytes_to_drop=0, nb_blocks_per_frame;
622 :
623 95151 : if (!ctx->tag_size && (remain>3)) {
624 :
625 : /* Did we read an ID3v2 ? */
626 95103 : if (start[0] == 'I' && start[1] == 'D' && start[2] == '3') {
627 0 : if (remain<10)
628 : return GF_OK;
629 :
630 0 : ctx->tag_size = ((start[9] & 0x7f) + ((start[8] & 0x7f) << 7) + ((start[7] & 0x7f) << 14) + ((start[6] & 0x7f) << 21));
631 :
632 : bytes_to_drop = 10;
633 0 : if (ctx->id3_buffer_alloc < ctx->tag_size+10) {
634 0 : ctx->id3_buffer = gf_realloc(ctx->id3_buffer, ctx->tag_size+10);
635 0 : ctx->id3_buffer_alloc = ctx->tag_size+10;
636 : }
637 0 : memcpy(ctx->id3_buffer, start, 10);
638 0 : ctx->id3_buffer_size = 10;
639 : goto drop_byte;
640 : }
641 : }
642 95151 : if (ctx->tag_size) {
643 0 : if (ctx->tag_size>remain) {
644 : bytes_to_drop = remain;
645 0 : ctx->tag_size-=remain;
646 : } else {
647 : bytes_to_drop = ctx->tag_size;
648 0 : ctx->tag_size = 0;
649 : }
650 0 : memcpy(ctx->id3_buffer + ctx->id3_buffer_size, start, bytes_to_drop);
651 0 : ctx->id3_buffer_size += bytes_to_drop;
652 :
653 0 : if (!ctx->tag_size && ctx->opid) {
654 0 : id3dmx_flush(filter, ctx->id3_buffer, ctx->id3_buffer_size, ctx->opid, ctx->expart ? &ctx->vpid : NULL);
655 0 : ctx->id3_buffer_size = 0;
656 : }
657 : goto drop_byte;
658 :
659 : }
660 :
661 95151 : sync = memchr(start, 0xFF, remain);
662 95151 : sync_pos = (u32) (sync ? sync - start : remain);
663 :
664 : //couldn't find sync byte in this packet
665 95151 : if (remain - sync_pos < 7) {
666 : break;
667 : }
668 :
669 : //not sync !
670 95025 : if ((sync[1] & 0xF0) != 0xF0) {
671 0 : GF_LOG(ctx->nb_frames ? GF_LOG_WARNING : GF_LOG_DEBUG, GF_LOG_PARSER, ("[ADTSDmx] invalid ADTS sync bytes, resyncing\n"));
672 0 : ctx->nb_frames = 0;
673 : goto drop_byte;
674 : }
675 95025 : if (!ctx->bs) {
676 149 : ctx->bs = gf_bs_new(sync + 1, remain - sync_pos - 1, GF_BITSTREAM_READ);
677 : } else {
678 94876 : gf_bs_reassign_buffer(ctx->bs, sync + 1, remain - sync_pos - 1);
679 : }
680 :
681 : //ok parse header
682 95025 : gf_bs_read_int(ctx->bs, 4);
683 :
684 95025 : ctx->hdr.is_mp2 = (Bool)gf_bs_read_int(ctx->bs, 1);
685 : //if (ctx->mpeg4)
686 : //we deprecate old MPEG-2 signaling for AAC in ISOBMFF, as it is not well supported anyway and we don't write adif_header as
687 : //supposed to be for these types
688 95025 : ctx->hdr.is_mp2 = 0;
689 :
690 95025 : gf_bs_read_int(ctx->bs, 2);
691 95025 : ctx->hdr.no_crc = (Bool)gf_bs_read_int(ctx->bs, 1);
692 :
693 95025 : ctx->hdr.profile = 1 + gf_bs_read_int(ctx->bs, 2);
694 95025 : ctx->hdr.sr_idx = gf_bs_read_int(ctx->bs, 4);
695 95025 : gf_bs_read_int(ctx->bs, 1);
696 95025 : ctx->hdr.nb_ch = gf_bs_read_int(ctx->bs, 3);
697 :
698 95025 : gf_bs_read_int(ctx->bs, 4);
699 95025 : ctx->hdr.frame_size = gf_bs_read_int(ctx->bs, 13);
700 95025 : gf_bs_read_int(ctx->bs, 11);
701 95025 : nb_blocks_per_frame = gf_bs_read_int(ctx->bs, 2);
702 95025 : ctx->hdr.hdr_size = 7;
703 :
704 95025 : if (!ctx->hdr.no_crc) {
705 : u32 skip;
706 0 : if (!nb_blocks_per_frame) {
707 : skip = 2;
708 : } else {
709 0 : skip = 2 + 2*nb_blocks_per_frame; //and we have 2 bytes per raw_data_block
710 : }
711 0 : ctx->hdr.hdr_size += skip;
712 0 : gf_bs_skip_bytes(ctx->bs, skip);
713 : }
714 :
715 95025 : if (!ctx->hdr.frame_size || !GF_M4ASampleRates[ctx->hdr.sr_idx]) {
716 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[ADTSDmx] Invalid ADTS frame header, resyncing\n"));
717 0 : ctx->nb_frames = 0;
718 : goto drop_byte;
719 : }
720 95025 : if ((nb_blocks_per_frame>2) || (nb_blocks_per_frame && ctx->hdr.nb_ch)) {
721 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[ADTSDmx] Unsupported multi-block ADTS frame header - patch welcome\n"));
722 0 : ctx->nb_frames = 0;
723 : goto drop_byte;
724 95025 : } else if (!nb_blocks_per_frame) {
725 95025 : if (ctx->aacchcfg<0)
726 0 : ctx->hdr.nb_ch = -ctx->aacchcfg;
727 95025 : else if (!ctx->hdr.nb_ch)
728 0 : ctx->hdr.nb_ch = ctx->aacchcfg;
729 :
730 95025 : if (!ctx->hdr.nb_ch) {
731 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ADTSDmx] Missing channel configuration in ADTS frame header, defaulting to stereo - use `--aacchcfg` to force config\n"));
732 0 : ctx->hdr.nb_ch = ctx->aacchcfg = 2;
733 : }
734 : }
735 :
736 95025 : if (nb_blocks_per_frame==2) {
737 0 : u32 pos = (u32) gf_bs_get_position(ctx->bs);
738 0 : gf_m4a_parse_program_config_element(ctx->bs, &ctx->acfg);
739 0 : if (!ctx->hdr.no_crc)
740 0 : gf_bs_skip_bytes(ctx->bs, 2); //per block CRC
741 :
742 0 : ctx->hdr.hdr_size += (u32) gf_bs_get_position(ctx->bs) - pos;
743 : }
744 : //value 1->6 match channel number, value 7 is 7.1
745 95025 : if (ctx->hdr.nb_ch==7)
746 0 : ctx->hdr.nb_ch = 8;
747 :
748 :
749 : //ready to send packet
750 95025 : if (ctx->hdr.frame_size + 1 < remain) {
751 : u32 next_frame = ctx->hdr.frame_size;
752 : //make sure we are sync!
753 83379 : if ((sync[next_frame] !=0xFF) || ((sync[next_frame+1] & 0xF0) !=0xF0) ) {
754 0 : GF_LOG(ctx->nb_frames ? GF_LOG_WARNING : GF_LOG_DEBUG, GF_LOG_PARSER, ("[ADTSDmx] invalid next ADTS frame sync, resyncing\n"));
755 0 : ctx->nb_frames = 0;
756 : goto drop_byte;
757 : }
758 : }
759 : //otherwise wait for next frame, unless if end of stream
760 11646 : else if (pck) {
761 11532 : if (ctx->timescale && !prev_pck_size && (cts != GF_FILTER_NO_TS) ) {
762 6207 : ctx->cts = cts;
763 : }
764 : break;
765 : }
766 :
767 83493 : if (ctx->hdr.frame_size < ctx->hdr.hdr_size) {
768 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ADTSDmx] Corrupted ADTS frame header, resyncing\n"));
769 0 : ctx->nb_frames = 0;
770 : goto drop_byte;
771 : }
772 :
773 83493 : adts_dmx_check_pid(filter, ctx);
774 :
775 83493 : if (!ctx->is_playing) {
776 137 : ctx->resume_from = 1 + ctx->adts_buffer_size - remain;
777 137 : return GF_OK;
778 : }
779 :
780 83356 : ctx->nb_frames++;
781 83356 : size = ctx->hdr.frame_size - ctx->hdr.hdr_size;
782 : offset = ctx->hdr.hdr_size;
783 : //per raw-block CRC
784 83356 : if ((nb_blocks_per_frame==2) && !ctx->hdr.no_crc)
785 0 : size -= 2;
786 :
787 83356 : if (ctx->in_seek) {
788 148 : u64 nb_samples_at_seek = (u64) (ctx->start_range * GF_M4ASampleRates[ctx->sr_idx]);
789 148 : if (ctx->cts + ctx->dts_inc >= nb_samples_at_seek) {
790 : //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
791 53 : ctx->in_seek = GF_FALSE;
792 : }
793 : }
794 :
795 : bytes_to_drop = ctx->hdr.frame_size;
796 83356 : if (ctx->timescale && !prev_pck_size && (cts != GF_FILTER_NO_TS) ) {
797 0 : ctx->cts = cts;
798 : cts = GF_FILTER_NO_TS;
799 : }
800 :
801 83356 : if (!ctx->in_seek) {
802 83261 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
803 83261 : if (!dst_pck) return GF_OUT_OF_MEM;
804 83261 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
805 :
806 83261 : memcpy(output, sync + offset, size);
807 :
808 83261 : gf_filter_pck_set_dts(dst_pck, ctx->cts);
809 83261 : gf_filter_pck_set_cts(dst_pck, ctx->cts);
810 83261 : gf_filter_pck_set_duration(dst_pck, ctx->dts_inc);
811 83261 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
812 83261 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
813 :
814 83261 : if (ctx->byte_offset != GF_FILTER_NO_BO) {
815 75406 : gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset + ctx->hdr.hdr_size);
816 : }
817 :
818 83261 : gf_filter_pck_send(dst_pck);
819 : }
820 : adts_dmx_update_cts(ctx);
821 :
822 :
823 : //truncated last frame
824 83356 : if (bytes_to_drop>remain) {
825 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ADTSDmx] truncated ADTS frame!\n"));
826 : bytes_to_drop=remain;
827 : }
828 :
829 166712 : drop_byte:
830 83356 : if (!bytes_to_drop) {
831 : bytes_to_drop = 1;
832 : }
833 83356 : start += bytes_to_drop;
834 83356 : remain -= bytes_to_drop;
835 :
836 83356 : if (prev_pck_size) {
837 6190 : if (prev_pck_size > bytes_to_drop) prev_pck_size -= bytes_to_drop;
838 : else {
839 : prev_pck_size=0;
840 6190 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
841 6190 : ctx->src_pck = pck;
842 6190 : if (pck)
843 6190 : gf_filter_pck_ref_props(&ctx->src_pck);
844 : }
845 : }
846 83356 : if (ctx->byte_offset != GF_FILTER_NO_BO)
847 75501 : ctx->byte_offset += bytes_to_drop;
848 : }
849 :
850 11772 : if (!pck) {
851 114 : ctx->adts_buffer_size = 0;
852 114 : return adts_dmx_process(filter);
853 : } else {
854 11658 : if (remain) {
855 11658 : memmove(ctx->adts_buffer, start, remain);
856 : }
857 11658 : ctx->adts_buffer_size = remain;
858 11658 : gf_filter_pid_drop_packet(ctx->ipid);
859 : }
860 11658 : return GF_OK;
861 : }
862 :
863 149 : static void adts_dmx_finalize(GF_Filter *filter)
864 : {
865 149 : GF_ADTSDmxCtx *ctx = gf_filter_get_udta(filter);
866 149 : if (ctx->bs) gf_bs_del(ctx->bs);
867 149 : if (ctx->indexes) gf_free(ctx->indexes);
868 149 : if (ctx->adts_buffer) gf_free(ctx->adts_buffer);
869 149 : if (ctx->id3_buffer) gf_free(ctx->id3_buffer);
870 149 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
871 149 : }
872 :
873 3074 : static const char *adts_dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
874 : {
875 : u32 nb_frames=0, next_pos=0, max_consecutive_frames=0;
876 : ADTSHeader prev_hdr;
877 : GF_BitStream *bs;
878 : Bool has_id3=GF_FALSE;
879 : Bool has_broken_data=GF_FALSE;
880 :
881 : /*check for id3*/
882 3074 : if (size>= 10) {
883 3070 : if (data[0] == 'I' && data[1] == 'D' && data[2] == '3') {
884 1 : u32 tag_size = ((data[9] & 0x7f) + ((data[8] & 0x7f) << 7) + ((data[7] & 0x7f) << 14) + ((data[6] & 0x7f) << 21));
885 :
886 1 : if (tag_size+10 > size) {
887 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("ID3 tag detected size %d but probe data only %d bytes, will rely on file extension (try increasing probe size using --block_size)\n", tag_size+10, size));
888 0 : *score = GF_FPROBE_EXT_MATCH;
889 0 : return "aac|adts";
890 : }
891 1 : data += tag_size+10;
892 1 : size -= tag_size+10;
893 : has_id3 = GF_TRUE;
894 : }
895 : }
896 :
897 3074 : bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
898 : memset(&prev_hdr, 0, sizeof(ADTSHeader));
899 3935 : while (gf_bs_available(bs)) {
900 : ADTSHeader hdr;
901 : u32 pos;
902 3935 : hdr.frame_size = 0;
903 3935 : if (!adts_dmx_sync_frame_bs(bs, &hdr)) {
904 2911 : if (hdr.frame_size) {
905 : //nb_frames++;
906 866 : max_consecutive_frames++;
907 : }
908 3074 : break;
909 : }
910 1024 : if ((hdr.hdr_size!=7) && (hdr.hdr_size!=9)) continue;
911 : // if (!hdr.nb_ch) continue;
912 1024 : pos = (u32) gf_bs_get_position(bs);
913 :
914 1024 : if (!nb_frames) {
915 : nb_frames = 1;
916 840 : } else if ((next_pos + hdr.hdr_size == pos) && (hdr.sr_idx==prev_hdr.sr_idx) && (hdr.nb_ch==prev_hdr.nb_ch) ) {
917 817 : nb_frames++;
918 817 : if (max_consecutive_frames<nb_frames) max_consecutive_frames = nb_frames;
919 817 : if (max_consecutive_frames>5)
920 : break;
921 : } else {
922 : nb_frames=1;
923 : has_broken_data=GF_TRUE;
924 : }
925 861 : prev_hdr = hdr;
926 861 : gf_bs_skip_bytes(bs, hdr.frame_size);
927 861 : next_pos = (u32) gf_bs_get_position(bs);
928 : }
929 3074 : gf_bs_del(bs);
930 3074 : if (max_consecutive_frames>=4) {
931 163 : *score = has_broken_data ? GF_FPROBE_MAYBE_SUPPORTED : GF_FPROBE_SUPPORTED;
932 163 : return "audio/aac";
933 : }
934 2911 : if (has_id3 && max_consecutive_frames) {
935 1 : *score = GF_FPROBE_MAYBE_SUPPORTED;
936 1 : return "audio/aac";
937 : }
938 : return NULL;
939 : }
940 :
941 : static const GF_FilterCapability ADTSDmxCaps[] =
942 : {
943 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
944 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "aac|adts"),
945 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/x-m4a|audio/aac|audio/aacp|audio/x-aac"),
946 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
947 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
948 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
949 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
950 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
951 : //we explitely set this one to prevent adts->latm reframer connection
952 : CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
953 : {0},
954 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
955 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
956 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
957 : };
958 :
959 :
960 : #define OFFS(_n) #_n, offsetof(GF_ADTSDmxCtx, _n)
961 : static const GF_FilterArgs ADTSDmxArgs[] =
962 : {
963 : { OFFS(frame_size), "size of AAC frame in audio samples", GF_PROP_UINT, "1024", NULL, GF_FS_ARG_HINT_EXPERT},
964 : { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
965 : // { OFFS(mpeg4), "force signaling as MPEG-4 AAC", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
966 : { OFFS(ovsbr), "force oversampling SBR (does not multiply timescales by 2)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
967 : { OFFS(sbr), "set SBR signaling\n"\
968 : "- no: no SBR signaling at all\n"\
969 : "- imp: backward-compatible SBR signaling (audio signaled as AAC-LC)\n"\
970 : "- exp: explicit SBR signaling (audio signaled as AAC-SBR)"\
971 : , GF_PROP_UINT, "no", "no|imp|exp", GF_FS_ARG_HINT_ADVANCED},
972 : { OFFS(ps), "set PS signaling\n"\
973 : "- no: no PS signaling at all\n"\
974 : "- imp: backward-compatible PS signaling (audio signaled as AAC-LC)\n"\
975 : "- exp: explicit PS signaling (audio signaled as AAC-PS)"\
976 : , GF_PROP_UINT, "no", "no|imp|exp", GF_FS_ARG_HINT_ADVANCED},
977 : { OFFS(expart), "expose pictures as a dedicated video pid", GF_PROP_BOOL, "false", NULL, 0},
978 : { OFFS(aacchcfg), "set AAC channel configuration to this value if missing from ADTS header, use negative value to always override", GF_PROP_SINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
979 : {0}
980 : };
981 :
982 :
983 : GF_FilterRegister ADTSDmxRegister = {
984 : .name = "rfadts",
985 : GF_FS_SET_DESCRIPTION("ADTS reframer")
986 : GF_FS_SET_HELP("This filter parses AAC files/data and outputs corresponding audio PID and frames.")
987 : .private_size = sizeof(GF_ADTSDmxCtx),
988 : .args = ADTSDmxArgs,
989 : .finalize = adts_dmx_finalize,
990 : SETCAPS(ADTSDmxCaps),
991 : .configure_pid = adts_dmx_configure_pid,
992 : .process = adts_dmx_process,
993 : .probe_data = adts_dmx_probe_data,
994 : .process_event = adts_dmx_process_event
995 : };
996 :
997 :
998 2877 : const GF_FilterRegister *adts_dmx_register(GF_FilterSession *session)
999 : {
1000 2877 : return &ADTSDmxRegister;
1001 : }
1002 :
1003 : #else
1004 : const GF_FilterRegister *adts_dmx_register(GF_FilterSession *session)
1005 : {
1006 : return NULL;
1007 : }
1008 : #endif // GPAC_DISABLE_AV_PARSERS
|