aacdec: Try to sniff a reasonable channel layout for PCE based configurations.
This changes the output order of multichannel PCE based streams.
This commit is contained in:
parent
e7d4a2a721
commit
37bed6ff3f
@ -263,9 +263,8 @@ typedef struct {
|
|||||||
* @name Channel element related data
|
* @name Channel element related data
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
enum ChannelPosition che_pos[4][MAX_ELEM_ID]; /**< channel element channel mapping with the
|
uint8_t layout_map[MAX_ELEM_ID*4][3];
|
||||||
* first index as the first 4 raw data block types
|
int layout_map_tags;
|
||||||
*/
|
|
||||||
ChannelElement *che[4][MAX_ELEM_ID];
|
ChannelElement *che[4][MAX_ELEM_ID];
|
||||||
ChannelElement *tag_che_map[4][MAX_ELEM_ID];
|
ChannelElement *tag_che_map[4][MAX_ELEM_ID];
|
||||||
int tags_mapped;
|
int tags_mapped;
|
||||||
|
@ -163,15 +163,14 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_channels(enum ChannelPosition che_pos[4][MAX_ELEM_ID])
|
static int count_channels(uint8_t (*layout)[3], int tags)
|
||||||
{
|
{
|
||||||
int i, type, sum = 0;
|
int i, sum = 0;
|
||||||
for (i = 0; i < MAX_ELEM_ID; i++) {
|
for (i = 0; i < tags; i++) {
|
||||||
for (type = 0; type < 4; type++) {
|
int syn_ele = layout[i][0];
|
||||||
sum += (1 + (type == TYPE_CPE)) *
|
int pos = layout[i][2];
|
||||||
(che_pos[type][i] != AAC_CHANNEL_OFF &&
|
sum += (1 + (syn_ele == TYPE_CPE)) *
|
||||||
che_pos[type][i] != AAC_CHANNEL_CC);
|
(pos != AAC_CHANNEL_OFF && pos != AAC_CHANNEL_CC);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
@ -213,30 +212,217 @@ static av_cold int che_configure(AACContext *ac,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct elem_to_channel {
|
||||||
|
uint64_t av_position;
|
||||||
|
uint8_t syn_ele;
|
||||||
|
uint8_t elem_id;
|
||||||
|
uint8_t aac_position;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int assign_pair(struct elem_to_channel e2c_vec[MAX_ELEM_ID],
|
||||||
|
uint8_t (*layout_map)[3], int offset, int tags, uint64_t left,
|
||||||
|
uint64_t right, int pos)
|
||||||
|
{
|
||||||
|
if (layout_map[offset][0] == TYPE_CPE) {
|
||||||
|
e2c_vec[offset] = (struct elem_to_channel) {
|
||||||
|
.av_position = left | right, .syn_ele = TYPE_CPE,
|
||||||
|
.elem_id = layout_map[offset ][1], .aac_position = pos };
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
e2c_vec[offset] = (struct elem_to_channel) {
|
||||||
|
.av_position = left, .syn_ele = TYPE_SCE,
|
||||||
|
.elem_id = layout_map[offset ][1], .aac_position = pos };
|
||||||
|
e2c_vec[offset + 1] = (struct elem_to_channel) {
|
||||||
|
.av_position = right, .syn_ele = TYPE_SCE,
|
||||||
|
.elem_id = layout_map[offset + 1][1], .aac_position = pos };
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int count_paired_channels(uint8_t (*layout_map)[3], int tags, int pos, int *current) {
|
||||||
|
int num_pos_channels = 0;
|
||||||
|
int first_cpe = 0;
|
||||||
|
int sce_parity = 0;
|
||||||
|
int i;
|
||||||
|
for (i = *current; i < tags; i++) {
|
||||||
|
if (layout_map[i][2] != pos)
|
||||||
|
break;
|
||||||
|
if (layout_map[i][0] == TYPE_CPE) {
|
||||||
|
if (sce_parity) {
|
||||||
|
if (pos == AAC_CHANNEL_FRONT || !first_cpe) {
|
||||||
|
sce_parity = 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_pos_channels += 2;
|
||||||
|
first_cpe = 1;
|
||||||
|
} else {
|
||||||
|
num_pos_channels++;
|
||||||
|
sce_parity ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sce_parity &&
|
||||||
|
((pos == AAC_CHANNEL_FRONT && first_cpe) || pos == AAC_CHANNEL_SIDE))
|
||||||
|
return -1;
|
||||||
|
*current = i;
|
||||||
|
return num_pos_channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags)
|
||||||
|
{
|
||||||
|
int i, n, total_non_cc_elements;
|
||||||
|
struct elem_to_channel e2c_vec[MAX_ELEM_ID] = {{ 0 }};
|
||||||
|
int num_front_channels, num_side_channels, num_back_channels;
|
||||||
|
uint64_t layout;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
num_front_channels =
|
||||||
|
count_paired_channels(layout_map, tags, AAC_CHANNEL_FRONT, &i);
|
||||||
|
if (num_front_channels < 0)
|
||||||
|
return 0;
|
||||||
|
num_side_channels =
|
||||||
|
count_paired_channels(layout_map, tags, AAC_CHANNEL_SIDE, &i);
|
||||||
|
if (num_side_channels < 0)
|
||||||
|
return 0;
|
||||||
|
num_back_channels =
|
||||||
|
count_paired_channels(layout_map, tags, AAC_CHANNEL_BACK, &i);
|
||||||
|
if (num_back_channels < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (num_front_channels & 1) {
|
||||||
|
e2c_vec[i] = (struct elem_to_channel) {
|
||||||
|
.av_position = AV_CH_FRONT_CENTER, .syn_ele = TYPE_SCE,
|
||||||
|
.elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_FRONT };
|
||||||
|
i++;
|
||||||
|
num_front_channels--;
|
||||||
|
}
|
||||||
|
if (num_front_channels >= 4) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
AV_CH_FRONT_LEFT_OF_CENTER,
|
||||||
|
AV_CH_FRONT_RIGHT_OF_CENTER,
|
||||||
|
AAC_CHANNEL_FRONT);
|
||||||
|
num_front_channels -= 2;
|
||||||
|
}
|
||||||
|
if (num_front_channels >= 2) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
AV_CH_FRONT_LEFT,
|
||||||
|
AV_CH_FRONT_RIGHT,
|
||||||
|
AAC_CHANNEL_FRONT);
|
||||||
|
num_front_channels -= 2;
|
||||||
|
}
|
||||||
|
while (num_front_channels >= 2) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
UINT64_MAX,
|
||||||
|
UINT64_MAX,
|
||||||
|
AAC_CHANNEL_FRONT);
|
||||||
|
num_front_channels -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_side_channels >= 2) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
AV_CH_SIDE_LEFT,
|
||||||
|
AV_CH_SIDE_RIGHT,
|
||||||
|
AAC_CHANNEL_FRONT);
|
||||||
|
num_side_channels -= 2;
|
||||||
|
}
|
||||||
|
while (num_side_channels >= 2) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
UINT64_MAX,
|
||||||
|
UINT64_MAX,
|
||||||
|
AAC_CHANNEL_SIDE);
|
||||||
|
num_side_channels -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (num_back_channels >= 4) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
UINT64_MAX,
|
||||||
|
UINT64_MAX,
|
||||||
|
AAC_CHANNEL_BACK);
|
||||||
|
num_back_channels -= 2;
|
||||||
|
}
|
||||||
|
if (num_back_channels >= 2) {
|
||||||
|
i += assign_pair(e2c_vec, layout_map, i, tags,
|
||||||
|
AV_CH_BACK_LEFT,
|
||||||
|
AV_CH_BACK_RIGHT,
|
||||||
|
AAC_CHANNEL_BACK);
|
||||||
|
num_back_channels -= 2;
|
||||||
|
}
|
||||||
|
if (num_back_channels) {
|
||||||
|
e2c_vec[i] = (struct elem_to_channel) {
|
||||||
|
.av_position = AV_CH_BACK_CENTER, .syn_ele = TYPE_SCE,
|
||||||
|
.elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_BACK };
|
||||||
|
i++;
|
||||||
|
num_back_channels--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) {
|
||||||
|
e2c_vec[i] = (struct elem_to_channel) {
|
||||||
|
.av_position = AV_CH_LOW_FREQUENCY, .syn_ele = TYPE_LFE,
|
||||||
|
.elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE };
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) {
|
||||||
|
e2c_vec[i] = (struct elem_to_channel) {
|
||||||
|
.av_position = UINT64_MAX, .syn_ele = TYPE_LFE,
|
||||||
|
.elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE };
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must choose a stable sort
|
||||||
|
total_non_cc_elements = n = i;
|
||||||
|
do {
|
||||||
|
int next_n = 0;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (e2c_vec[i-1].av_position > e2c_vec[i].av_position) {
|
||||||
|
FFSWAP(struct elem_to_channel, e2c_vec[i-1], e2c_vec[i]);
|
||||||
|
next_n = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = next_n;
|
||||||
|
} while (n > 0);
|
||||||
|
|
||||||
|
layout = 0;
|
||||||
|
for (i = 0; i < total_non_cc_elements; i++) {
|
||||||
|
layout_map[i][0] = e2c_vec[i].syn_ele;
|
||||||
|
layout_map[i][1] = e2c_vec[i].elem_id;
|
||||||
|
layout_map[i][2] = e2c_vec[i].aac_position;
|
||||||
|
if (e2c_vec[i].av_position != UINT64_MAX) {
|
||||||
|
layout |= e2c_vec[i].av_position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure output channel order based on the current program configuration element.
|
* Configure output channel order based on the current program configuration element.
|
||||||
*
|
*
|
||||||
* @param che_pos current channel position configuration
|
* @param che_pos current channel position configuration
|
||||||
* @param new_che_pos New channel position configuration - we only do something if it differs from the current one.
|
|
||||||
*
|
*
|
||||||
* @return Returns error status. 0 - OK, !0 - error
|
* @return Returns error status. 0 - OK, !0 - error
|
||||||
*/
|
*/
|
||||||
static av_cold int output_configure(AACContext *ac,
|
static av_cold int output_configure(AACContext *ac,
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID],
|
uint8_t layout_map[MAX_ELEM_ID*4][3], int tags,
|
||||||
int channel_config, enum OCStatus oc_type)
|
int channel_config, enum OCStatus oc_type)
|
||||||
{
|
{
|
||||||
AVCodecContext *avctx = ac->avctx;
|
AVCodecContext *avctx = ac->avctx;
|
||||||
int i, type, channels = 0, ret;
|
int i, channels = 0, ret;
|
||||||
|
|
||||||
if (new_che_pos)
|
if (ac->layout_map != layout_map) {
|
||||||
memcpy(ac->che_pos, new_che_pos, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
|
memcpy(ac->layout_map, layout_map, tags * sizeof(layout_map[0]));
|
||||||
|
ac->layout_map_tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
if (channel_config) {
|
if (channel_config) {
|
||||||
for (i = 0; i < tags_per_config[channel_config]; i++) {
|
for (i = 0; i < tags_per_config[channel_config]; i++) {
|
||||||
int id = aac_channel_layout_map[channel_config - 1][i][1];
|
int type = aac_channel_layout_map[channel_config - 1][i][0];
|
||||||
type = aac_channel_layout_map[channel_config - 1][i][0];
|
int id = aac_channel_layout_map[channel_config - 1][i][1];
|
||||||
if ((ret = che_configure(ac, ac->che_pos[type][id],
|
int positon = aac_channel_layout_map[channel_config - 1][i][2];
|
||||||
type, id, &channels)))
|
if ((ret = che_configure(ac, positon,
|
||||||
|
type, id,
|
||||||
|
&channels)))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,20 +433,24 @@ static av_cold int output_configure(AACContext *ac,
|
|||||||
/* Allocate or free elements depending on if they are in the
|
/* Allocate or free elements depending on if they are in the
|
||||||
* current program configuration.
|
* current program configuration.
|
||||||
*
|
*
|
||||||
* Set up default 1:1 output mapping.
|
* Try to sniff a reasonable channel order, otherwise output the
|
||||||
|
* channels in the order the PCE declared them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < MAX_ELEM_ID; i++) {
|
uint64_t layout = sniff_channel_order(layout_map, tags);
|
||||||
for (type = 0; type < 4; type++) {
|
for (i = 0; i < tags; i++) {
|
||||||
if ((ret = che_configure(ac, ac->che_pos[type][i],
|
int type = layout_map[i][0];
|
||||||
type, i, &channels)))
|
int id = layout_map[i][1];
|
||||||
return ret;
|
int position = layout_map[i][2];
|
||||||
}
|
if ((ret = che_configure(ac, position,
|
||||||
|
type, id,
|
||||||
|
&channels)))
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ac->tag_che_map, ac->che, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0]));
|
memcpy(ac->tag_che_map, ac->che, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0]));
|
||||||
|
|
||||||
avctx->channel_layout = 0;
|
avctx->channel_layout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
avctx->channels = channels;
|
avctx->channels = channels;
|
||||||
@ -277,30 +467,45 @@ static av_cold int output_configure(AACContext *ac,
|
|||||||
* @param sce_map mono (Single Channel Element) map
|
* @param sce_map mono (Single Channel Element) map
|
||||||
* @param type speaker type/position for these channels
|
* @param type speaker type/position for these channels
|
||||||
*/
|
*/
|
||||||
static void decode_channel_map(enum ChannelPosition *cpe_map,
|
static void decode_channel_map(uint8_t layout_map[][3],
|
||||||
enum ChannelPosition *sce_map,
|
|
||||||
enum ChannelPosition type,
|
enum ChannelPosition type,
|
||||||
GetBitContext *gb, int n)
|
GetBitContext *gb, int n)
|
||||||
{
|
{
|
||||||
while (n--) {
|
while (n--) {
|
||||||
enum ChannelPosition *map = cpe_map && get_bits1(gb) ? cpe_map : sce_map; // stereo or mono map
|
enum RawDataBlockType syn_ele;
|
||||||
map[get_bits(gb, 4)] = type;
|
switch (type) {
|
||||||
|
case AAC_CHANNEL_FRONT:
|
||||||
|
case AAC_CHANNEL_BACK:
|
||||||
|
case AAC_CHANNEL_SIDE:
|
||||||
|
syn_ele = get_bits1(gb);
|
||||||
|
break;
|
||||||
|
case AAC_CHANNEL_CC:
|
||||||
|
skip_bits1(gb);
|
||||||
|
syn_ele = TYPE_CCE;
|
||||||
|
break;
|
||||||
|
case AAC_CHANNEL_LFE:
|
||||||
|
syn_ele = TYPE_LFE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
layout_map[0][0] = syn_ele;
|
||||||
|
layout_map[0][1] = get_bits(gb, 4);
|
||||||
|
layout_map[0][2] = type;
|
||||||
|
layout_map++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode program configuration element; reference: table 4.2.
|
* Decode program configuration element; reference: table 4.2.
|
||||||
*
|
*
|
||||||
* @param new_che_pos New channel position configuration - we only do something if it differs from the current one.
|
|
||||||
*
|
|
||||||
* @return Returns error status. 0 - OK, !0 - error
|
* @return Returns error status. 0 - OK, !0 - error
|
||||||
*/
|
*/
|
||||||
static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID],
|
uint8_t (*layout_map)[3],
|
||||||
GetBitContext *gb)
|
GetBitContext *gb)
|
||||||
{
|
{
|
||||||
int num_front, num_side, num_back, num_lfe, num_assoc_data, num_cc, sampling_index;
|
int num_front, num_side, num_back, num_lfe, num_assoc_data, num_cc, sampling_index;
|
||||||
int comment_len;
|
int comment_len;
|
||||||
|
int tags;
|
||||||
|
|
||||||
skip_bits(gb, 2); // object_type
|
skip_bits(gb, 2); // object_type
|
||||||
|
|
||||||
@ -323,14 +528,19 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
|||||||
if (get_bits1(gb))
|
if (get_bits1(gb))
|
||||||
skip_bits(gb, 3); // mixdown_coeff_index and pseudo_surround
|
skip_bits(gb, 3); // mixdown_coeff_index and pseudo_surround
|
||||||
|
|
||||||
decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_FRONT, gb, num_front);
|
decode_channel_map(layout_map , AAC_CHANNEL_FRONT, gb, num_front);
|
||||||
decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_SIDE, gb, num_side );
|
tags = num_front;
|
||||||
decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_BACK, gb, num_back );
|
decode_channel_map(layout_map + tags, AAC_CHANNEL_SIDE, gb, num_side);
|
||||||
decode_channel_map(NULL, new_che_pos[TYPE_LFE], AAC_CHANNEL_LFE, gb, num_lfe );
|
tags += num_side;
|
||||||
|
decode_channel_map(layout_map + tags, AAC_CHANNEL_BACK, gb, num_back);
|
||||||
|
tags += num_back;
|
||||||
|
decode_channel_map(layout_map + tags, AAC_CHANNEL_LFE, gb, num_lfe);
|
||||||
|
tags += num_lfe;
|
||||||
|
|
||||||
skip_bits_long(gb, 4 * num_assoc_data);
|
skip_bits_long(gb, 4 * num_assoc_data);
|
||||||
|
|
||||||
decode_channel_map(new_che_pos[TYPE_CCE], new_che_pos[TYPE_CCE], AAC_CHANNEL_CC, gb, num_cc );
|
decode_channel_map(layout_map + tags, AAC_CHANNEL_CC, gb, num_cc);
|
||||||
|
tags += num_cc;
|
||||||
|
|
||||||
align_get_bits(gb);
|
align_get_bits(gb);
|
||||||
|
|
||||||
@ -341,19 +551,18 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
skip_bits_long(gb, comment_len);
|
skip_bits_long(gb, comment_len);
|
||||||
return 0;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up channel positions based on a default channel configuration
|
* Set up channel positions based on a default channel configuration
|
||||||
* as specified in table 1.17.
|
* as specified in table 1.17.
|
||||||
*
|
*
|
||||||
* @param new_che_pos New channel position configuration - we only do something if it differs from the current one.
|
|
||||||
*
|
|
||||||
* @return Returns error status. 0 - OK, !0 - error
|
* @return Returns error status. 0 - OK, !0 - error
|
||||||
*/
|
*/
|
||||||
static av_cold int set_default_channel_config(AVCodecContext *avctx,
|
static av_cold int set_default_channel_config(AVCodecContext *avctx,
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID],
|
uint8_t (*layout_map)[3],
|
||||||
|
int *tags,
|
||||||
int channel_config)
|
int channel_config)
|
||||||
{
|
{
|
||||||
if (channel_config < 1 || channel_config > 7) {
|
if (channel_config < 1 || channel_config > 7) {
|
||||||
@ -361,32 +570,8 @@ static av_cold int set_default_channel_config(AVCodecContext *avctx,
|
|||||||
channel_config);
|
channel_config);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
*tags = tags_per_config[channel_config];
|
||||||
/* default channel configurations:
|
memcpy(layout_map, aac_channel_layout_map[channel_config-1], *tags * sizeof(*layout_map));
|
||||||
*
|
|
||||||
* 1ch : front center (mono)
|
|
||||||
* 2ch : L + R (stereo)
|
|
||||||
* 3ch : front center + L + R
|
|
||||||
* 4ch : front center + L + R + back center
|
|
||||||
* 5ch : front center + L + R + back stereo
|
|
||||||
* 6ch : front center + L + R + back stereo + LFE
|
|
||||||
* 7ch : front center + L + R + outer front left + outer front right + back stereo + LFE
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (channel_config != 2)
|
|
||||||
new_che_pos[TYPE_SCE][0] = AAC_CHANNEL_FRONT; // front center (or mono)
|
|
||||||
if (channel_config > 1)
|
|
||||||
new_che_pos[TYPE_CPE][0] = AAC_CHANNEL_FRONT; // L + R (or stereo)
|
|
||||||
if (channel_config == 4)
|
|
||||||
new_che_pos[TYPE_SCE][1] = AAC_CHANNEL_BACK; // back center
|
|
||||||
if (channel_config > 4)
|
|
||||||
new_che_pos[TYPE_CPE][(channel_config == 7) + 1]
|
|
||||||
= AAC_CHANNEL_BACK; // back stereo
|
|
||||||
if (channel_config > 5)
|
|
||||||
new_che_pos[TYPE_LFE][0] = AAC_CHANNEL_LFE; // LFE
|
|
||||||
if (channel_config == 7)
|
|
||||||
new_che_pos[TYPE_CPE][1] = AAC_CHANNEL_FRONT; // outer front left + outer front right
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,8 +588,9 @@ static int decode_ga_specific_config(AACContext *ac, AVCodecContext *avctx,
|
|||||||
MPEG4AudioConfig *m4ac,
|
MPEG4AudioConfig *m4ac,
|
||||||
int channel_config)
|
int channel_config)
|
||||||
{
|
{
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID];
|
|
||||||
int extension_flag, ret;
|
int extension_flag, ret;
|
||||||
|
uint8_t layout_map[MAX_ELEM_ID*4][3];
|
||||||
|
int tags = 0;
|
||||||
|
|
||||||
if (get_bits1(gb)) { // frameLengthFlag
|
if (get_bits1(gb)) { // frameLengthFlag
|
||||||
av_log_missing_feature(avctx, "960/120 MDCT window is", 1);
|
av_log_missing_feature(avctx, "960/120 MDCT window is", 1);
|
||||||
@ -419,22 +605,23 @@ static int decode_ga_specific_config(AACContext *ac, AVCodecContext *avctx,
|
|||||||
m4ac->object_type == AOT_ER_AAC_SCALABLE)
|
m4ac->object_type == AOT_ER_AAC_SCALABLE)
|
||||||
skip_bits(gb, 3); // layerNr
|
skip_bits(gb, 3); // layerNr
|
||||||
|
|
||||||
memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
|
|
||||||
if (channel_config == 0) {
|
if (channel_config == 0) {
|
||||||
skip_bits(gb, 4); // element_instance_tag
|
skip_bits(gb, 4); // element_instance_tag
|
||||||
if ((ret = decode_pce(avctx, m4ac, new_che_pos, gb)))
|
tags = decode_pce(avctx, m4ac, layout_map, gb);
|
||||||
return ret;
|
if (tags < 0)
|
||||||
|
return tags;
|
||||||
} else {
|
} else {
|
||||||
if ((ret = set_default_channel_config(avctx, new_che_pos, channel_config)))
|
if ((ret = set_default_channel_config(avctx, layout_map, &tags, channel_config)))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count_channels(new_che_pos) > 1) {
|
if (count_channels(layout_map, tags) > 1) {
|
||||||
m4ac->ps = 0;
|
m4ac->ps = 0;
|
||||||
} else if (m4ac->sbr == 1 && m4ac->ps == -1)
|
} else if (m4ac->sbr == 1 && m4ac->ps == -1)
|
||||||
m4ac->ps = 1;
|
m4ac->ps = 1;
|
||||||
|
|
||||||
if (ac && (ret = output_configure(ac, new_che_pos, channel_config, OC_GLOBAL_HDR)))
|
if (ac && (ret = output_configure(ac, layout_map, tags,
|
||||||
|
channel_config, OC_GLOBAL_HDR)))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (extension_flag) {
|
if (extension_flag) {
|
||||||
@ -588,7 +775,8 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
|
|||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
int sr, i;
|
int sr, i;
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID];
|
uint8_t layout_map[MAX_ELEM_ID*4][3];
|
||||||
|
int layout_map_tags;
|
||||||
|
|
||||||
sr = sample_rate_idx(avctx->sample_rate);
|
sr = sample_rate_idx(avctx->sample_rate);
|
||||||
ac->m4ac.sampling_index = sr;
|
ac->m4ac.sampling_index = sr;
|
||||||
@ -605,9 +793,11 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
|
|||||||
ac->m4ac.chan_config = i;
|
ac->m4ac.chan_config = i;
|
||||||
|
|
||||||
if (ac->m4ac.chan_config) {
|
if (ac->m4ac.chan_config) {
|
||||||
int ret = set_default_channel_config(avctx, new_che_pos, ac->m4ac.chan_config);
|
int ret = set_default_channel_config(avctx, layout_map,
|
||||||
|
&layout_map_tags, ac->m4ac.chan_config);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
output_configure(ac, new_che_pos, ac->m4ac.chan_config, OC_GLOBAL_HDR);
|
output_configure(ac, layout_map, layout_map_tags,
|
||||||
|
ac->m4ac.chan_config, OC_GLOBAL_HDR);
|
||||||
else if (avctx->err_recognition & AV_EF_EXPLODE)
|
else if (avctx->err_recognition & AV_EF_EXPLODE)
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
@ -1711,7 +1901,8 @@ static int decode_extension_payload(AACContext *ac, GetBitContext *gb, int cnt,
|
|||||||
} else if (ac->m4ac.ps == -1 && ac->output_configured < OC_LOCKED && ac->avctx->channels == 1) {
|
} else if (ac->m4ac.ps == -1 && ac->output_configured < OC_LOCKED && ac->avctx->channels == 1) {
|
||||||
ac->m4ac.sbr = 1;
|
ac->m4ac.sbr = 1;
|
||||||
ac->m4ac.ps = 1;
|
ac->m4ac.ps = 1;
|
||||||
output_configure(ac, NULL, ac->m4ac.chan_config, ac->output_configured);
|
output_configure(ac, ac->layout_map, ac->layout_map_tags,
|
||||||
|
ac->m4ac.chan_config, ac->output_configured);
|
||||||
} else {
|
} else {
|
||||||
ac->m4ac.sbr = 1;
|
ac->m4ac.sbr = 1;
|
||||||
}
|
}
|
||||||
@ -2085,16 +2276,18 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb)
|
|||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
AACADTSHeaderInfo hdr_info;
|
AACADTSHeaderInfo hdr_info;
|
||||||
|
uint8_t layout_map[MAX_ELEM_ID*4][3];
|
||||||
|
int layout_map_tags;
|
||||||
|
|
||||||
size = avpriv_aac_parse_header(gb, &hdr_info);
|
size = avpriv_aac_parse_header(gb, &hdr_info);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (hdr_info.chan_config) {
|
if (hdr_info.chan_config) {
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID];
|
|
||||||
memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
|
|
||||||
ac->m4ac.chan_config = hdr_info.chan_config;
|
ac->m4ac.chan_config = hdr_info.chan_config;
|
||||||
if (set_default_channel_config(ac->avctx, new_che_pos, hdr_info.chan_config))
|
if (set_default_channel_config(ac->avctx, layout_map,
|
||||||
|
&layout_map_tags, hdr_info.chan_config))
|
||||||
return -7;
|
return -7;
|
||||||
if (output_configure(ac, new_che_pos, hdr_info.chan_config,
|
if (output_configure(ac, layout_map, layout_map_tags,
|
||||||
|
hdr_info.chan_config,
|
||||||
FFMAX(ac->output_configured, OC_TRIAL_FRAME)))
|
FFMAX(ac->output_configured, OC_TRIAL_FRAME)))
|
||||||
return -7;
|
return -7;
|
||||||
} else if (ac->output_configured != OC_LOCKED) {
|
} else if (ac->output_configured != OC_LOCKED) {
|
||||||
@ -2181,15 +2374,18 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_PCE: {
|
case TYPE_PCE: {
|
||||||
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID];
|
uint8_t layout_map[MAX_ELEM_ID*4][3];
|
||||||
memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
|
int tags;
|
||||||
if ((err = decode_pce(avctx, &ac->m4ac, new_che_pos, gb)))
|
tags = decode_pce(avctx, &ac->m4ac, layout_map, gb);
|
||||||
|
if (tags < 0) {
|
||||||
|
err = tags;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (ac->output_configured > OC_TRIAL_PCE)
|
if (ac->output_configured > OC_TRIAL_PCE)
|
||||||
av_log(avctx, AV_LOG_ERROR,
|
av_log(avctx, AV_LOG_ERROR,
|
||||||
"Not evaluating a further program_config_element as this construct is dubious at best.\n");
|
"Not evaluating a further program_config_element as this construct is dubious at best.\n");
|
||||||
else
|
else
|
||||||
err = output_configure(ac, new_che_pos, 0, OC_TRIAL_PCE);
|
err = output_configure(ac, layout_map, tags, 0, OC_TRIAL_PCE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,14 +80,14 @@ static const float * const tns_tmp2_map[4] = {
|
|||||||
|
|
||||||
static const int8_t tags_per_config[16] = { 0, 1, 1, 2, 3, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0 };
|
static const int8_t tags_per_config[16] = { 0, 1, 1, 2, 3, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
static const uint8_t aac_channel_layout_map[7][5][2] = {
|
static const uint8_t aac_channel_layout_map[7][5][3] = {
|
||||||
{ { TYPE_SCE, 0 }, },
|
{ { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, },
|
||||||
{ { TYPE_CPE, 0 }, },
|
{ { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, },
|
||||||
{ { TYPE_CPE, 0 }, { TYPE_SCE, 0 }, },
|
{ { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, },
|
||||||
{ { TYPE_CPE, 0 }, { TYPE_SCE, 0 }, { TYPE_SCE, 1 }, },
|
{ { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 1, AAC_CHANNEL_BACK }, },
|
||||||
{ { TYPE_CPE, 0 }, { TYPE_SCE, 0 }, { TYPE_CPE, 1 }, },
|
{ { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_BACK }, },
|
||||||
{ { TYPE_CPE, 0 }, { TYPE_SCE, 0 }, { TYPE_LFE, 0 }, { TYPE_CPE, 1 }, },
|
{ { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, { TYPE_CPE, 1, AAC_CHANNEL_BACK }, },
|
||||||
{ { TYPE_CPE, 1 }, { TYPE_SCE, 0 }, { TYPE_LFE, 0 }, { TYPE_CPE, 2 }, { TYPE_CPE, 0 }, },
|
{ { TYPE_CPE, 1, AAC_CHANNEL_FRONT }, { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, { TYPE_CPE, 2, AAC_CHANNEL_BACK }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint64_t aac_channel_layout[8] = {
|
static const uint64_t aac_channel_layout[8] = {
|
||||||
|
@ -8,15 +8,15 @@ fate-aac-al05_44: REF = $(SAMPLES)/aac/al05_44.s16
|
|||||||
|
|
||||||
FATE_AAC += fate-aac-al06_44
|
FATE_AAC += fate-aac-al06_44
|
||||||
fate-aac-al06_44: CMD = pcm -i $(SAMPLES)/aac/al06_44.mp4
|
fate-aac-al06_44: CMD = pcm -i $(SAMPLES)/aac/al06_44.mp4
|
||||||
fate-aac-al06_44: REF = $(SAMPLES)/aac/al06_44.s16
|
fate-aac-al06_44: REF = $(SAMPLES)/aac/al06_44_reorder.s16
|
||||||
|
|
||||||
FATE_AAC += fate-aac-al07_96
|
FATE_AAC += fate-aac-al07_96
|
||||||
fate-aac-al07_96: CMD = pcm -i $(SAMPLES)/aac/al07_96.mp4
|
fate-aac-al07_96: CMD = pcm -i $(SAMPLES)/aac/al07_96.mp4
|
||||||
fate-aac-al07_96: REF = $(SAMPLES)/aac/al07_96.s16
|
fate-aac-al07_96: REF = $(SAMPLES)/aac/al07_96_reorder.s16
|
||||||
|
|
||||||
FATE_AAC += fate-aac-al15_44
|
FATE_AAC += fate-aac-al15_44
|
||||||
fate-aac-al15_44: CMD = pcm -i $(SAMPLES)/aac/al15_44.mp4
|
fate-aac-al15_44: CMD = pcm -i $(SAMPLES)/aac/al15_44.mp4
|
||||||
fate-aac-al15_44: REF = $(SAMPLES)/aac/al15_44.s16
|
fate-aac-al15_44: REF = $(SAMPLES)/aac/al15_44_reorder.s16
|
||||||
|
|
||||||
FATE_AAC += fate-aac-al17_44
|
FATE_AAC += fate-aac-al17_44
|
||||||
fate-aac-al17_44: CMD = pcm -i $(SAMPLES)/aac/al17_44.mp4
|
fate-aac-al17_44: CMD = pcm -i $(SAMPLES)/aac/al17_44.mp4
|
||||||
@ -32,7 +32,7 @@ fate-aac-am00_88: REF = $(SAMPLES)/aac/am00_88.s16
|
|||||||
|
|
||||||
FATE_AAC += fate-aac-am05_44
|
FATE_AAC += fate-aac-am05_44
|
||||||
fate-aac-am05_44: CMD = pcm -i $(SAMPLES)/aac/am05_44.mp4
|
fate-aac-am05_44: CMD = pcm -i $(SAMPLES)/aac/am05_44.mp4
|
||||||
fate-aac-am05_44: REF = $(SAMPLES)/aac/am05_44.s16
|
fate-aac-am05_44: REF = $(SAMPLES)/aac/am05_44_reorder.s16
|
||||||
|
|
||||||
FATE_AAC += fate-aac-al_sbr_hq_cm_48_2
|
FATE_AAC += fate-aac-al_sbr_hq_cm_48_2
|
||||||
fate-aac-al_sbr_hq_cm_48_2: CMD = pcm -i $(SAMPLES)/aac/al_sbr_cm_48_2.mp4
|
fate-aac-al_sbr_hq_cm_48_2: CMD = pcm -i $(SAMPLES)/aac/al_sbr_cm_48_2.mp4
|
||||||
@ -40,7 +40,7 @@ fate-aac-al_sbr_hq_cm_48_2: REF = $(SAMPLES)/aac/al_sbr_hq_cm_48_2.s16
|
|||||||
|
|
||||||
FATE_AAC += fate-aac-al_sbr_hq_cm_48_5.1
|
FATE_AAC += fate-aac-al_sbr_hq_cm_48_5.1
|
||||||
fate-aac-al_sbr_hq_cm_48_5.1: CMD = pcm -i $(SAMPLES)/aac/al_sbr_cm_48_5.1.mp4
|
fate-aac-al_sbr_hq_cm_48_5.1: CMD = pcm -i $(SAMPLES)/aac/al_sbr_cm_48_5.1.mp4
|
||||||
fate-aac-al_sbr_hq_cm_48_5.1: REF = $(SAMPLES)/aac/al_sbr_hq_cm_48_5.1.s16
|
fate-aac-al_sbr_hq_cm_48_5.1: REF = $(SAMPLES)/aac/al_sbr_hq_cm_48_5.1_reorder.s16
|
||||||
|
|
||||||
FATE_AAC += fate-aac-al_sbr_ps_06_ur
|
FATE_AAC += fate-aac-al_sbr_ps_06_ur
|
||||||
fate-aac-al_sbr_ps_06_ur: CMD = pcm -i $(SAMPLES)/aac/al_sbr_ps_06_new.mp4
|
fate-aac-al_sbr_ps_06_ur: CMD = pcm -i $(SAMPLES)/aac/al_sbr_ps_06_new.mp4
|
||||||
|
Loading…
Reference in New Issue
Block a user