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 : #include <gpac/internal/media_dev.h>
30 :
31 : #ifndef GPAC_DISABLE_AV_PARSERS
32 :
33 : typedef struct
34 : {
35 : u64 pos;
36 : Double duration;
37 : } LATMIdx;
38 :
39 : typedef struct
40 : {
41 : //filter args
42 : u32 frame_size;
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 sr_idx, nb_ch, base_object_type;
53 : GF_Fraction64 duration;
54 : Double start_range;
55 : Bool in_seek;
56 : u32 timescale;
57 :
58 : GF_M4ADecSpecInfo acfg;
59 :
60 : char *latm_buffer;
61 : u32 latm_buffer_size, latm_buffer_alloc;
62 : u32 dts_inc;
63 :
64 : Bool is_playing;
65 : Bool is_file, file_loaded;
66 : Bool initial_play_done;
67 :
68 : GF_FilterPacket *src_pck;
69 :
70 : LATMIdx *indexes;
71 : u32 index_alloc_size, index_size;
72 : u32 resume_from;
73 :
74 : Bool prev_sap;
75 : u32 bitrate;
76 : GF_Err in_error;
77 : } GF_LATMDmxCtx;
78 :
79 :
80 7905 : static Bool latm_dmx_sync_frame_bs(GF_BitStream *bs, GF_M4ADecSpecInfo *acfg, u32 *nb_bytes, u8 *buffer, u32 *nb_skipped)
81 : {
82 : u32 val, size;
83 : u64 pos, mux_size;
84 7905 : if (nb_skipped) *nb_skipped = 0;
85 7905 : if (!acfg) return 0;
86 :
87 9242282 : while (gf_bs_available(bs)>3) {
88 9240365 : val = gf_bs_read_u8(bs);
89 9240365 : if (val!=0x56) {
90 9217002 : if (nb_skipped) (*nb_skipped) ++;
91 9217002 : continue;
92 : }
93 23363 : val = gf_bs_read_int(bs, 3);
94 23363 : if (val != 0x07) {
95 16424 : gf_bs_read_int(bs, 5);
96 16424 : if (nb_skipped) (*nb_skipped) ++;
97 16424 : continue;
98 : }
99 6939 : mux_size = gf_bs_read_int(bs, 13);
100 6939 : pos = gf_bs_get_position(bs);
101 6939 : if (mux_size>gf_bs_available(bs) ) {
102 1223 : gf_bs_seek(bs, pos-3);
103 1223 : return GF_FALSE;
104 : }
105 :
106 : /*use same stream mux*/
107 5716 : if (!gf_bs_read_int(bs, 1)) {
108 : Bool amux_version, amux_versionA;
109 :
110 817 : amux_version = (Bool)gf_bs_read_int(bs, 1);
111 : amux_versionA = GF_FALSE;
112 817 : if (amux_version) amux_versionA = (Bool)gf_bs_read_int(bs, 1);
113 272 : if (!amux_versionA) {
114 : u32 i, allStreamsSameTimeFraming, numProgram;
115 618 : if (amux_version) gf_latm_get_value(bs);
116 :
117 618 : allStreamsSameTimeFraming = gf_bs_read_int(bs, 1);
118 618 : /*numSubFrames = */gf_bs_read_int(bs, 6);
119 618 : numProgram = gf_bs_read_int(bs, 4);
120 4383 : for (i=0; i<=numProgram; i++) {
121 : u32 j, num_lay;
122 3765 : num_lay = gf_bs_read_int(bs, 3);
123 19677 : for (j=0; j<=num_lay; j++) {
124 : u32 frameLengthType;
125 : Bool same_cfg = GF_FALSE;
126 15912 : if (i || j) same_cfg = (Bool)gf_bs_read_int(bs, 1);
127 :
128 15294 : if (!same_cfg) {
129 7636 : if (amux_version==1) gf_latm_get_value(bs);
130 7636 : gf_m4a_parse_config(bs, acfg, GF_FALSE);
131 : }
132 15912 : frameLengthType = gf_bs_read_int(bs, 3);
133 15912 : if (!frameLengthType) {
134 2437 : /*latmBufferFullness = */gf_bs_read_int(bs, 8);
135 : if (!allStreamsSameTimeFraming) {
136 : }
137 : } else {
138 : /*not supported*/
139 : }
140 : }
141 :
142 : }
143 : /*other data present*/
144 618 : if (gf_bs_read_int(bs, 1)) {
145 : // u32 k = 0;
146 : }
147 : /*CRCcheck present*/
148 618 : if (gf_bs_read_int(bs, 1)) {
149 : }
150 : }
151 : }
152 :
153 : size = 0;
154 : while (1) {
155 6352 : u32 tmp = gf_bs_read_int(bs, 8);
156 6352 : size += tmp;
157 6352 : if (tmp!=255) break;
158 : }
159 5716 : if (gf_bs_available(bs) < size) {
160 0 : gf_bs_seek(bs, pos-3);
161 0 : return GF_FALSE;
162 : }
163 :
164 5716 : if (nb_bytes) {
165 2970 : *nb_bytes = (u32) size;
166 : }
167 :
168 5716 : if (buffer) {
169 2970 : gf_bs_read_data(bs, (char *) buffer, size);
170 : } else {
171 294416 : while (size) {
172 291670 : gf_bs_read_int(bs, 8);
173 291670 : size--;
174 : }
175 : }
176 :
177 : /*parse amux*/
178 5716 : gf_bs_seek(bs, pos + mux_size);
179 :
180 5716 : if ((gf_bs_available(bs)>2) && gf_bs_peek_bits(bs, 11, 0) != 0x2B7) {
181 951 : gf_bs_seek(bs, pos + 1);
182 951 : if (nb_skipped) (*nb_skipped) ++;
183 951 : continue;
184 : }
185 :
186 : return GF_TRUE;
187 : }
188 : return GF_FALSE;
189 : }
190 :
191 :
192 :
193 4 : GF_Err latm_dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
194 : {
195 : const GF_PropertyValue *p;
196 4 : GF_LATMDmxCtx *ctx = gf_filter_get_udta(filter);
197 :
198 4 : 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 4 : if (! gf_filter_pid_check_caps(pid))
207 : return GF_NOT_SUPPORTED;
208 :
209 4 : ctx->ipid = pid;
210 4 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
211 4 : if (p) ctx->timescale = p->value.uint;
212 :
213 4 : if (ctx->timescale && !ctx->opid) {
214 0 : ctx->opid = gf_filter_pid_new(filter);
215 0 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
216 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
217 : }
218 :
219 : return GF_OK;
220 : }
221 :
222 36 : static void latm_dmx_check_dur(GF_Filter *filter, GF_LATMDmxCtx *ctx)
223 : {
224 : FILE *stream;
225 : GF_BitStream *bs;
226 : GF_M4ADecSpecInfo acfg;
227 : u64 duration, cur_dur, cur_pos, rate;
228 : s32 sr_idx = -1;
229 : const GF_PropertyValue *p;
230 70 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
231 :
232 4 : if (ctx->index<=0) {
233 2 : ctx->file_loaded = GF_TRUE;
234 : return;
235 : }
236 :
237 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
238 2 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
239 0 : ctx->is_file = GF_FALSE;
240 0 : ctx->file_loaded = GF_TRUE;
241 : return;
242 : }
243 2 : ctx->is_file = GF_TRUE;
244 :
245 2 : stream = gf_fopen(p->value.string, "rb");
246 2 : if (!stream) return;
247 :
248 2 : ctx->index_size = 0;
249 :
250 : memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
251 :
252 :
253 2 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
254 : duration = 0;
255 : cur_dur = 0;
256 2 : cur_pos = gf_bs_get_position(bs);
257 1625 : while (latm_dmx_sync_frame_bs(bs, &acfg, 0, NULL, NULL)) {
258 1623 : if ((sr_idx>=0) && (sr_idx != acfg.base_sr_index)) {
259 0 : duration *= GF_M4ASampleRates[acfg.base_sr_index];
260 0 : duration /= GF_M4ASampleRates[sr_idx];
261 :
262 0 : cur_dur *= GF_M4ASampleRates[acfg.base_sr_index];
263 0 : cur_dur /= GF_M4ASampleRates[sr_idx];
264 : }
265 1623 : sr_idx = acfg.base_sr_index;
266 1623 : duration += ctx->frame_size;
267 1623 : cur_dur += ctx->frame_size;
268 1623 : if (cur_dur > ctx->index * GF_M4ASampleRates[sr_idx]) {
269 36 : if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
270 34 : else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
271 36 : ctx->indexes = gf_realloc(ctx->indexes, sizeof(LATMIdx)*ctx->index_alloc_size);
272 36 : ctx->indexes[ctx->index_size].pos = cur_pos;
273 36 : ctx->indexes[ctx->index_size].duration = (Double) duration;
274 36 : ctx->indexes[ctx->index_size].duration /= GF_M4ASampleRates[sr_idx];
275 36 : ctx->index_size ++;
276 : cur_dur = 0;
277 : }
278 :
279 1623 : cur_pos = gf_bs_get_position(bs);
280 : }
281 2 : rate = gf_bs_get_position(bs);
282 2 : gf_bs_del(bs);
283 2 : gf_fclose(stream);
284 :
285 2 : if (sr_idx>=0) {
286 2 : if (!ctx->duration.num || (ctx->duration.num * GF_M4ASampleRates[sr_idx] != duration * ctx->duration.den)) {
287 2 : ctx->duration.num = (s32) duration;
288 2 : ctx->duration.den = GF_M4ASampleRates[sr_idx];
289 :
290 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
291 :
292 2 : if (duration && !gf_sys_is_test_mode() ) {
293 0 : rate *= 8 * ctx->duration.den;
294 0 : rate /= ctx->duration.num;
295 0 : ctx->bitrate = (u32) rate;
296 : }
297 : }
298 : }
299 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
300 2 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
301 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
302 : }
303 :
304 2970 : static void latm_dmx_check_pid(GF_Filter *filter, GF_LATMDmxCtx *ctx)
305 : {
306 : u8 *dsi_b;
307 : u32 dsi_s, sr, timescale=0;
308 : u32 codecid;
309 2970 : if (!ctx->opid) {
310 4 : ctx->opid = gf_filter_pid_new(filter);
311 4 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
312 4 : latm_dmx_check_dur(filter, ctx);
313 : }
314 2970 : if (!GF_M4ASampleRates[ctx->acfg.base_sr_index]) {
315 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[LATMDmx] Wrong sample rate in audio config, broken stream\n"));
316 0 : ctx->in_error = GF_NON_COMPLIANT_BITSTREAM;
317 2966 : return;
318 : }
319 :
320 2970 : if ((ctx->sr_idx == ctx->acfg.base_sr_index) && (ctx->nb_ch == ctx->acfg.nb_chan )
321 2966 : && (ctx->base_object_type == ctx->acfg.base_object_type) ) return;
322 :
323 4 : if (ctx->acfg.base_object_type==GF_M4A_USAC)
324 : codecid = GF_CODECID_USAC;
325 : else
326 : codecid = GF_CODECID_AAC_MPEG4;
327 : //copy properties at init or reconfig
328 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
329 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT( codecid));
330 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->frame_size) );
331 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
332 4 : if (ctx->is_file && ctx->index) {
333 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
334 : }
335 4 : if (ctx->duration.num)
336 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
337 :
338 :
339 4 : ctx->nb_ch = ctx->acfg.nb_chan;
340 4 : ctx->base_object_type = ctx->acfg.base_object_type;
341 :
342 4 : sr = GF_M4ASampleRates[ctx->acfg.base_sr_index];
343 4 : if (!ctx->timescale) {
344 : //we change sample rate, change cts
345 4 : if (ctx->cts && (ctx->sr_idx != ctx->acfg.base_sr_index)) {
346 0 : ctx->cts *= sr;
347 0 : ctx->cts /= GF_M4ASampleRates[ctx->sr_idx];
348 : }
349 : }
350 4 : ctx->sr_idx = ctx->acfg.base_sr_index;
351 :
352 4 : ctx->dts_inc = ctx->frame_size;
353 4 : gf_m4a_write_config(&ctx->acfg, &dsi_b, &dsi_s);
354 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dsi_b, dsi_s) );
355 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PROFILE_LEVEL, & PROP_UINT (ctx->acfg.audioPL) );
356 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(sr));
357 :
358 : timescale = sr;
359 :
360 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : timescale));
361 4 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
362 :
363 4 : if (ctx->bitrate) {
364 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
365 : }
366 : }
367 :
368 74 : static Bool latm_dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
369 : {
370 : u32 i;
371 : GF_FilterEvent fevt;
372 74 : GF_LATMDmxCtx *ctx = gf_filter_get_udta(filter);
373 :
374 74 : switch (evt->base.type) {
375 4 : case GF_FEVT_PLAY:
376 4 : if (!ctx->is_playing) {
377 4 : ctx->is_playing = GF_TRUE;
378 4 : ctx->cts = 0;
379 : }
380 4 : if (! ctx->is_file) {
381 2 : if (evt->play.start_range || ctx->initial_play_done) {
382 0 : ctx->latm_buffer_size = 0;
383 0 : ctx->resume_from = 0;
384 : }
385 :
386 2 : ctx->initial_play_done = GF_TRUE;
387 2 : return GF_FALSE;
388 : }
389 2 : ctx->start_range = evt->play.start_range;
390 2 : ctx->in_seek = GF_TRUE;
391 2 : ctx->file_pos = 0;
392 2 : if (ctx->start_range) {
393 0 : for (i=1; i<ctx->index_size; i++) {
394 0 : if (ctx->indexes[i].duration>ctx->start_range) {
395 0 : ctx->cts = (u64) (ctx->indexes[i-1].duration * GF_M4ASampleRates[ctx->sr_idx]);
396 0 : ctx->file_pos = ctx->indexes[i-1].pos;
397 0 : break;
398 : }
399 : }
400 : }
401 2 : if (!ctx->initial_play_done) {
402 2 : ctx->initial_play_done = GF_TRUE;
403 : //seek will not change the current source state, don't send a seek
404 2 : if (!ctx->file_pos)
405 : return GF_TRUE;
406 : }
407 0 : ctx->latm_buffer_size = 0;
408 0 : ctx->resume_from = 0;
409 : //post a seek
410 0 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
411 0 : fevt.seek.start_offset = ctx->file_pos;
412 0 : gf_filter_pid_send_event(ctx->ipid, &fevt);
413 :
414 : //cancel event
415 0 : return GF_TRUE;
416 :
417 1 : case GF_FEVT_STOP:
418 : //don't cancel event
419 1 : ctx->is_playing = GF_FALSE;
420 1 : return GF_FALSE;
421 :
422 : case GF_FEVT_SET_SPEED:
423 : //cancel event
424 : return GF_TRUE;
425 : default:
426 : break;
427 : }
428 : //by default don't cancel event - to rework once we have downloading in place
429 69 : return GF_FALSE;
430 : }
431 :
432 : static GFINLINE void latm_dmx_update_cts(GF_LATMDmxCtx *ctx)
433 : {
434 : assert(ctx->dts_inc);
435 :
436 2966 : if (ctx->timescale) {
437 0 : u64 inc = ctx->dts_inc;
438 0 : inc *= ctx->timescale;
439 0 : inc /= GF_M4ASampleRates[ctx->sr_idx];
440 0 : ctx->cts += inc;
441 : } else {
442 2966 : ctx->cts += ctx->dts_inc;
443 : }
444 : }
445 :
446 86 : GF_Err latm_dmx_process(GF_Filter *filter)
447 : {
448 86 : GF_LATMDmxCtx *ctx = gf_filter_get_udta(filter);
449 : GF_FilterPacket *pck, *dst_pck;
450 : u32 pos;
451 : u8 *data=NULL, *output;
452 86 : u32 pck_size=0, prev_pck_size;
453 : u64 cts = GF_FILTER_NO_TS;
454 :
455 86 : if (ctx->in_error)
456 : return ctx->in_error;
457 :
458 : //always reparse duration
459 86 : if (!ctx->duration.num)
460 32 : latm_dmx_check_dur(filter, ctx);
461 :
462 86 : if (ctx->opid && !ctx->is_playing)
463 : return GF_OK;
464 :
465 71 : pck = gf_filter_pid_get_packet(ctx->ipid);
466 71 : if (!pck) {
467 3 : if (gf_filter_pid_is_eos(ctx->ipid)) {
468 3 : if (!ctx->latm_buffer_size) {
469 3 : if (ctx->opid)
470 3 : gf_filter_pid_set_eos(ctx->opid);
471 3 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
472 3 : ctx->src_pck = NULL;
473 3 : return GF_EOS;
474 : }
475 : } else {
476 : return GF_OK;
477 : }
478 : } else {
479 68 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
480 : }
481 :
482 : //input pid sets some timescale - we flushed pending data , update cts
483 68 : if (ctx->timescale && pck) {
484 0 : cts = gf_filter_pck_get_cts(pck);
485 : }
486 :
487 68 : prev_pck_size = ctx->latm_buffer_size;
488 :
489 68 : if (pck && !ctx->resume_from) {
490 64 : if (ctx->latm_buffer_size + pck_size > ctx->latm_buffer_alloc) {
491 20 : ctx->latm_buffer_alloc = ctx->latm_buffer_size + pck_size;
492 20 : ctx->latm_buffer = gf_realloc(ctx->latm_buffer, ctx->latm_buffer_alloc);
493 : }
494 64 : memcpy(ctx->latm_buffer + ctx->latm_buffer_size, data, pck_size);
495 64 : ctx->latm_buffer_size += pck_size;
496 : }
497 :
498 68 : if (!ctx->bs) ctx->bs = gf_bs_new(ctx->latm_buffer, ctx->latm_buffer_size, GF_BITSTREAM_READ);
499 64 : else gf_bs_reassign_buffer(ctx->bs, ctx->latm_buffer, ctx->latm_buffer_size);
500 :
501 68 : if (ctx->resume_from) {
502 4 : gf_bs_seek(ctx->bs, ctx->resume_from-1);
503 4 : ctx->resume_from = 0;
504 : }
505 :
506 68 : if (cts == GF_FILTER_NO_TS)
507 : prev_pck_size = 0;
508 :
509 :
510 2966 : while (1) {
511 3034 : pos = (u32) gf_bs_get_position(ctx->bs);
512 : u8 latm_buffer[4096];
513 3034 : u32 latm_frame_size = 4096;
514 3034 : if (!latm_dmx_sync_frame_bs(ctx->bs,&ctx->acfg, &latm_frame_size, latm_buffer, NULL)) break;
515 :
516 2970 : if (ctx->in_seek) {
517 2 : u64 nb_samples_at_seek = (u64) (ctx->start_range * GF_M4ASampleRates[ctx->sr_idx]);
518 2 : if (ctx->cts + ctx->dts_inc >= nb_samples_at_seek) {
519 : //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
520 2 : ctx->in_seek = GF_FALSE;
521 : }
522 : }
523 :
524 2970 : latm_dmx_check_pid(filter, ctx);
525 :
526 2970 : if (!ctx->is_playing) {
527 4 : ctx->resume_from = pos+1;
528 8 : return GF_OK;
529 : }
530 :
531 2966 : if (!ctx->in_seek) {
532 : GF_FilterSAPType sap = GF_FILTER_SAP_1;
533 :
534 2966 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, latm_frame_size, &output);
535 2966 : if (!dst_pck) return GF_OUT_OF_MEM;
536 :
537 2966 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
538 :
539 2966 : memcpy(output, latm_buffer, latm_frame_size);
540 :
541 2966 : gf_filter_pck_set_cts(dst_pck, ctx->cts);
542 2966 : gf_filter_pck_set_duration(dst_pck, ctx->dts_inc);
543 2966 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
544 :
545 : /*xHE-AAC, check RAP*/
546 2966 : if (ctx->acfg.base_object_type==GF_CODECID_USAC) {
547 0 : if (latm_frame_size && (output[0] & 0x80) && !ctx->prev_sap) {
548 : sap = GF_FILTER_SAP_1;
549 0 : ctx->prev_sap = GF_TRUE;
550 : } else {
551 : sap = GF_FILTER_SAP_NONE;
552 0 : ctx->prev_sap = GF_FALSE;
553 : }
554 : }
555 2966 : gf_filter_pck_set_sap(dst_pck, sap);
556 :
557 2966 : gf_filter_pck_send(dst_pck);
558 : }
559 : latm_dmx_update_cts(ctx);
560 :
561 2966 : if (prev_pck_size) {
562 0 : pos = (u32) gf_bs_get_position(ctx->bs);
563 0 : if (prev_pck_size<=pos) {
564 : prev_pck_size=0;
565 0 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
566 0 : ctx->src_pck = pck;
567 0 : if (pck)
568 0 : gf_filter_pck_ref_props(&ctx->src_pck);
569 : }
570 : }
571 : }
572 :
573 64 : if (pck) {
574 64 : pos = (u32) gf_bs_get_position(ctx->bs);
575 : assert(ctx->latm_buffer_size >= pos);
576 64 : memmove(ctx->latm_buffer, ctx->latm_buffer+pos, ctx->latm_buffer_size - pos);
577 64 : ctx->latm_buffer_size -= pos;
578 64 : gf_filter_pid_drop_packet(ctx->ipid);
579 : assert(!ctx->resume_from);
580 : } else {
581 0 : ctx->latm_buffer_size = 0;
582 0 : return latm_dmx_process(filter);
583 : }
584 64 : return GF_OK;
585 : }
586 :
587 4 : static void latm_dmx_finalize(GF_Filter *filter)
588 : {
589 4 : GF_LATMDmxCtx *ctx = gf_filter_get_udta(filter);
590 4 : if (ctx->bs) gf_bs_del(ctx->bs);
591 4 : if (ctx->indexes) gf_free(ctx->indexes);
592 4 : if (ctx->latm_buffer) gf_free(ctx->latm_buffer);
593 4 : }
594 :
595 3074 : static const char *latm_dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
596 : {
597 : u32 nb_frames=0;
598 : u32 nb_skip=0;
599 : GF_M4ADecSpecInfo acfg;
600 3074 : GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
601 172 : while (1) {
602 3246 : u32 nb_skipped = 0;
603 3246 : if (!latm_dmx_sync_frame_bs(bs, &acfg, 0, NULL, &nb_skipped)) break;
604 172 : if (! GF_M4ASampleRates[acfg.base_sr_index]) {
605 : nb_frames = 0;
606 : break;
607 : }
608 :
609 172 : if (nb_skipped) {
610 1 : if (nb_skip) {
611 : nb_frames = 0;
612 : break;
613 : }
614 : nb_skip++;
615 : }
616 172 : nb_frames++;
617 : }
618 3074 : gf_bs_del(bs);
619 3074 : if (nb_frames>=2) {
620 4 : *score = nb_skip ? GF_FPROBE_MAYBE_SUPPORTED : GF_FPROBE_SUPPORTED;
621 4 : return "audio/aac+latm";
622 : }
623 : return NULL;
624 : }
625 :
626 : static const GF_FilterCapability LATMDmxCaps[] =
627 : {
628 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
629 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "latm"),
630 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/aac+latm"),
631 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
632 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
633 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
634 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
635 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
636 : CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
637 : {0},
638 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
639 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
640 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
641 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
642 : };
643 :
644 :
645 : #define OFFS(_n) #_n, offsetof(GF_LATMDmxCtx, _n)
646 : static const GF_FilterArgs LATMDmxArgs[] =
647 : {
648 : { OFFS(frame_size), "size of AAC frame in audio samples", GF_PROP_UINT, "1024", NULL, GF_FS_ARG_HINT_EXPERT},
649 : { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
650 : {0}
651 : };
652 :
653 :
654 : GF_FilterRegister LATMDmxRegister = {
655 : .name = "rflatm",
656 : GF_FS_SET_DESCRIPTION("LATM reframer")
657 : GF_FS_SET_HELP("This filter parses AAC in LATM files/data and outputs corresponding audio PID and frames.")
658 : .private_size = sizeof(GF_LATMDmxCtx),
659 : .args = LATMDmxArgs,
660 : .finalize = latm_dmx_finalize,
661 : SETCAPS(LATMDmxCaps),
662 : .configure_pid = latm_dmx_configure_pid,
663 : .process = latm_dmx_process,
664 : .probe_data = latm_dmx_probe_data,
665 : .process_event = latm_dmx_process_event
666 : };
667 :
668 :
669 2877 : const GF_FilterRegister *latm_dmx_register(GF_FilterSession *session)
670 : {
671 2877 : return &LATMDmxRegister;
672 : }
673 :
674 : #else
675 : const GF_FilterRegister *latm_dmx_register(GF_FilterSession *session)
676 : {
677 : return NULL;
678 : }
679 : #endif // GPAC_DISABLE_AV_PARSERS
|