diff options
Diffstat (limited to 'src/libac3')
-rw-r--r-- | src/libac3/ac3.h | 6 | ||||
-rw-r--r-- | src/libac3/decode.c | 35 | ||||
-rw-r--r-- | src/libac3/downmix.c | 255 | ||||
-rw-r--r-- | src/libac3/downmix.h | 3 | ||||
-rw-r--r-- | src/libac3/xine_decoder.c | 121 |
5 files changed, 350 insertions, 70 deletions
diff --git a/src/libac3/ac3.h b/src/libac3/ac3.h index 07f41c0a0..69c11b9ed 100644 --- a/src/libac3/ac3.h +++ b/src/libac3/ac3.h @@ -40,10 +40,12 @@ typedef struct ac3_config_s typedef struct ac3_frame_s { - uint32_t sampling_rate; + uint32_t sampling_rate; int16_t * audio_data; + int num_channels; } ac3_frame_t; void ac3_init(void); int ac3_frame_length(uint8_t * buf); -ac3_frame_t* ac3_decode_frame(uint8_t * buf); +int ac3_sampling_rate(uint8_t * buf); +ac3_frame_t* ac3_decode_frame(uint8_t * buf, int max_num_channels); diff --git a/src/libac3/decode.c b/src/libac3/decode.c index db0068b8d..c859525e8 100644 --- a/src/libac3/decode.c +++ b/src/libac3/decode.c @@ -53,9 +53,9 @@ static ac3_frame_t frame; //the floating point samples for one audblk static stream_samples_t samples; -//the integer samples for the entire frame (with enough space for 2 ch out) +//the integer samples for the entire frame (with enough space for 5 ch out) //if this size change, be sure to change the size when muting -static int16_t s16_samples[2 * 6 * 256]; +static int16_t s16_samples[5 * 6 * 256]; void ac3_init(void) @@ -73,11 +73,20 @@ int ac3_frame_length(uint8_t * buf) return parse_syncinfo (buf, &dummy, &dummy); } +int ac3_sampling_rate(uint8_t * buf) +{ + int dummy, rate; + + parse_syncinfo (buf, &rate, &dummy); + return rate; +} + ac3_frame_t* -ac3_decode_frame(uint8_t * buf) +ac3_decode_frame(uint8_t * buf, int max_num_channels) { uint32_t i; int dummy; + int num_channels; if (!parse_syncinfo (buf, &frame.sampling_rate, &dummy)) goto error; @@ -87,6 +96,22 @@ ac3_decode_frame(uint8_t * buf) if (parse_bsi (&state, buf)) goto error; + switch (state.acmod) { + case 7 : + case 5 : + /* case 3 : FIXME : implement downmix functions*/ + num_channels = (max_num_channels<5) ? max_num_channels : 5; + break; + case 4 : + case 6 : + num_channels = (max_num_channels<4) ? max_num_channels : 4; + break; + default: + num_channels = 2; + } + + frame.num_channels = num_channels; + if (!done_banner) { stats_print_banner (&state); done_banner = 1; @@ -118,13 +143,15 @@ ac3_decode_frame(uint8_t * buf) // Downmix into the requested number of channels // and convert floating point to int16_t - downmix(&state,samples,&s16_samples[i * 2 * 256]); + downmix(&state,samples,&s16_samples[i * num_channels * 256], + num_channels); sanity_check(&state,&audblk); if(error_flag) goto error; } + return &frame; error: diff --git a/src/libac3/downmix.c b/src/libac3/downmix.c index a50b045be..fd801308d 100644 --- a/src/libac3/downmix.c +++ b/src/libac3/downmix.c @@ -42,6 +42,54 @@ static float cmixlev_lut[4] = { 0.2928, 0.2468, 0.2071, 0.2468 }; static float smixlev_lut[4] = { 0.2928, 0.2071, 0.0 , 0.2071 }; static void +downmix_3f_2r_to_5ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + left_sur = samples[3]; + right_sur = samples[4]; + + for (j = 0; j < 256; j++) + { + s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f); + s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f); + s16_samples[j * 5 + 2] = (int16_t) (*left_sur++ * 32767.0f); + s16_samples[j * 5 + 3] = (int16_t) (*right_sur++ * 32767.0f); + s16_samples[j * 5 + 4] = (int16_t) (*centre++ * 32767.0f); + } +} + +static void +downmix_3f_2r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float right_tmp; + float left_tmp; + float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + left_sur = samples[3]; + right_sur = samples[4]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.5000f * *left++ + 0.500f * *centre ; + right_tmp= 0.5000f * *right++ + 0.500f * *centre++ ; + + s16_samples[j * 4 ] = (int16_t) (left_tmp * 32767.0f); + s16_samples[j * 4 + 1] = (int16_t) (right_tmp * 32767.0f); + s16_samples[j * 4 + 2] = (int16_t) (*left_sur++ * 32767.0f); + s16_samples[j * 4 + 3] = (int16_t) (*right_sur++ * 32767.0f); + } +} + +static void downmix_3f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) { uint32_t j; @@ -70,6 +118,29 @@ downmix_3f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_ } static void +downmix_2f_2r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float slev; + float *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; + + left = samples[0]; + right = samples[1]; + left_sur = samples[2]; + right_sur = samples[3]; + + slev = smixlev_lut[state->surmixlev]; + + for (j = 0; j < 256; j++) + { + s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f); + s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f); + s16_samples[j * 5 + 2] = (int16_t) (*left_sur++ * 32767.0f); + s16_samples[j * 5 + 3] = (int16_t) (*right_sur++ * 32767.0f); + } +} + +static void downmix_2f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) { uint32_t j; @@ -96,6 +167,58 @@ downmix_2f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_ } static void +downmix_3f_1r_to_5ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float *centre = 0, *left = 0, *right = 0, *sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + //Mono surround + sur = samples[3]; + + for (j = 0; j < 256; j++) + { + s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f); + s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f); + s16_samples[j * 5 + 2] = (int16_t) (*sur * 32767.0f); + s16_samples[j * 5 + 3] = (int16_t) (*sur++ * 32767.0f); + s16_samples[j * 5 + 4] = (int16_t) (*centre++ * 32767.0f); + } +} + +static void +downmix_3f_1r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float right_tmp; + float left_tmp; + float clev,slev; + float *centre = 0, *left = 0, *right = 0, *sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + //Mono surround + sur = samples[3]; + + clev = cmixlev_lut[state->cmixlev]; + slev = smixlev_lut[state->surmixlev]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.5000f * *left++ + 0.500f * *centre ; + right_tmp= 0.5000f * *right++ + 0.500f * *centre++ ; + + s16_samples[j * 4 ] = (int16_t) (left_tmp * 32767.0f); + s16_samples[j * 4 + 1] = (int16_t) (right_tmp * 32767.0f); + s16_samples[j * 4 + 2] = (int16_t) (*sur * 32767.0f); + s16_samples[j * 4 + 3] = (int16_t) (*sur++ * 32767.0f); + } +} + +static void downmix_3f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) { uint32_t j; @@ -125,6 +248,26 @@ downmix_3f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_ static void +downmix_2f_1r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +{ + uint32_t j; + float *left = 0, *right = 0, *sur = 0; + + left = samples[0]; + right = samples[1]; + //Mono surround + sur = samples[2]; + + for (j = 0; j < 256; j++) + { + s16_samples[j * 4 ] = (int16_t) (*left++ * 32767.0f); + s16_samples[j * 4 + 1] = (int16_t) (*right++ * 32767.0f); + s16_samples[j * 4 + 2] = (int16_t) (*sur * 32767.0f); + s16_samples[j * 4 + 3] = (int16_t) (*sur++ * 32767.0f); + } +} + +static void downmix_2f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) { uint32_t j; @@ -208,19 +351,19 @@ downmix_1f_0r_to_2ch(float *centre,int16_t *s16_samples) } // -// Downmix into 2 or 4 channels (4 ch isn't in quite yet) +// Downmix into 2 or 4 or 5 channels (4 ch isn't in quite yet) // // The downmix function names have the following format // -// downmix_Xf_Yr_to_[2|4]ch[_dolby] +// downmix_Xf_Yr_to_[2|4|5]ch[_dolby] // // where X = number of front channels // Y = number of rear channels -// [2|4] = number of output channels +// [2|4|5] = number of output channels // [_dolby] = with or without dolby surround mix // -void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) +void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples, int num_channels) { if(state->acmod > 7) dprintf("(downmix) invalid acmod number\n"); @@ -239,46 +382,74 @@ void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples) //Non-Dolby surround downmixes switch(state->acmod) { - // 3/2 - case 7: - downmix_3f_2r_to_2ch(state, samples,s16_samples); - break; - - // 2/2 - case 6: - downmix_2f_2r_to_2ch(state, samples,s16_samples); - break; - - // 3/1 - case 5: - downmix_3f_1r_to_2ch(state, samples,s16_samples); - break; - - // 2/1 - case 4: - downmix_2f_1r_to_2ch(state, samples,s16_samples); - break; - - // 3/0 - case 3: - downmix_3f_0r_to_2ch(state, samples,s16_samples); - break; - - case 2: - downmix_2f_0r_to_2ch(state, samples,s16_samples); - break; - - // 1/0 - case 1: - downmix_1f_0r_to_2ch(samples[0],s16_samples); - break; - - // 1+1 - case 0: + // 3/2 + case 7: + switch (num_channels) { + case 5: + downmix_3f_2r_to_5ch(state, samples,s16_samples); + break; + case 4: + downmix_3f_2r_to_4ch(state, samples,s16_samples); + break; + case 2: + downmix_3f_2r_to_2ch(state, samples,s16_samples); + break; + } + break; + + // 2/2 + case 6: + if (num_channels == 4) + downmix_2f_2r_to_4ch(state, samples,s16_samples); + else + downmix_2f_2r_to_2ch(state, samples,s16_samples); + break; + + // 3/1 + case 5: + + switch (num_channels) { + case 5: + downmix_3f_1r_to_5ch(state, samples,s16_samples); + break; + case 4: + downmix_3f_1r_to_4ch(state, samples,s16_samples); + break; + case 2: + downmix_3f_1r_to_2ch(state, samples,s16_samples); + break; + } + + break; + + // 2/1 + case 4: + if (num_channels == 4) + downmix_2f_1r_to_4ch(state, samples,s16_samples); + else + downmix_2f_1r_to_2ch(state, samples,s16_samples); + break; + + // 3/0 + case 3: + downmix_3f_0r_to_2ch(state, samples,s16_samples); + break; + + case 2: + downmix_2f_0r_to_2ch(state, samples,s16_samples); + break; + + // 1/0 + case 1: + downmix_1f_0r_to_2ch(samples[0],s16_samples); + break; + + // 1+1 + case 0: #if 0 - downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples); + downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples); #endif - break; + break; } } diff --git a/src/libac3/downmix.h b/src/libac3/downmix.h index 525980afb..28c6aea15 100644 --- a/src/libac3/downmix.h +++ b/src/libac3/downmix.h @@ -25,4 +25,5 @@ * */ -void downmix(ac3_state_t * state, stream_samples_t stream_samples,int16_t *s16_samples); +void downmix(ac3_state_t * state, stream_samples_t stream_samples,int16_t *s16_samples, + int num_channels); diff --git a/src/libac3/xine_decoder.c b/src/libac3/xine_decoder.c index b11987299..5b9ab7ef6 100644 --- a/src/libac3/xine_decoder.c +++ b/src/libac3/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.2 2001/05/26 15:07:18 guenter Exp $ + * $Id: xine_decoder.c,v 1.3 2001/05/27 23:48:12 guenter Exp $ * * stuff needed to turn libac3 into a xine decoder plugin */ @@ -48,8 +48,12 @@ typedef struct ac3dec_decoder_s { uint16_t syncword; ao_functions_t *audio_out; + int audio_caps; + int bypass_mode; + int max_num_channels; int output_sampling_rate; int output_open; + int output_mode; } ac3dec_decoder_t; @@ -62,11 +66,36 @@ void ac3dec_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { ac3dec_decoder_t *this = (ac3dec_decoder_t *) this_gen; - this->audio_out = audio_out; - ac3_init (); + this->audio_out = audio_out; + this->audio_caps = audio_out->get_capabilities(audio_out); this->syncword = 0; this->sync_todo = 6; this->output_open = 0; + + ac3_init (); + + /* + * find out if this driver supports ac3 output + * or, if not, how many channels we've got + */ + + if (this->audio_caps & AO_CAP_MODE_AC3) + this->bypass_mode = 1; + else { + this->bypass_mode = 0; + + /* find best mode */ + if (this->audio_caps & AO_CAP_MODE_5CHANNEL) + this->max_num_channels = 5; + else if (this->audio_caps & AO_CAP_MODE_4CHANNEL) + this->max_num_channels = 4; + else if (this->audio_caps & AO_CAP_MODE_STEREO) + this->max_num_channels = 2; + else { + printf ("HELP! a mono-only audio driver?!\n"); + this->max_num_channels = 1; + } + } } void ac3dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { @@ -77,6 +106,7 @@ void ac3dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { uint8_t *end = buf->content + buf->size; ac3_frame_t *ac3_frame; int sampling_rate; + int output_mode; uint8_t byte; @@ -125,30 +155,79 @@ void ac3dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { return ; } - /* now, decode this frame */ + /* + * do we want to decode this frame in software? + */ - ac3_frame = ac3_decode_frame (this->frame_buffer); + if (!this->bypass_mode) { + + /* oki, decode this frame in software*/ + + ac3_frame = ac3_decode_frame (this->frame_buffer, this->max_num_channels); + + /* determine output mode */ + switch (ac3_frame->num_channels) { + case 1: + output_mode = AO_CAP_MODE_MONO; + break; + case 2: + output_mode = AO_CAP_MODE_STEREO; + break; + case 4: + output_mode = AO_CAP_MODE_4CHANNEL; + break; + case 5: + output_mode = AO_CAP_MODE_5CHANNEL; + break; + } - /* output audio */ + /* output decoded samples */ - if (!this->output_open - || (ac3_frame->sampling_rate != this->output_sampling_rate) ) { + if (!this->output_open + || (ac3_frame->sampling_rate != this->output_sampling_rate) + || (output_mode != this->output_mode)) { - if (this->output_open) - this->audio_out->close (this->audio_out); + if (this->output_open) + this->audio_out->close (this->audio_out); + + + this->output_open = (this->audio_out->open (this->audio_out, 16, + ac3_frame->sampling_rate, + output_mode) == 1); + this->output_sampling_rate = ac3_frame->sampling_rate; + this->output_mode = output_mode; + } + + if (this->output_open) { + this->audio_out->write_audio_data (this->audio_out, + ac3_frame->audio_data, + 256*6, + this->pts); + this->pts = 0; + } + } else { + + /* + * loop through ac3 data + */ + + if (!this->output_open) { + this->output_open = (this->audio_out->open (this->audio_out, 16, + ac3_sampling_rate(this->frame_buffer), + AO_CAP_MODE_AC3) == 1); + this->output_mode - AO_CAP_MODE_AC3; + } + + + if (this->output_open) { + this->audio_out->write_audio_data (this->audio_out, + this->frame_buffer, + this->frame_length, + this->pts); + this->pts = 0; + } - this->output_open = (this->audio_out->open (this->audio_out, 16, - ac3_frame->sampling_rate, - AO_CAP_MODE_STEREO) == 1); - this->output_sampling_rate = ac3_frame->sampling_rate; - } - if (this->output_open) { - this->audio_out->write_audio_data (this->audio_out, - ac3_frame->audio_data, - 256*6, - this->pts); - this->pts = 0; } /* done with frame, prepare for next one */ |