summaryrefslogtreecommitdiff
path: root/libavcodec/aacenc.c
diff options
context:
space:
mode:
authorRostislav Pehlivanov <atomnuker@gmail.com>2016-10-03 19:53:11 +0100
committerRostislav Pehlivanov <atomnuker@gmail.com>2017-11-09 03:37:48 +0000
commitfbf295e2bd4d48d7a0a094ed5afce2fa5b6cf35a (patch)
tree8e9393646be34185894c56ad5beaf8308a8c1ca3 /libavcodec/aacenc.c
parent0a771e6b32429f9195d431415bf707c28ef31fff (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.c69
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}
};