X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=src%2Fmain.c;h=5fe46adb791cb5d65dfdeb4266e493d8ab4bbccd;hb=be234dc464159da366ec770fe8e5a958f317f7a9;hp=a1780704fce84a9589d192007ea7fed6d2e4d4b7;hpb=29a8f73fafe37beb8048316cca06ac83dfd1f2e1;p=fdkaac.git diff --git a/src/main.c b/src/main.c index a178070..5fe46ad 100644 --- a/src/main.c +++ b/src/main.c @@ -34,6 +34,7 @@ #endif #include "compat.h" #include "wav_reader.h" +#include "caf_reader.h" #include "aacenc.h" #include "m4af.h" #include "progress.h" @@ -132,10 +133,6 @@ PROGNAME " %s\n" " 0: Off\n" " 1: On(default)\n" " -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n" -" -s, --sbr-signaling 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 Transport format\n" " 0: RAW (default, muxed into M4A)\n" " 1: ADIF\n" @@ -152,7 +149,10 @@ PROGNAME " %s\n" " 0: iTunSMPB (default)\n" " 1: ISO standard (edts + sgpd)\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" " --moov-before-mdat Place moov box before mdat box on m4a output\n" "\n" @@ -207,6 +207,7 @@ typedef struct aacenc_param_ex_t { char *output_filename; FILE *output_fp; unsigned gapless_mode; + unsigned include_sbr_delay; unsigned ignore_length; int silent; int moov_before_mdat; @@ -217,6 +218,8 @@ typedef struct aacenc_param_ex_t { const char *raw_format; aacenc_tag_store_t tags; + aacenc_tag_store_t source_tags; + aacenc_translate_generic_text_tag_ctx_t source_tag_ctx; char *json_filename; } aacenc_param_ex_t; @@ -227,6 +230,7 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) int ch; 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_RAW_CHANNELS M4AF_FOURCC('r','c','h','n') #define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t') @@ -244,12 +248,12 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) { "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' }, { "gapless-mode", required_argument, 0, 'G' }, + { "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY }, { "ignorelength", no_argument, 0, 'I' }, { "silent", no_argument, 0, 'S' }, { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT }, @@ -323,13 +327,6 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) 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"); @@ -357,6 +354,9 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) } params->gapless_mode = n; break; + case OPT_INCLUDE_SBR_DELAY: + params->include_sbr_delay = 1; + break; case 'I': params->ignore_length = 1; break; @@ -570,11 +570,16 @@ int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params, HANDLE_AACENCODER encoder) { unsigned i; - aacenc_tag_entry_t *tag = params->tags.tag_table; + aacenc_tag_entry_t *tag; + + tag = params->source_tags.tag_table; + for (i = 0; i < params->source_tags.tag_count; ++i, ++tag) + aacenc_write_tag_entry(m4af, tag); if (params->json_filename) aacenc_write_tags_from_json(m4af, params->json_filename); + tag = params->tags.tag_table; for (i = 0; i < params->tags.tag_count; ++i, ++tag) aacenc_write_tag_entry(m4af, tag); @@ -661,7 +666,7 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) goto END; } 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) io.vtbl = &pcm_io_vtbl; else @@ -683,8 +688,27 @@ pcm_reader_t *open_input(aacenc_param_ex_t *params) goto END; } } else { - if ((reader = wav_open(&io, params->ignore_length)) == 0) { - fprintf(stderr, "ERROR: broken / unsupported input file\n"); + int c; + ungetc(c = getc(params->input_fp), params->input_fp); + + switch (c) { + case 'R': + if ((reader = wav_open(&io, params->ignore_length)) == 0) { + fprintf(stderr, "ERROR: broken / unsupported input file\n"); + goto END; + } + break; + case 'c': + params->source_tag_ctx.add = aacenc_add_tag_entry_to_store; + params->source_tag_ctx.add_ctx = ¶ms->source_tags; + if ((reader = caf_open(&io, + aacenc_translate_generic_text_tag, + ¶ms->source_tag_ctx)) == 0) { + fprintf(stderr, "ERROR: broken / unsupported input file\n"); + goto END; + } + break; + default: goto END; } } @@ -709,6 +733,7 @@ int main(int argc, char **argv) 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); @@ -721,6 +746,17 @@ int main(int argc, char **argv) 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; @@ -737,19 +773,21 @@ int main(int argc, char **argv) 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); @@ -762,9 +800,15 @@ int main(int argc, char **argv) goto END; if (m4af) { uint32_t delay = aacinfo.encoderDelay; + uint32_t padding; 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, padding >> downsampled_timescale); if (finalize_m4a(m4af, ¶ms, encoder) < 0) @@ -778,7 +822,10 @@ END: if (params.output_fp) fclose(params.output_fp); if (encoder) aacEncClose(&encoder); if (output_filename) free(output_filename); - if (params.tags.tag_table) aacenc_free_tag_store(¶ms.tags); + if (params.tags.tag_table) + aacenc_free_tag_store(¶ms.tags); + if (params.source_tags.tag_table) + aacenc_free_tag_store(¶ms.source_tags); return result; }