Commit df48e0ee authored by Francois Cartegnie's avatar Francois Cartegnie

demux: lpcm: fix AOB decoding (fix #11936)

Fixes endianness and aout 16/32 bits.
AOB channels are split into 2 groups, with only one
that might be in use. They both can differ in
resolution and sampling rate.
We have to set output buffer to max bits of those two
and adapt reads accordingly to each group.
We'll reject only different group sampling rates
(missing spec about interleaving).
parent e85242dd
......@@ -171,7 +171,7 @@ enum
typedef struct
{
unsigned i_channels;
bool b_used;
unsigned i_bits;
unsigned pi_position[6];
} aob_group_t;
......@@ -393,8 +393,19 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
p_dec->fmt_out.audio.i_original_channels = i_original_channels;
p_dec->fmt_out.audio.i_physical_channels = i_original_channels;
if ( p_sys->i_type == LPCM_AOB )
{
i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) /
(
( (p_aob_group[0].i_bits / 8) * p_aob_group[0].i_channels ) +
( (p_aob_group[1].i_bits / 8) * p_aob_group[1].i_channels )
);
}
else
{
i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) /
(i_channels + i_channels_padding) * 8 / i_bits;
}
if( p_sys->b_packetizer )
{
......@@ -801,7 +812,25 @@ static int AobHeader( unsigned *pi_rate,
return VLC_EGENERIC;
/* */
*pi_bits = 16 + 4 * i_index_size_g1;
/* max is 0x2, 0xf == unused */
g[0].i_bits = ( i_index_size_g1 != 0x0f ) ? 16 + 4 * i_index_size_g1 : 0;
g[1].i_bits = ( i_index_size_g2 != 0x0f ) ? 16 + 4 * i_index_size_g2 : 0;
/* No info about interlacing of different sampling rate */
if ( g[1].i_bits && ( i_index_rate_g1 != i_index_rate_g2 ) )
return VLC_EGENERIC;
/* only set 16bits if both are <= */
if( g[0].i_bits )
{
if( g[0].i_bits > 16 || g[1].i_bits > 16 )
*pi_bits = 32;
else
*pi_bits = 16;
}
else
return VLC_EGENERIC;
if( i_index_rate_g1 & 0x08 )
*pi_rate = 44100 << (i_index_rate_g1 & 0x07);
else
......@@ -828,13 +857,10 @@ static int AobHeader( unsigned *pi_rate,
}
assert( (i_layout1 & i_layout2) == 0 );
}
/* It is enabled only when presents and compatible wih group1 */
const bool b_group2_used = i_index_size_g1 == i_index_size_g2 &&
i_index_rate_g1 == i_index_rate_g2;
/* */
*pi_channels = i_channels1 + ( b_group2_used ? i_channels2 : 0 );
*pi_layout = i_layout1 | ( b_group2_used ? i_layout2 : 0 );
*pi_channels = i_channels1 + ( g[1].i_bits ? i_channels2 : 0 );
*pi_layout = i_layout1 | ( g[1].i_bits ? i_layout2 : 0 );
/* */
for( unsigned i = 0; i < 2; i++ )
......@@ -844,8 +870,7 @@ static int AobHeader( unsigned *pi_rate,
g[i].i_channels = i == 0 ? i_channels1 :
i_channels2;
g[i].b_used = i == 0 || b_group2_used;
if( !g[i].b_used )
if( !g[i].i_bits )
continue;
for( unsigned j = 0; j < g[i].i_channels; j++ )
{
......@@ -1102,62 +1127,93 @@ static void VobExtract( block_t *p_aout_buffer, block_t *p_block,
#endif
}
}
static void AobExtract( block_t *p_aout_buffer,
block_t *p_block, unsigned i_bits, aob_group_t p_group[2] )
block_t *p_block, unsigned i_aoutbits, aob_group_t p_group[2] )
{
const unsigned i_channels = p_group[0].i_channels +
( p_group[1].b_used ? p_group[1].i_channels : 0 );
uint8_t *p_out = p_aout_buffer->p_buffer;
const unsigned i_total_channels = p_group[0].i_channels +
( p_group[1].i_bits ? p_group[1].i_channels : 0 );
while( p_block->i_buffer > 0 )
{
for( int i = 0; i < 2; i++ )
{
const aob_group_t *g = &p_group[1-i];
const unsigned int i_group_size = 2 * g->i_channels * i_bits / 8;
const unsigned int i_group_size = 2 * g->i_channels * g->i_bits / 8;
if( p_block->i_buffer < i_group_size )
{
p_block->i_buffer = 0;
break;
}
if( !g->i_bits )
continue;
unsigned int i_aout_written = 0;
for( unsigned n = 0; n < 2; n++ )
{
for( unsigned j = 0; j < g->i_channels && g->b_used; j++ )
for( unsigned j = 0; j < g->i_channels; j++ )
{
const int i_src = n * g->i_channels + j;
const int i_dst = n * i_channels + g->pi_position[j];
const int i_dst = n * i_total_channels + g->pi_position[j];
uint32_t *p_out32 = (uint32_t *) &p_out[4*i_dst];
if( i_bits == 24 )
if( g->i_bits == 24 )
{
p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
p_out[3*i_dst+2] = p_block->p_buffer[4*g->i_channels+i_src];
assert( i_aoutbits == 32 );
*p_out32 = (p_block->p_buffer[2*i_src+0] << 24)
| (p_block->p_buffer[2*i_src+1] << 16)
| (p_block->p_buffer[4*g->i_channels+i_src] << 8);
#ifdef WORDS_BIGENDIAN
*p_out32 = bswap32(*p_out32);
#endif
i_aout_written += 4;
}
else if( i_bits == 20 )
else if( g->i_bits == 20 )
{
p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
if( n == 0 )
p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src] ) & 0xf0;
else
p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src] << 4) & 0xf0;
assert( i_aoutbits == 32 );
*p_out32 = (p_block->p_buffer[2*i_src+0] << 24)
| (p_block->p_buffer[2*i_src+1] << 16)
| (((p_block->p_buffer[4*g->i_channels+i_src] << ((!n)?0:4) ) & 0xf0) << 8);
#ifdef WORDS_BIGENDIAN
*p_out32 = bswap32(*p_out32);
#endif
i_aout_written += 4;
}
else
{
assert( i_bits == 16 );
/* Big Endian -> Little Endian */
assert( g->i_bits == 16 );
assert( i_aoutbits == 16 || i_aoutbits == 32 );
if( i_aoutbits == 16 )
{
#ifdef WORDS_BIGENDIAN
memcpy( &p_out[2*i_dst], &p_block->p_buffer[2*i_src], 2 );
#else
p_out[2*i_dst+1] = p_block->p_buffer[2*i_src+0];
p_out[2*i_dst+0] = p_block->p_buffer[2*i_src+1];
#endif
i_aout_written += 2;
}
else
{
*p_out32 = (p_block->p_buffer[2*i_src+0] << 24)
| (p_block->p_buffer[2*i_src+1] << 16);
#ifdef WORDS_BIGENDIAN
*p_out32 = bswap32(*p_out32);
#endif
i_aout_written += 4;
}
}
}
}
/* */
p_out += i_aout_written;
p_block->i_buffer -= i_group_size;
p_block->p_buffer += i_group_size;
}
/* */
p_out += (i_bits == 16 ? 2 : 3) * i_channels * 2;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment