summaryrefslogtreecommitdiff
path: root/src/libac3
diff options
context:
space:
mode:
Diffstat (limited to 'src/libac3')
-rw-r--r--src/libac3/ac3.h6
-rw-r--r--src/libac3/decode.c35
-rw-r--r--src/libac3/downmix.c255
-rw-r--r--src/libac3/downmix.h3
-rw-r--r--src/libac3/xine_decoder.c121
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 */