mirror of
https://github.com/nu774/fdkaac.git
synced 2025-06-05 23:29:14 +02:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
b159a7b095 | |||
be234dc464 | |||
c9ac59e8d3 | |||
9b8f9915c2 | |||
5ccbfaa710 | |||
8f05e0751b | |||
053279541b | |||
f48bf1294c | |||
8896249ac5 |
22
ChangeLog
22
ChangeLog
@ -1,6 +1,26 @@
|
|||||||
|
2013-10-25 nu774 <honeycomb77@gmail.com>
|
||||||
|
|
||||||
|
* update ChangeLog [HEAD]
|
||||||
|
|
||||||
|
* bump version [v0.4.0]
|
||||||
|
|
||||||
|
* update README
|
||||||
|
|
||||||
|
2013-10-24 nu774 <honeycomb77@gmail.com>
|
||||||
|
|
||||||
|
* caf input support
|
||||||
|
|
||||||
|
* refactor pcm io routines
|
||||||
|
|
||||||
|
2013-10-23 nu774 <honeycomb77@gmail.com>
|
||||||
|
|
||||||
|
* cleanup metadata handling
|
||||||
|
|
||||||
|
* --tag-from-json: properly support number/total format in json track field
|
||||||
|
|
||||||
2013-10-22 nu774 <honeycomb77@gmail.com>
|
2013-10-22 nu774 <honeycomb77@gmail.com>
|
||||||
|
|
||||||
* bump version [HEAD]
|
* bump version [v0.3.3]
|
||||||
|
|
||||||
* fixed bogus sgpd written on --gapless-mode=1 and 2
|
* fixed bogus sgpd written on --gapless-mode=1 and 2
|
||||||
|
|
||||||
|
63
src/aacenc.c
63
src/aacenc.c
@ -10,6 +10,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "aacenc.h"
|
#include "aacenc.h"
|
||||||
|
|
||||||
int aacenc_is_sbr_active(const aacenc_param_t *params)
|
int aacenc_is_sbr_active(const aacenc_param_t *params)
|
||||||
@ -25,6 +26,68 @@ int aacenc_is_sbr_active(const aacenc_param_t *params)
|
|||||||
return 0;
|
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
|
static
|
||||||
int aacenc_channel_mode(const pcm_sample_description_t *format)
|
int aacenc_channel_mode(const pcm_sample_description_t *format)
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,10 @@ typedef struct aacenc_param_t {
|
|||||||
|
|
||||||
int aacenc_is_sbr_active(const aacenc_param_t *params);
|
int aacenc_is_sbr_active(const aacenc_param_t *params);
|
||||||
|
|
||||||
|
int aacenc_mp4asc(const aacenc_param_t *params,
|
||||||
|
const uint8_t *asc, uint32_t ascsize,
|
||||||
|
uint8_t *outasc, uint32_t *outsize);
|
||||||
|
|
||||||
int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
|
int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
|
||||||
const pcm_sample_description_t *format,
|
const pcm_sample_description_t *format,
|
||||||
AACENC_InfoStruct *info);
|
AACENC_InfoStruct *info);
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
#include "lpcm.h"
|
#include "lpcm.h"
|
||||||
#include "m4af_endian.h"
|
#include "m4af_endian.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||||
# define inline __inline
|
|
||||||
# ifdef _M_IX86
|
# ifdef _M_IX86
|
||||||
inline int lrint(double x)
|
inline int lrint(double x)
|
||||||
{
|
{
|
||||||
|
59
src/main.c
59
src/main.c
@ -133,10 +133,6 @@ PROGNAME " %s\n"
|
|||||||
" 0: Off\n"
|
" 0: Off\n"
|
||||||
" 1: On(default)\n"
|
" 1: On(default)\n"
|
||||||
" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\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"
|
" -f, --transport-format <n> Transport format\n"
|
||||||
" 0: RAW (default, muxed into M4A)\n"
|
" 0: RAW (default, muxed into M4A)\n"
|
||||||
" 1: ADIF\n"
|
" 1: ADIF\n"
|
||||||
@ -153,7 +149,10 @@ PROGNAME " %s\n"
|
|||||||
" 0: iTunSMPB (default)\n"
|
" 0: iTunSMPB (default)\n"
|
||||||
" 1: ISO standard (edts + sgpd)\n"
|
" 1: ISO standard (edts + sgpd)\n"
|
||||||
" 2: Both\n"
|
" 2: Both\n"
|
||||||
" --ignorelength Ignore length of WAV header\n"
|
" --include-sbr-delay Count SBR decoder delay in encoder delay\n"
|
||||||
|
" This is not iTunes compatible, but is default\n"
|
||||||
|
" behavior of FDK library.\n"
|
||||||
|
" -I, --ignorelength Ignore length of WAV header\n"
|
||||||
" -S, --silent Don't print progress messages\n"
|
" -S, --silent Don't print progress messages\n"
|
||||||
" --moov-before-mdat Place moov box before mdat box on m4a output\n"
|
" --moov-before-mdat Place moov box before mdat box on m4a output\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -208,6 +207,7 @@ typedef struct aacenc_param_ex_t {
|
|||||||
char *output_filename;
|
char *output_filename;
|
||||||
FILE *output_fp;
|
FILE *output_fp;
|
||||||
unsigned gapless_mode;
|
unsigned gapless_mode;
|
||||||
|
unsigned include_sbr_delay;
|
||||||
unsigned ignore_length;
|
unsigned ignore_length;
|
||||||
int silent;
|
int silent;
|
||||||
int moov_before_mdat;
|
int moov_before_mdat;
|
||||||
@ -230,6 +230,7 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
|||||||
int ch;
|
int ch;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
|
#define OPT_INCLUDE_SBR_DELAY M4AF_FOURCC('s','d','l','y')
|
||||||
#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
|
#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
|
||||||
#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
|
#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
|
||||||
#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
|
#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
|
||||||
@ -247,12 +248,12 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
|||||||
{ "bandwidth", required_argument, 0, 'w' },
|
{ "bandwidth", required_argument, 0, 'w' },
|
||||||
{ "afterburner", required_argument, 0, 'a' },
|
{ "afterburner", required_argument, 0, 'a' },
|
||||||
{ "lowdelay-sbr", no_argument, 0, 'L' },
|
{ "lowdelay-sbr", no_argument, 0, 'L' },
|
||||||
{ "sbr-signaling", required_argument, 0, 's' },
|
|
||||||
{ "transport-format", required_argument, 0, 'f' },
|
{ "transport-format", required_argument, 0, 'f' },
|
||||||
{ "adts-crc-check", no_argument, 0, 'C' },
|
{ "adts-crc-check", no_argument, 0, 'C' },
|
||||||
{ "header-period", required_argument, 0, 'P' },
|
{ "header-period", required_argument, 0, 'P' },
|
||||||
|
|
||||||
{ "gapless-mode", required_argument, 0, 'G' },
|
{ "gapless-mode", required_argument, 0, 'G' },
|
||||||
|
{ "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY },
|
||||||
{ "ignorelength", no_argument, 0, 'I' },
|
{ "ignorelength", no_argument, 0, 'I' },
|
||||||
{ "silent", no_argument, 0, 'S' },
|
{ "silent", no_argument, 0, 'S' },
|
||||||
{ "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
|
{ "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
|
||||||
@ -326,13 +327,6 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
|||||||
case 'L':
|
case 'L':
|
||||||
params->lowdelay_sbr = 1;
|
params->lowdelay_sbr = 1;
|
||||||
break;
|
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':
|
case 'f':
|
||||||
if (sscanf(optarg, "%u", &n) != 1) {
|
if (sscanf(optarg, "%u", &n) != 1) {
|
||||||
fprintf(stderr, "invalid arg for transport-format\n");
|
fprintf(stderr, "invalid arg for transport-format\n");
|
||||||
@ -360,6 +354,9 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
|
|||||||
}
|
}
|
||||||
params->gapless_mode = n;
|
params->gapless_mode = n;
|
||||||
break;
|
break;
|
||||||
|
case OPT_INCLUDE_SBR_DELAY:
|
||||||
|
params->include_sbr_delay = 1;
|
||||||
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
params->ignore_length = 1;
|
params->ignore_length = 1;
|
||||||
break;
|
break;
|
||||||
@ -669,7 +666,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params)
|
|||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
io.cookie = params->input_fp;
|
io.cookie = params->input_fp;
|
||||||
if (fstat(fileno(io.cookie), &stb) == 0
|
if (fstat(fileno(params->input_fp), &stb) == 0
|
||||||
&& (stb.st_mode & S_IFMT) == S_IFREG)
|
&& (stb.st_mode & S_IFMT) == S_IFREG)
|
||||||
io.vtbl = &pcm_io_vtbl;
|
io.vtbl = &pcm_io_vtbl;
|
||||||
else
|
else
|
||||||
@ -736,6 +733,7 @@ int main(int argc, char **argv)
|
|||||||
const pcm_sample_description_t *sample_format;
|
const pcm_sample_description_t *sample_format;
|
||||||
int downsampled_timescale = 0;
|
int downsampled_timescale = 0;
|
||||||
int frame_count = 0;
|
int frame_count = 0;
|
||||||
|
int sbr_mode = 0;
|
||||||
|
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
setbuf(stderr, 0);
|
setbuf(stderr, 0);
|
||||||
@ -748,6 +746,17 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
sample_format = pcm_get_format(reader);
|
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,
|
if (aacenc_init(&encoder, (aacenc_param_t*)¶ms, sample_format,
|
||||||
&aacinfo) < 0)
|
&aacinfo) < 0)
|
||||||
goto END;
|
goto END;
|
||||||
@ -764,19 +773,21 @@ int main(int argc, char **argv)
|
|||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
handle_signals();
|
handle_signals();
|
||||||
|
sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms);
|
||||||
if (!params.transport_format) {
|
if (!params.transport_format) {
|
||||||
uint32_t scale;
|
uint32_t scale;
|
||||||
|
uint8_t mp4asc[32];
|
||||||
|
uint32_t ascsize = sizeof(mp4asc);
|
||||||
unsigned framelen = aacinfo.frameLength;
|
unsigned framelen = aacinfo.frameLength;
|
||||||
int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)¶ms);
|
if (sbr_mode)
|
||||||
int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
|
|
||||||
if (sbr_mode && !sig_mode)
|
|
||||||
downsampled_timescale = 1;
|
downsampled_timescale = 1;
|
||||||
scale = sample_format->sample_rate >> downsampled_timescale;
|
scale = sample_format->sample_rate >> downsampled_timescale;
|
||||||
if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
|
if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
|
||||||
params.output_fp)) < 0)
|
params.output_fp)) < 0)
|
||||||
goto END;
|
goto END;
|
||||||
m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf,
|
aacenc_mp4asc((aacenc_param_t*)¶ms, aacinfo.confBuf,
|
||||||
aacinfo.confSize);
|
aacinfo.confSize, mp4asc, &ascsize);
|
||||||
|
m4af_set_decoder_specific_info(m4af, 0, mp4asc, ascsize);
|
||||||
m4af_set_fixed_frame_duration(m4af, 0,
|
m4af_set_fixed_frame_duration(m4af, 0,
|
||||||
framelen >> downsampled_timescale);
|
framelen >> downsampled_timescale);
|
||||||
m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
|
m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
|
||||||
@ -789,9 +800,15 @@ int main(int argc, char **argv)
|
|||||||
goto END;
|
goto END;
|
||||||
if (m4af) {
|
if (m4af) {
|
||||||
uint32_t delay = aacinfo.encoderDelay;
|
uint32_t delay = aacinfo.encoderDelay;
|
||||||
|
uint32_t padding;
|
||||||
int64_t frames_read = pcm_get_position(reader);
|
int64_t frames_read = pcm_get_position(reader);
|
||||||
uint32_t padding = frame_count * aacinfo.frameLength
|
|
||||||
- frames_read - aacinfo.encoderDelay;
|
if (sbr_mode && params.profile != AOT_ER_AAC_ELD &&
|
||||||
|
!params.include_sbr_delay)
|
||||||
|
delay -= 481 << 1;
|
||||||
|
if (sbr_mode && (delay & 1))
|
||||||
|
++delay;
|
||||||
|
padding = frame_count * aacinfo.frameLength - frames_read - delay;
|
||||||
m4af_set_priming(m4af, 0, delay >> downsampled_timescale,
|
m4af_set_priming(m4af, 0, delay >> downsampled_timescale,
|
||||||
padding >> downsampled_timescale);
|
padding >> downsampled_timescale);
|
||||||
if (finalize_m4a(m4af, ¶ms, encoder) < 0)
|
if (finalize_m4a(m4af, ¶ms, encoder) < 0)
|
||||||
|
@ -56,7 +56,8 @@ static tag_key_mapping_t tag_mapping_table[] = {
|
|||||||
{ "grouping", M4AF_TAG_GROUPING },
|
{ "grouping", M4AF_TAG_GROUPING },
|
||||||
{ "itunescompilation", M4AF_TAG_COMPILATION },
|
{ "itunescompilation", M4AF_TAG_COMPILATION },
|
||||||
{ "lyrics", M4AF_TAG_LYRICS },
|
{ "lyrics", M4AF_TAG_LYRICS },
|
||||||
{ "performer", M4AF_TAG_ARTIST },
|
{ "tempo", M4AF_TAG_TEMPO },
|
||||||
|
{ "recordeddate", M4AF_TAG_DATE },
|
||||||
{ "title", M4AF_TAG_TITLE },
|
{ "title", M4AF_TAG_TITLE },
|
||||||
{ "titlesort", M4AF_FOURCC('s','o','n','m') },
|
{ "titlesort", M4AF_FOURCC('s','o','n','m') },
|
||||||
{ "titlesortorder", M4AF_FOURCC('s','o','n','m') },
|
{ "titlesortorder", M4AF_FOURCC('s','o','n','m') },
|
||||||
|
Reference in New Issue
Block a user