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 write 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/filters.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/bitstream.h>
29 :
30 : #include <gpac/avparse.h>
31 :
32 :
33 : typedef struct
34 : {
35 : //opts
36 : Bool exporter, mpeg2;
37 :
38 : //only one input pid declared
39 : GF_FilterPid *ipid;
40 : //only one output pid declared
41 : GF_FilterPid *opid;
42 :
43 : u32 codecid, channels, sr_idx, aac_type, ch_cfg;
44 :
45 : Bool is_latm;
46 :
47 : GF_BitStream *bs_w;
48 :
49 : #ifndef GPAC_DISABLE_AV_PARSERS
50 : GF_M4ADecSpecInfo acfg;
51 : u8 *pce;
52 : u32 pce_size;
53 : #else
54 : u8 *dsi;
55 : u32 dsi_size;
56 : #endif
57 : u32 dsi_crc;
58 : Bool update_dsi;
59 : GF_Fraction fdsi;
60 : u64 last_cts;
61 : u32 timescale;
62 : } GF_ADTSMxCtx;
63 :
64 :
65 :
66 :
67 13 : GF_Err adtsmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
68 : {
69 : u32 i, sr, chan_cfg=0;
70 : Bool patch_channels = GF_FALSE;
71 : const GF_PropertyValue *p;
72 13 : GF_ADTSMxCtx *ctx = gf_filter_get_udta(filter);
73 :
74 13 : if (is_remove) {
75 0 : ctx->ipid = NULL;
76 0 : if (ctx->opid) {
77 0 : gf_filter_pid_remove(ctx->opid);
78 0 : ctx->opid = NULL;
79 : }
80 : return GF_OK;
81 : }
82 13 : if (! gf_filter_pid_check_caps(pid))
83 : return GF_NOT_SUPPORTED;
84 :
85 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
86 13 : if (!p) return GF_NOT_SUPPORTED;
87 13 : ctx->codecid = p->value.uint;
88 :
89 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
90 13 : if (!p) return GF_NOT_SUPPORTED;
91 13 : sr = p->value.uint;
92 :
93 13 : ctx->channels = 0;
94 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
95 13 : if (p)
96 13 : ctx->channels = p->value.uint;
97 :
98 : #ifndef GPAC_DISABLE_AV_PARSERS
99 13 : memset(&ctx->acfg, 0, sizeof(GF_M4ADecSpecInfo));
100 : #endif
101 :
102 13 : ctx->aac_type = 0;
103 13 : if (ctx->is_latm) {
104 : u32 crc;
105 2 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
106 2 : if (!p) return GF_NOT_SUPPORTED;
107 :
108 2 : crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
109 2 : if (crc != ctx->dsi_crc) {
110 2 : ctx->dsi_crc = crc;
111 : #ifndef GPAC_DISABLE_AV_PARSERS
112 2 : gf_m4a_get_config(p->value.data.ptr, p->value.data.size, &ctx->acfg);
113 : #endif
114 2 : ctx->update_dsi = GF_TRUE;
115 : }
116 :
117 2 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
118 2 : if (!p) return GF_NOT_SUPPORTED;
119 2 : ctx->timescale = p->value.uint;
120 :
121 11 : } else if (ctx->codecid==GF_CODECID_AAC_MPEG4) {
122 : //setup default config
123 11 : chan_cfg = ctx->channels;
124 11 : if (chan_cfg==8)
125 : chan_cfg = 7;
126 :
127 11 : if (!ctx->mpeg2) {
128 : #ifndef GPAC_DISABLE_AV_PARSERS
129 11 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
130 11 : if (p) {
131 9 : gf_m4a_get_config(p->value.data.ptr, p->value.data.size, &ctx->acfg);
132 9 : ctx->aac_type = ctx->acfg.base_object_type - 1;
133 9 : chan_cfg = ctx->acfg.chan_cfg;
134 9 : sr = ctx->acfg.base_sr;
135 : } else
136 : #endif
137 : {
138 2 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[RFADTS] no AAC decoder config, assuming AAC-LC\n"));
139 2 : ctx->aac_type = GF_M4A_AAC_LC;
140 :
141 2 : if (!ctx->channels) {
142 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFADTS] no channel config found for ADTS, forcing stereo\n"));
143 0 : chan_cfg = ctx->channels = 2;
144 : patch_channels = GF_TRUE;
145 : }
146 :
147 2 : if (!chan_cfg) {
148 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFADTS] Unkown channel config, will not be able to signal it in ADTS\n"));
149 : }
150 : }
151 : }
152 :
153 11 : if (chan_cfg>7) {
154 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFADTS] Unkown channel config, will not be able to signal it in ADTS\n"));
155 : chan_cfg = 0;
156 : }
157 : } else {
158 0 : ctx->aac_type = ctx->codecid - GF_CODECID_AAC_MPEG2_MP;
159 : }
160 :
161 : #ifndef GPAC_DISABLE_AV_PARSERS
162 13 : if (ctx->channels && ctx->acfg.nb_chan && (ctx->channels != ctx->acfg.nb_chan)) {
163 : //do not warn here, as most MP4 files will use nbChan=2 for multichan
164 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[RFADTS] Mismatch between container number of channels (%d) and AAC config (%d), using AAC config\n", ctx->channels, ctx->acfg.nb_chan));
165 0 : ctx->channels = ctx->acfg.nb_chan;
166 : patch_channels = GF_TRUE;
167 : }
168 13 : if ((ctx->acfg.base_object_type==2) && (ctx->acfg.base_sr!=sr)) {
169 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFADTS] Mismatch between container samplerate (%d) and AAC config SBR base samplerate (%d), using AAC config\n", sr, ctx->acfg.base_sr));
170 0 : sr = ctx->acfg.base_sr;
171 : }
172 13 : if (!ctx->acfg.chan_cfg && ctx->acfg.program_config_element_present) {
173 0 : GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
174 0 : gf_m4a_write_program_config_element_bs(bs, &ctx->acfg);
175 0 : if (ctx->pce) gf_free(ctx->pce);
176 0 : ctx->pce = NULL;
177 0 : gf_bs_get_content(bs, &ctx->pce, &ctx->pce_size);
178 0 : gf_bs_del(bs);
179 :
180 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFADTS] ADTS will use multiple raw blocks to signal channel configuration\n"));
181 : }
182 : #else
183 :
184 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
185 : if (!p) return GF_NOT_SUPPORTED;
186 : ctx->dsi = p->value.data.ptr;
187 : ctx->dsi_size = p->value.data.size;
188 : #endif
189 :
190 :
191 13 : ctx->ch_cfg = chan_cfg;
192 :
193 68 : for (i=0; i<16; i++) {
194 68 : if (GF_M4ASampleRates[i] == (u32) sr) {
195 13 : ctx->sr_idx = i;
196 13 : break;
197 : }
198 : }
199 :
200 :
201 13 : if (!ctx->opid) {
202 11 : ctx->opid = gf_filter_pid_new(filter);
203 : }
204 13 : ctx->ipid = pid;
205 13 : gf_filter_pid_copy_properties(ctx->opid, pid);
206 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
207 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
208 13 : if (ctx->is_latm)
209 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED_LATM, &PROP_BOOL(GF_TRUE) );
210 :
211 13 : if (patch_channels)
212 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->channels));
213 13 : gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
214 13 : return GF_OK;
215 : }
216 :
217 :
218 :
219 2772 : GF_Err adtsmx_process(GF_Filter *filter)
220 : {
221 2772 : GF_ADTSMxCtx *ctx = gf_filter_get_udta(filter);
222 : GF_FilterPacket *pck, *dst_pck;
223 : u8 *data, *output;
224 : u32 pck_size, size;
225 :
226 2772 : pck = gf_filter_pid_get_packet(ctx->ipid);
227 2772 : if (!pck) {
228 374 : if (gf_filter_pid_is_eos(ctx->ipid)) {
229 24 : gf_filter_pid_set_eos(ctx->opid);
230 24 : return GF_EOS;
231 : }
232 : return GF_OK;
233 : }
234 :
235 2398 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
236 :
237 2398 : if (ctx->is_latm) {
238 : u32 asize;
239 :
240 377 : size = pck_size+20;
241 377 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
242 377 : if (!dst_pck) return GF_OUT_OF_MEM;
243 :
244 377 : if (!ctx->bs_w) ctx->bs_w = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
245 375 : else gf_bs_reassign_buffer(ctx->bs_w, output, size);
246 :
247 377 : gf_bs_write_int(ctx->bs_w, 0x2B7, 11);
248 377 : gf_bs_write_int(ctx->bs_w, 0, 13);
249 377 : if (ctx->codecid==GF_CODECID_USAC) {
250 0 : GF_FilterSAPType sap = gf_filter_pck_get_sap(pck);
251 0 : if ((sap == GF_FILTER_SAP_1) || (sap == GF_FILTER_SAP_4_PROL)) {
252 0 : ctx->update_dsi = GF_TRUE;
253 : }
254 : } else {
255 :
256 377 : if (ctx->fdsi.num && ctx->fdsi.den) {
257 0 : u64 ts = gf_filter_pck_get_cts(pck);
258 0 : if (ts != GF_FILTER_NO_TS) {
259 0 : if ((ts - ctx->last_cts) * ctx->fdsi.den >= ctx->timescale * ctx->fdsi.num) {
260 0 : ctx->last_cts = ts;
261 0 : ctx->update_dsi = GF_TRUE;
262 : }
263 : }
264 : }
265 : }
266 : /*same mux config = 0 (refresh aac config)*/
267 377 : if (ctx->update_dsi) {
268 2 : gf_bs_write_int(ctx->bs_w, 0, 1);
269 : /*mux config */
270 2 : gf_bs_write_int(ctx->bs_w, 0, 1);/*audio mux version = 0*/
271 2 : gf_bs_write_int(ctx->bs_w, 1, 1);/*allStreamsSameTimeFraming*/
272 2 : gf_bs_write_int(ctx->bs_w, 0, 6);/*numSubFrames*/
273 2 : gf_bs_write_int(ctx->bs_w, 0, 4);/*numProgram*/
274 2 : gf_bs_write_int(ctx->bs_w, 0, 3);/*numLayer prog 1*/
275 :
276 : #ifndef GPAC_DISABLE_AV_PARSERS
277 2 : gf_m4a_write_config_bs(ctx->bs_w, &ctx->acfg);
278 : #else
279 : gf_bs_write_data(ctx->bs_w, ctx->dsi, ctx->dsi_size);
280 : #endif
281 2 : gf_bs_write_int(ctx->bs_w, 0, 3);/*frameLengthType*/
282 2 : gf_bs_write_int(ctx->bs_w, 0, 8);/*latmBufferFullness*/
283 2 : gf_bs_write_int(ctx->bs_w, 0, 1);/*other data present*/
284 2 : gf_bs_write_int(ctx->bs_w, 0, 1);/*crcCheckPresent*/
285 :
286 2 : ctx->update_dsi = 0;
287 : } else {
288 375 : gf_bs_write_int(ctx->bs_w, 1, 1);
289 : }
290 : /*write payloadLengthInfo*/
291 377 : asize = pck_size;
292 : while (1) {
293 745 : if (asize>=255) {
294 184 : gf_bs_write_int(ctx->bs_w, 255, 8);
295 184 : asize -= 255;
296 : } else {
297 377 : gf_bs_write_int(ctx->bs_w, asize, 8);
298 : break;
299 : }
300 : }
301 377 : gf_bs_write_data(ctx->bs_w, data, pck_size);
302 377 : gf_bs_align(ctx->bs_w);
303 :
304 377 : size = (u32) gf_bs_get_position(ctx->bs_w);
305 377 : gf_filter_pck_truncate(dst_pck, size);
306 :
307 : /*rewrite LATM frame header*/
308 377 : output[1] |= ((size-3) >> 8 ) & 0x1F;
309 377 : output[2] = (size-3) & 0xFF;
310 :
311 : } else {
312 : u32 nb_blocks = 0;
313 2021 : size = pck_size+7;
314 : #ifndef GPAC_DISABLE_AV_PARSERS
315 2021 : if (! ctx->acfg.chan_cfg && ctx->pce_size) {
316 : nb_blocks = 2;
317 0 : size += ctx->pce_size;
318 : }
319 : #endif
320 2021 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
321 2021 : if (!dst_pck) return GF_OUT_OF_MEM;
322 :
323 2021 : if (!ctx->bs_w) ctx->bs_w = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
324 2012 : else gf_bs_reassign_buffer(ctx->bs_w, output, size);
325 :
326 2021 : gf_bs_write_int(ctx->bs_w, 0xFFF, 12);/*sync*/
327 2021 : gf_bs_write_int(ctx->bs_w, (ctx->mpeg2==1) ? 1 : 0, 1);/*mpeg2 aac*/
328 2021 : gf_bs_write_int(ctx->bs_w, 0, 2); /*layer*/
329 2021 : gf_bs_write_int(ctx->bs_w, 1, 1); /* protection_absent*/
330 2021 : gf_bs_write_int(ctx->bs_w, ctx->aac_type, 2);
331 2021 : gf_bs_write_int(ctx->bs_w, ctx->sr_idx, 4);
332 2021 : gf_bs_write_int(ctx->bs_w, 0, 1);
333 2021 : gf_bs_write_int(ctx->bs_w, ctx->ch_cfg, 3);
334 2021 : gf_bs_write_int(ctx->bs_w, 0, 4);
335 2021 : gf_bs_write_int(ctx->bs_w, size, 13);
336 2021 : gf_bs_write_int(ctx->bs_w, 0x7FF, 11);
337 :
338 2021 : gf_bs_write_int(ctx->bs_w, nb_blocks, 2);
339 :
340 2021 : output += 7;
341 : #ifndef GPAC_DISABLE_AV_PARSERS
342 2021 : if (nb_blocks) {
343 0 : memcpy(output, ctx->pce, ctx->pce_size);
344 0 : output += ctx->pce_size;
345 : }
346 : #endif
347 2021 : memcpy(output, data, pck_size);
348 : }
349 :
350 2398 : gf_filter_pck_merge_properties(pck, dst_pck);
351 2398 : gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
352 :
353 :
354 2398 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
355 :
356 2398 : gf_filter_pck_send(dst_pck);
357 2398 : gf_filter_pid_drop_packet(ctx->ipid);
358 2398 : return GF_OK;
359 : }
360 :
361 11 : static void adtsmx_finalize(GF_Filter *filter)
362 : {
363 11 : GF_ADTSMxCtx *ctx = gf_filter_get_udta(filter);
364 11 : if (ctx->bs_w) gf_bs_del(ctx->bs_w);
365 11 : if (ctx->pce) gf_free(ctx->pce);
366 11 : }
367 :
368 : static const GF_FilterCapability ADTSMxCaps[] =
369 : {
370 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
371 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
372 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
373 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
374 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
375 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
376 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
377 : };
378 :
379 :
380 : #define OFFS(_n) #_n, offsetof(GF_ADTSMxCtx, _n)
381 : static const GF_FilterArgs ADTSMxArgs[] =
382 : {
383 : { OFFS(mpeg2), "signal as MPEG2 AAC\n"
384 : "- auto: selects based on AAC profile\n"
385 : "- no: always signals as MPEG-4 AAC\n"
386 : "- yes: always signals as MPEG-2 AAC"
387 : "", GF_PROP_UINT, "auto", "auto|no|yes", GF_FS_ARG_HINT_ADVANCED},
388 : {0}
389 : };
390 :
391 :
392 : GF_FilterRegister ADTSMxRegister = {
393 : .name = "ufadts",
394 : GF_FS_SET_DESCRIPTION("ADTS writer")
395 : GF_FS_SET_HELP("This filter converts AAC streams into ADTS encapsulated data.")
396 : .private_size = sizeof(GF_ADTSMxCtx),
397 : .args = ADTSMxArgs,
398 : .finalize = adtsmx_finalize,
399 : SETCAPS(ADTSMxCaps),
400 : .configure_pid = adtsmx_configure_pid,
401 : .process = adtsmx_process
402 : };
403 :
404 :
405 2877 : const GF_FilterRegister *adtsmx_register(GF_FilterSession *session)
406 : {
407 2877 : return &ADTSMxRegister;
408 : }
409 :
410 2 : static GF_Err latmmx_initialize(GF_Filter*filter)
411 : {
412 2 : GF_ADTSMxCtx *ctx = gf_filter_get_udta(filter);
413 2 : ctx->is_latm = GF_TRUE;
414 2 : return GF_OK;
415 : }
416 :
417 : #define OFFS(_n) #_n, offsetof(GF_ADTSMxCtx, _n)
418 : static const GF_FilterArgs LATMMxArgs[] =
419 : {
420 : { OFFS(fdsi), "set delay between two LATM Audio Config", GF_PROP_FRACTION, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
421 : {0}
422 : };
423 :
424 :
425 : static const GF_FilterCapability LATMMxCaps[] =
426 : {
427 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
428 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
429 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
430 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
431 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
432 : CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_USAC),
433 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
434 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
435 : };
436 :
437 : GF_FilterRegister LATMMxRegister = {
438 : .name = "uflatm",
439 : GF_FS_SET_DESCRIPTION("Raw AAC to LATM writer")
440 : GF_FS_SET_HELP("This filter converts AAC streams into LATM encapsulated data.")
441 : .private_size = sizeof(GF_ADTSMxCtx),
442 : .args = LATMMxArgs,
443 : .initialize = latmmx_initialize,
444 : .finalize = adtsmx_finalize,
445 : SETCAPS(LATMMxCaps),
446 : .configure_pid = adtsmx_configure_pid,
447 : .process = adtsmx_process
448 : };
449 :
450 :
451 2877 : const GF_FilterRegister *latm_mx_register(GF_FilterSession *session)
452 : {
453 2877 : return &LATMMxRegister;
454 : }
|