X-Git-Url: https://git.sesse.net/?p=vlc;a=blobdiff_plain;f=modules%2Fcodec%2Flpcm.c;h=8e62b152d41ac8bfefbc15afed91464ab9fb135e;hp=74b3d366e586388f7b078318f72df25b8e2782cc;hb=3118165aefce584687fd67953e477fbbdf7e1bcb;hpb=152b1687c0ec112f3ab1360006d048d6b9cf7258 diff --git a/modules/codec/lpcm.c b/modules/codec/lpcm.c index 74b3d366e5..8e62b152d4 100644 --- a/modules/codec/lpcm.c +++ b/modules/codec/lpcm.c @@ -45,6 +45,12 @@ static int OpenDecoder ( vlc_object_t * ); static int OpenPacketizer( vlc_object_t * ); static void CloseCommon ( vlc_object_t * ); +#ifdef ENABLE_SOUT +static int OpenEncoder ( vlc_object_t * ); +static void CloseEncoder ( vlc_object_t * ); +static block_t *EncodeFrames( encoder_t *, aout_buffer_t * ); +#endif + vlc_module_begin () set_category( CAT_INPUT ) @@ -58,6 +64,14 @@ vlc_module_begin () set_capability( "packetizer", 100 ) set_callbacks( OpenPacketizer, CloseCommon ) +#ifdef ENABLE_SOUT + add_submodule () + set_description( N_("Linear PCM audio encoder") ) + set_capability( "encoder", 100 ) + set_callbacks( OpenEncoder, CloseEncoder ) + add_shortcut( "lpcm" ) +#endif + vlc_module_end () @@ -72,12 +86,25 @@ struct decoder_sys_t /* * Output properties */ - audio_date_t end_date; + date_t end_date; /* */ unsigned i_header_size; - bool b_dvd; + int i_type; +}; + +#ifdef ENABLE_SOUT +struct encoder_sys_t +{ + int i_channels; + int i_rate; + + int i_frame_samples; + uint8_t *p_buffer; + int i_buffer_used; + int i_frame_num; }; +#endif /* * LPCM DVD header : @@ -91,6 +118,18 @@ struct decoder_sys_t * - number of channels - 1 (3 bits) 1 == 2 channels * - start code (8 bits) == 0x80 * + * LPCM DVD-A header (http://dvd-audio.sourceforge.net/spec/aob.shtml) + * - continuity counter (8 bits, clipped to 0x00-0x1f) + * - header size (16 bits) + * - byte pointer to start of first audio frame. + * - unknown (8bits, 0x10 for stereo, 0x00 for surround) + * - sample size (4+4 bits) + * - samplerate (4+4 bits) + * - unknown (8 bits) + * - group assignment (8 bits) + * - unknown (8 bits) + * - padding(variable) + * * LPCM BD header : * - unkown (16 bits) * - number of channels (4 bits) @@ -99,19 +138,44 @@ struct decoder_sys_t * - unknown (6 bits) */ -#define LPCM_DVD_HEADER_LEN (6) +#define LPCM_VOB_HEADER_LEN (6) +#define LPCM_AOB_HEADER_LEN (11) #define LPCM_BD_HEADER_LEN (4) +enum +{ + LPCM_VOB, + LPCM_AOB, + LPCM_BD, +}; + +typedef struct +{ + unsigned i_channels; + bool b_used; + unsigned pi_position[6]; +} aob_group_t; + /***************************************************************************** * Local prototypes *****************************************************************************/ static void *DecodeFrame ( decoder_t *, block_t ** ); -static int DvdHeader( unsigned *pi_rate, + +/* */ +static int VobHeader( unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_original_channels, unsigned *pi_bits, const uint8_t *p_header ); -static void DvdExtract( aout_buffer_t *, block_t *, unsigned i_bits ); - +static void VobExtract( aout_buffer_t *, block_t *, unsigned i_bits ); +/* */ +static int AobHeader( unsigned *pi_rate, + unsigned *pi_channels, unsigned *pi_layout, + unsigned *pi_bits, + unsigned *pi_padding, + aob_group_t g[2], + const uint8_t *p_header ); +static void AobExtract( aout_buffer_t *, block_t *, unsigned i_bits, aob_group_t p_group[2] ); +/* */ static int BdHeader( unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_original_channels, unsigned *pi_bits, @@ -126,17 +190,25 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; - bool b_dvd; + int i_type; + int i_header_size; switch( p_dec->fmt_in.i_codec ) { /* DVD LPCM */ case VLC_CODEC_DVD_LPCM: - b_dvd = true; + i_type = LPCM_VOB; + i_header_size = LPCM_VOB_HEADER_LEN; + break; + /* DVD-Audio LPCM */ + case VLC_CODEC_DVDA_LPCM: + i_type = LPCM_AOB; + i_header_size = LPCM_AOB_HEADER_LEN; break; /* BD LPCM */ case VLC_CODEC_BD_LPCM: - b_dvd = false; + i_type = LPCM_BD; + i_header_size = LPCM_BD_HEADER_LEN; break; default: return VLC_EGENERIC; @@ -148,16 +220,29 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer ) /* Misc init */ p_sys->b_packetizer = b_packetizer; - aout_DateSet( &p_sys->end_date, 0 ); - p_sys->i_header_size = b_dvd ? LPCM_DVD_HEADER_LEN : LPCM_BD_HEADER_LEN; - p_sys->b_dvd = b_dvd; + date_Set( &p_sys->end_date, 0 ); + p_sys->i_type = i_type; + p_sys->i_header_size = i_header_size; /* Set output properties */ p_dec->fmt_out.i_cat = AUDIO_ES; if( b_packetizer ) { - p_dec->fmt_out.i_codec = b_dvd ? VLC_CODEC_DVD_LPCM : VLC_CODEC_BD_LPCM; + switch( i_type ) + { + case LPCM_VOB: + p_dec->fmt_out.i_codec = VLC_CODEC_DVD_LPCM; + break; + case LPCM_AOB: + p_dec->fmt_out.i_codec = VLC_CODEC_DVDA_LPCM; + break; + default: + assert(0); + case LPCM_BD: + p_dec->fmt_out.i_codec = VLC_CODEC_BD_LPCM; + break; + } } else { @@ -210,13 +295,13 @@ static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block ) *pp_block = NULL; /* So the packet doesn't get re-sent */ /* Date management */ - if( p_block->i_pts > 0 && - p_block->i_pts != aout_DateGet( &p_sys->end_date ) ) + if( p_block->i_pts > VLC_TS_INVALID && + p_block->i_pts != date_Get( &p_sys->end_date ) ) { - aout_DateSet( &p_sys->end_date, p_block->i_pts ); + date_Set( &p_sys->end_date, p_block->i_pts ); } - if( !aout_DateGet( &p_sys->end_date ) ) + if( !date_Get( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); @@ -231,16 +316,30 @@ static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block ) } int i_ret; - if( p_sys->b_dvd ) - i_ret = DvdHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, + unsigned i_padding = 0; + aob_group_t p_aob_group[2]; + switch( p_sys->i_type ) + { + case LPCM_VOB: + i_ret = VobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, p_block->p_buffer ); - else + break; + case LPCM_AOB: + i_ret = AobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, &i_padding, + p_aob_group, + p_block->p_buffer ); + break; + case LPCM_BD: i_ret = BdHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, p_block->p_buffer ); + break; + default: + abort(); + } - if( i_ret ) + if( i_ret || p_block->i_buffer <= p_sys->i_header_size + i_padding ) { - msg_Warn( p_dec, "no frame sync" ); + msg_Warn( p_dec, "no frame sync or too small frame" ); block_Release( p_block ); return NULL; } @@ -248,21 +347,21 @@ static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block ) /* Set output properties */ if( p_dec->fmt_out.audio.i_rate != i_rate ) { - aout_DateInit( &p_sys->end_date, i_rate ); - aout_DateSet( &p_sys->end_date, p_block->i_pts ); + date_Init( &p_sys->end_date, i_rate, 1 ); + date_Set( &p_sys->end_date, p_block->i_pts ); } p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_original_channels = i_original_channels; p_dec->fmt_out.audio.i_physical_channels = i_original_channels & AOUT_CHAN_PHYSMASK; - i_frame_length = (p_block->i_buffer - p_sys->i_header_size) / i_channels * 8 / i_bits; + i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) / i_channels * 8 / i_bits; if( p_sys->b_packetizer ) { - p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date ); + p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date ); p_block->i_length = - aout_DateIncrement( &p_sys->end_date, i_frame_length ) - + date_Increment( &p_sys->end_date, i_frame_length ) - p_block->i_pts; /* Just pass on the incoming frame */ @@ -288,17 +387,28 @@ static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block ) if( !p_aout_buffer ) return NULL; - p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date ); - p_aout_buffer->end_date = - aout_DateIncrement( &p_sys->end_date, i_frame_length ); + p_aout_buffer->i_pts = date_Get( &p_sys->end_date ); + p_aout_buffer->i_length = + date_Increment( &p_sys->end_date, i_frame_length ) + - p_aout_buffer->i_pts; - p_block->p_buffer += p_sys->i_header_size; - p_block->i_buffer -= p_sys->i_header_size; + p_block->p_buffer += p_sys->i_header_size + i_padding; + p_block->i_buffer -= p_sys->i_header_size + i_padding; - if( p_sys->b_dvd ) - DvdExtract( p_aout_buffer, p_block, i_bits ); - else + switch( p_sys->i_type ) + { + case LPCM_VOB: + VobExtract( p_aout_buffer, p_block, i_bits ); + break; + case LPCM_AOB: + AobExtract( p_aout_buffer, p_block, i_bits, p_aob_group ); + break; + default: + assert(0); + case LPCM_BD: BdExtract( p_aout_buffer, p_block ); + break; + } block_Release( p_block ); return p_aout_buffer; @@ -314,10 +424,149 @@ static void CloseCommon( vlc_object_t *p_this ) free( p_dec->p_sys ); } +#ifdef ENABLE_SOUT +/***************************************************************************** + * OpenEncoder: lpcm encoder construction + *****************************************************************************/ +static int OpenEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys; + + /* We only support DVD LPCM yet. */ + if( p_enc->fmt_out.i_codec != VLC_CODEC_DVD_LPCM || + ( p_enc->fmt_in.audio.i_rate != 48000 && + p_enc->fmt_in.audio.i_rate != 96000 && + p_enc->fmt_in.audio.i_rate != 44100 && + p_enc->fmt_in.audio.i_rate != 32000 ) || + p_enc->fmt_in.audio.i_channels > 8 ) + return VLC_EGENERIC; + + /* Allocate the memory needed to store the encoder's structure */ + if( ( p_enc->p_sys = p_sys = + (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL ) + return VLC_ENOMEM; + + /* In DVD LCPM, a frame is always 150 PTS ticks. */ + p_sys->i_frame_samples = p_enc->fmt_in.audio.i_rate * 150 / 90000; + p_sys->p_buffer = (uint8_t *)malloc( + p_sys->i_frame_samples * + p_enc->fmt_in.audio.i_channels * + p_enc->fmt_in.audio.i_bitspersample); + p_sys->i_buffer_used = 0; + p_sys->i_frame_num = 0; + + p_sys->i_channels = p_enc->fmt_in.audio.i_channels; + p_sys->i_rate = p_enc->fmt_in.audio.i_rate; + + p_enc->pf_encode_audio = EncodeFrames; + p_enc->fmt_in.i_codec = p_enc->fmt_out.i_codec; + + p_enc->fmt_in.audio.i_bitspersample = 16; + p_enc->fmt_in.i_codec = VLC_CODEC_S16B; + + p_enc->fmt_out.i_bitrate = + p_enc->fmt_in.audio.i_channels * + p_enc->fmt_in.audio.i_rate * + p_enc->fmt_in.audio.i_bitspersample * + (p_sys->i_frame_samples + LPCM_VOB_HEADER_LEN) / + p_sys->i_frame_samples; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * CloseEncoder: lpcm encoder destruction + *****************************************************************************/ +static void CloseEncoder ( vlc_object_t *p_this ) +{ + VLC_UNUSED(p_this); +} + +/***************************************************************************** + * EncodeFrames: encode zero or more LCPM audio packets + *****************************************************************************/ +static block_t *EncodeFrames( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + block_t *p_first_block = NULL, *p_last_block = NULL; + + if( !p_aout_buf || !p_aout_buf->i_buffer ) return NULL; + + const int i_num_frames = ( p_sys->i_buffer_used + p_aout_buf->i_nb_samples ) / + p_sys->i_frame_samples; + const int i_leftover_samples = ( p_sys->i_buffer_used + p_aout_buf->i_nb_samples ) % + p_sys->i_frame_samples; + const int i_frame_size = p_sys->i_frame_samples * p_sys->i_channels * 2 + LPCM_VOB_HEADER_LEN; + const int i_start_offset = -p_sys->i_buffer_used; + + uint8_t i_freq_code = 0; + + switch( p_sys->i_rate ) { + case 48000: + i_freq_code = 0; + break; + case 96000: + i_freq_code = 1; + break; + case 44100: + i_freq_code = 2; + break; + case 32000: + i_freq_code = 3; + break; + } + + int i_bytes_consumed = 0; + + for ( int i = 0; i < i_num_frames; ++i ) + { + block_t *p_block = block_New( p_enc, i_frame_size ); + if( !p_block ) + return NULL; + + uint8_t *frame = (uint8_t *)p_block->p_buffer; + frame[0] = 1; /* one frame in packet */ + frame[1] = 0; + frame[2] = 0; /* no first access unit */ + frame[3] = (p_sys->i_frame_num + i) & 0x1f; /* no emphasis, no mute */ + frame[4] = (i_freq_code << 4) | (p_sys->i_channels - 1); + frame[5] = 0x80; /* neutral dynamic range */ + + const int i_consume_samples = p_sys->i_frame_samples - p_sys->i_buffer_used; + const int i_kept_bytes = p_sys->i_buffer_used * p_sys->i_channels * 2; + const int i_consume_bytes = i_consume_samples * p_sys->i_channels * 2; + + memcpy( frame + 6, p_sys->p_buffer, i_kept_bytes ); + memcpy( frame + 6 + i_kept_bytes, p_aout_buf->p_buffer + i_bytes_consumed, i_consume_bytes ); + + p_sys->i_frame_num++; + p_sys->i_buffer_used = 0; + i_bytes_consumed += i_consume_bytes; + + p_block->i_dts = p_block->i_pts = p_aout_buf->i_pts + + (i * p_sys->i_frame_samples + i_start_offset) * CLOCK_FREQ / p_sys->i_rate; + p_block->i_length = p_sys->i_frame_samples * CLOCK_FREQ / p_sys->i_rate; + + if( !p_first_block ) + p_first_block = p_last_block = p_block; + else + p_last_block = p_last_block->p_next = p_block; + } + + memcpy( p_sys->p_buffer, + p_aout_buf->p_buffer + i_bytes_consumed, + i_leftover_samples * p_sys->i_channels * 2 ); + p_sys->i_buffer_used = i_leftover_samples; + + return p_first_block; +} +#endif + /***************************************************************************** * *****************************************************************************/ -static int DvdHeader( unsigned *pi_rate, +static int VobHeader( unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_original_channels, unsigned *pi_bits, const uint8_t *p_header ) @@ -401,6 +650,146 @@ static int DvdHeader( unsigned *pi_rate, return -1; return 0; } + +static const unsigned p_aob_group1[21][6] = { + { AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, +}; +static const unsigned p_aob_group2[21][6] = { + { 0 }, + { 0 }, + { AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_LFE, 0 }, + { AOUT_CHAN_LFE, AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_LFE, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_LFE, AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_LFE, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_LFE, 0 }, + { AOUT_CHAN_LFE, AOUT_CHAN_REARCENTER, 0 }, + { AOUT_CHAN_LFE, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }, + { AOUT_CHAN_LFE, 0 }, + { AOUT_CHAN_CENTER, 0 }, + { AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 }, +}; + +static int AobHeader( unsigned *pi_rate, + unsigned *pi_channels, unsigned *pi_layout, + unsigned *pi_bits, + unsigned *pi_padding, + aob_group_t g[2], + const uint8_t *p_header ) +{ + const unsigned i_header_size = GetWBE( &p_header[1] ); + if( i_header_size + 3 < LPCM_AOB_HEADER_LEN ) + return VLC_EGENERIC; + + *pi_padding = 3+i_header_size - LPCM_AOB_HEADER_LEN; + + const int i_index_size_g1 = (p_header[6] >> 4) & 0x0f; + const int i_index_size_g2 = (p_header[6] ) & 0x0f; + const int i_index_rate_g1 = (p_header[7] >> 4) & 0x0f; + const int i_index_rate_g2 = (p_header[7] ) & 0x0f; + const int i_assignment = p_header[9]; + + /* Validate */ + if( i_index_size_g1 > 0x02 || + ( i_index_size_g2 != 0x0f && i_index_size_g2 > 0x02 ) ) + return VLC_EGENERIC; + if( (i_index_rate_g1 & 0x07) > 0x02 || + ( i_index_rate_g2 != 0x0f && (i_index_rate_g1 & 0x07) > 0x02 ) ) + return VLC_EGENERIC; + if( i_assignment > 20 ) + return VLC_EGENERIC; + + /* */ + *pi_bits = 16 + 4 * i_index_size_g1; + if( i_index_rate_g1 & 0x08 ) + *pi_rate = 44100 << (i_index_rate_g1 & 0x07); + else + *pi_rate = 48000 << (i_index_rate_g1 & 0x07); + + + /* Group1 */ + unsigned i_channels1 = 0; + unsigned i_layout1 = 0; + for( int i = 0; p_aob_group1[i_assignment][i] != 0; i++ ) + { + i_channels1++; + i_layout1 |= p_aob_group1[i_assignment][i]; + } + /* Group2 */ + unsigned i_channels2 = 0; + unsigned i_layout2 = 0; + if( i_index_size_g2 != 0x0f && i_index_rate_g2 != 0x0f ) + { + for( int i = 0; p_aob_group2[i_assignment][i] != 0; i++ ) + { + i_channels2++; + i_layout2 |= p_aob_group2[i_assignment][i]; + } + 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 ); + + /* */ + for( unsigned i = 0; i < 2; i++ ) + { + const unsigned *p_aob = i == 0 ? p_aob_group1[i_assignment] : + p_aob_group2[i_assignment]; + g[i].i_channels = i == 0 ? i_channels1 : + i_channels2; + + g[i].b_used = i == 0 || b_group2_used; + if( !g[i].b_used ) + continue; + for( unsigned j = 0; j < g[i].i_channels; j++ ) + { + g[i].pi_position[j] = 0; + for( int k = 0; pi_vlc_chan_order_wg4[k] != 0; k++ ) + { + const unsigned i_channel = pi_vlc_chan_order_wg4[k]; + if( i_channel == p_aob[j] ) + break; + if( (*pi_layout) & i_channel ) + g[i].pi_position[j]++; + } + } + } + return VLC_SUCCESS; +} + static int BdHeader( unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_original_channels, unsigned *pi_bits, @@ -492,7 +881,7 @@ static int BdHeader( unsigned *pi_rate, return 0; } -static void DvdExtract( aout_buffer_t *p_aout_buffer, block_t *p_block, +static void VobExtract( aout_buffer_t *p_aout_buffer, block_t *p_block, unsigned i_bits ) { uint8_t *p_out = p_aout_buffer->p_buffer; @@ -556,9 +945,66 @@ static void DvdExtract( aout_buffer_t *p_aout_buffer, block_t *p_block, memcpy( p_out, p_block->p_buffer, p_block->i_buffer ); } } +static void AobExtract( aout_buffer_t *p_aout_buffer, + block_t *p_block, unsigned i_bits, 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; + + 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; + + if( p_block->i_buffer < i_group_size ) + { + p_block->i_buffer = 0; + break; + } + for( unsigned n = 0; n < 2; n++ ) + { + for( unsigned j = 0; j < g->i_channels && g->b_used; j++ ) + { + const int i_src = n * g->i_channels + j; + const int i_dst = n * i_channels + g->pi_position[j]; + + if( 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]; + } + else if( 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; + } + else + { + assert( i_bits == 16 ); + p_out[2*i_dst+0] = p_block->p_buffer[2*i_src+0]; + p_out[2*i_dst+1] = p_block->p_buffer[2*i_src+1]; + } + } + } + + p_block->i_buffer -= i_group_size; + p_block->p_buffer += i_group_size; + } + /* */ + p_out += (i_bits == 16 ? 2 : 3) * i_channels * 2; + + } +} static void BdExtract( aout_buffer_t *p_aout_buffer, block_t *p_block ) { memcpy( p_aout_buffer->p_buffer, p_block->p_buffer, p_block->i_buffer ); } -