#endif
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "aacenc.h"
int aacenc_is_sbr_active(const aacenc_param_t *params)
return 0;
}
+static const unsigned aacenc_sampling_freq_tab[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static
+unsigned sampling_freq_index(unsigned rate)
+{
+ unsigned i;
+ for (i = 0; aacenc_sampling_freq_tab[i]; ++i)
+ if (aacenc_sampling_freq_tab[i] == rate)
+ return i;
+ return 0xf;
+}
+
+/*
+ * Append backward compatible SBR/PS signaling to implicit signaling ASC,
+ * if SBR/PS is present.
+ */
+int aacenc_mp4asc(const aacenc_param_t *params,
+ const uint8_t *asc, uint32_t ascsize,
+ uint8_t *outasc, uint32_t *outsize)
+{
+ unsigned asc_sfreq = aacenc_sampling_freq_tab[(asc[0]&0x7)<<1 |asc[1]>>7];
+
+ switch (params->profile) {
+ case AOT_SBR:
+ case AOT_PS:
+ if (*outsize < ascsize + 3)
+ return -1;
+ memcpy(outasc, asc, ascsize);
+ /* syncExtensionType:11 (value:0x2b7) */
+ outasc[ascsize+0] = 0x2b << 1;
+ outasc[ascsize+1] = 0x7 << 5;
+ /* extensionAudioObjectType:5 (value:5)*/
+ outasc[ascsize+1] |= 5;
+ /* sbrPresentFlag:1 (value:1) */
+ outasc[ascsize+2] = 0x80;
+ /* extensionSamplingFrequencyIndex:4 */
+ outasc[ascsize+2] |= sampling_freq_index(asc_sfreq << 1) << 3;
+ if (params->profile == AOT_SBR) {
+ *outsize = ascsize + 3;
+ break;
+ }
+ if (*outsize < ascsize + 5)
+ return -1;
+ /* syncExtensionType:11 (value:0x548) */
+ outasc[ascsize+2] |= 0x5;
+ outasc[ascsize+3] = 0x48;
+ /* psPresentFlag:1 (value:1) */
+ outasc[ascsize+4] = 0x80;
+ *outsize = ascsize + 5;
+ break;
+ default:
+ if (*outsize < ascsize)
+ return -1;
+ memcpy(outasc, asc, ascsize);
+ *outsize = ascsize;
+ }
+ return 0;
+}
+
static
int aacenc_channel_mode(const pcm_sample_description_t *format)
{
" 0: Off\n"
" 1: On(default)\n"
" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n"
-" -s, --sbr-signaling <n> SBR signaling mode\n"
-" 0: Implicit, backward compatible(default)\n"
-" 1: Explicit SBR and implicit PS\n"
-" 2: Explicit hierarchical signaling\n"
" -f, --transport-format <n> Transport format\n"
" 0: RAW (default, muxed into M4A)\n"
" 1: ADIF\n"
{ "bandwidth", required_argument, 0, 'w' },
{ "afterburner", required_argument, 0, 'a' },
{ "lowdelay-sbr", no_argument, 0, 'L' },
- { "sbr-signaling", required_argument, 0, 's' },
{ "transport-format", required_argument, 0, 'f' },
{ "adts-crc-check", no_argument, 0, 'C' },
{ "header-period", required_argument, 0, 'P' },
case 'L':
params->lowdelay_sbr = 1;
break;
- case 's':
- if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
- fprintf(stderr, "invalid arg for sbr-signaling\n");
- return -1;
- }
- params->sbr_signaling = n;
- break;
case 'f':
if (sscanf(optarg, "%u", &n) != 1) {
fprintf(stderr, "invalid arg for transport-format\n");
const pcm_sample_description_t *sample_format;
int downsampled_timescale = 0;
int frame_count = 0;
+ int sbr_mode = 0;
setlocale(LC_CTYPE, "");
setbuf(stderr, 0);
sample_format = pcm_get_format(reader);
+ /*
+ * We use explicit/hierarchical signaling for LOAS.
+ * Other than that, we request implicit signaling to FDK library, then
+ * append explicit/backward-compatible signaling to ASC in case of MP4FF.
+ *
+ * Explicit/backward-compatible signaling of SBR is the most recommended
+ * way in MPEG4 part3 spec, and seems the only way supported by iTunes.
+ * Since FDK library does not support it, we have to do it on our side.
+ */
+ params.sbr_signaling = (params.transport_format == TT_MP4_LOAS) ? 2 : 0;
+
if (aacenc_init(&encoder, (aacenc_param_t*)¶ms, sample_format,
&aacinfo) < 0)
goto END;
goto END;
}
handle_signals();
+ sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms);
if (!params.transport_format) {
uint32_t scale;
+ uint8_t mp4asc[32];
+ uint32_t ascsize = sizeof(mp4asc);
unsigned framelen = aacinfo.frameLength;
- int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms);
- int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
- if (sbr_mode && !sig_mode)
+ if (sbr_mode)
downsampled_timescale = 1;
scale = sample_format->sample_rate >> downsampled_timescale;
if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
params.output_fp)) < 0)
goto END;
- m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf,
- aacinfo.confSize);
+ aacenc_mp4asc((aacenc_param_t*)¶ms, aacinfo.confBuf,
+ aacinfo.confSize, mp4asc, &ascsize);
+ m4af_set_decoder_specific_info(m4af, 0, mp4asc, ascsize);
m4af_set_fixed_frame_duration(m4af, 0,
framelen >> downsampled_timescale);
m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);