diff options
author | Rostislav Pehlivanov <atomnuker@gmail.com> | 2016-10-03 21:53:11 +0300 |
---|---|---|
committer | Rostislav Pehlivanov <atomnuker@gmail.com> | 2017-11-09 06:37:48 +0300 |
commit | fbf295e2bd4d48d7a0a094ed5afce2fa5b6cf35a (patch) | |
tree | 8e9393646be34185894c56ad5beaf8308a8c1ca3 /libavcodec/aacenc.c | |
parent | 0a771e6b32429f9195d431415bf707c28ef31fff (diff) |
aacenc: support extended channel layouts using PCEs
This commit implements support for PCE (Program Configuration Elements) in the
AAC encoder, and as such allows for encoding of channel layouts not present
in the presets defined by the spec (which only lists the 8 most common ones).
This has been a highly requested feature and is also the first open source encoder
to support this many layouts.
Many thanks to pkviet <pkv.stream@gmail.com> who implemented support for and
verified all channel layouts.
Diffstat (limited to 'libavcodec/aacenc.c')
-rw-r--r-- | libavcodec/aacenc.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 3efcbda403..51e467f754 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -50,6 +50,40 @@ static AVOnce aac_table_init = AV_ONCE_INIT; +static void put_pce(PutBitContext *pb, AVCodecContext *avctx) +{ + int i, j; + AACEncContext *s = avctx->priv_data; + AACPCEInfo *pce = &s->pce; + + put_bits(pb, 4, 0); + + put_bits(pb, 2, avctx->profile); + put_bits(pb, 4, s->samplerate_index); + + put_bits(pb, 4, pce->num_ele[0]); /* Front */ + put_bits(pb, 4, pce->num_ele[1]); /* Side */ + put_bits(pb, 4, pce->num_ele[2]); /* Back */ + put_bits(pb, 2, pce->num_ele[3]); /* LFE */ + put_bits(pb, 3, 0); /* Assoc data */ + put_bits(pb, 4, 0); /* CCs */ + + put_bits(pb, 1, 0); /* Stereo mixdown */ + put_bits(pb, 1, 0); /* Mono mixdown */ + put_bits(pb, 1, 0); /* Something else */ + + for (i = 0; i < 4; i++) { + for (j = 0; j < pce->num_ele[i]; j++) { + if (i < 3) + put_bits(pb, 1, pce->pairing[i][j]); + put_bits(pb, 4, pce->index[i][j]); + } + } + + avpriv_align_put_bits(pb); + put_bits(pb, 8, 0); +} + /** * Make AAC audio config object. * @see 1.6.2.1 "Syntax - AudioSpecificConfig" @@ -58,7 +92,7 @@ static void put_audio_specific_config(AVCodecContext *avctx) { PutBitContext pb; AACEncContext *s = avctx->priv_data; - int channels = s->channels - (s->channels == 8 ? 1 : 0); + int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); init_put_bits(&pb, avctx->extradata, avctx->extradata_size); put_bits(&pb, 5, s->profile+1); //profile @@ -68,6 +102,8 @@ static void put_audio_specific_config(AVCodecContext *avctx) put_bits(&pb, 1, 0); //frame length - 1024 samples put_bits(&pb, 1, 0); //does not depend on core coder put_bits(&pb, 1, 0); //is not extension + if (s->needs_pce) + put_pce(&pb, avctx); //Explicitly Mark SBR absent put_bits(&pb, 11, 0x2b7); //sync extension @@ -488,7 +524,7 @@ static void copy_input_samples(AACEncContext *s, const AVFrame *frame) { int ch; int end = 2048 + (frame ? frame->nb_samples : 0); - const uint8_t *channel_map = aac_chan_maps[s->channels - 1]; + const uint8_t *channel_map = s->reorder_map; /* copy and remap input samples */ for (ch = 0; ch < s->channels; ch++) { @@ -920,16 +956,36 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) /* Constants */ s->last_frame_pb_count = 0; - avctx->extradata_size = 5; + avctx->extradata_size = 20; avctx->frame_size = 1024; avctx->initial_padding = 1024; s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120; /* Channel map and unspecified bitrate guessing */ s->channels = avctx->channels; - ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7, - "Unsupported number of channels: %d\n", s->channels); - s->chan_map = aac_chan_configs[s->channels-1]; + + s->needs_pce = 1; + for (i = 0; i < FF_ARRAY_ELEMS(aac_normal_chan_layouts); i++) { + if (avctx->channel_layout == aac_normal_chan_layouts[i]) { + s->needs_pce = s->options.pce; + break; + } + } + + if (s->needs_pce) { + for (i = 0; i < FF_ARRAY_ELEMS(aac_pce_configs); i++) + if (avctx->channel_layout == aac_pce_configs[i].layout) + break; + ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout\n"); + av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout\n"); + s->pce = aac_pce_configs[i]; + s->reorder_map = s->pce.reorder_map; + s->chan_map = s->pce.config_map; + } else { + s->reorder_map = aac_chan_maps[s->channels - 1]; + s->chan_map = aac_chan_configs[s->channels - 1]; + } + if (!avctx->bit_rate) { for (i = 1; i <= s->chan_map[0]; i++) { avctx->bit_rate += s->chan_map[i] == TYPE_CPE ? 128000 : /* Pair */ @@ -1062,6 +1118,7 @@ static const AVOption aacenc_options[] = { {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, {NULL} }; |