diff options
Diffstat (limited to 'src/liba52/xine_decoder.c')
-rw-r--r-- | src/liba52/xine_decoder.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/src/liba52/xine_decoder.c b/src/liba52/xine_decoder.c new file mode 100644 index 000000000..6d4b89078 --- /dev/null +++ b/src/liba52/xine_decoder.c @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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.1 2001/08/29 00:51:57 guenter Exp $ + * + * stuff needed to turn liba52 into a xine decoder plugin + */ + + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "audio_out.h" +#include "a52.h" +#include "a52_internal.h" +#include "buffer.h" +#include "xine_internal.h" +#include "cpu_accel.h" + +#undef DEBUG_A52 +#ifdef DEBUG_A52 +int a52file; +#endif + +typedef struct a52dec_decoder_s { + audio_decoder_t audio_decoder; + + uint32_t pts; + uint32_t last_pts; + + uint8_t frame_buffer[3840]; + uint8_t *frame_ptr; + int sync_todo; + int frame_length, frame_todo; + uint16_t syncword; + + a52_state_t a52_state; + int a52_flags; + int a52_bit_rate; + int a52_sample_rate; + float a52_level; + int have_lfe; + + int a52_flags_map[8]; + int ao_flags_map[8]; + + int16_t int_samples [6 * 256 * 6]; + sample_t *samples; + + ao_instance_t *audio_out; + int audio_caps; + int bypass_mode; + int output_sampling_rate; + int output_open; + int output_mode; + + int disable_dynrng ; +} a52dec_decoder_t; + +int a52dec_can_handle (audio_decoder_t *this_gen, int buf_type) { + return ((buf_type & 0xFFFF0000) == BUF_AUDIO_A52) ; +} + + +void a52dec_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + /* int i; */ + + this->audio_out = audio_out; + this->audio_caps = audio_out->get_capabilities(audio_out); + this->syncword = 0; + this->sync_todo = 7; + this->output_open = 0; + this->pts = 0; + this->last_pts = 0; + + this->samples = a52_init (mm_accel()); + + /* + * find out if this driver supports a52 output + * or, if not, how many channels we've got + */ + + if (this->audio_caps & AO_CAP_MODE_A52) + this->bypass_mode = 1; + else { + this->bypass_mode = 0; + + this->a52_flags_map[A52_MONO] = A52_MONO; + this->a52_flags_map[A52_STEREO] = A52_STEREO; + this->a52_flags_map[A52_3F] = A52_STEREO; + this->a52_flags_map[A52_2F1R] = A52_STEREO; + this->a52_flags_map[A52_3F1R] = A52_STEREO; + this->a52_flags_map[A52_2F2R] = A52_STEREO; + this->a52_flags_map[A52_3F2R] = A52_STEREO; + + this->ao_flags_map[A52_MONO] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_STEREO] = AO_CAP_MODE_STEREO; + this->ao_flags_map[A52_3F] = AO_CAP_MODE_STEREO; + this->ao_flags_map[A52_2F1R] = AO_CAP_MODE_STEREO; + this->ao_flags_map[A52_3F1R] = AO_CAP_MODE_STEREO; + this->ao_flags_map[A52_2F2R] = AO_CAP_MODE_STEREO; + this->ao_flags_map[A52_3F2R] = AO_CAP_MODE_STEREO; + + /* find best mode */ + if (this->audio_caps & AO_CAP_MODE_5_1CHANNEL) { + + this->a52_flags_map[A52_2F2R] = A52_2F2R; + this->a52_flags_map[A52_3F2R] = A52_3F2R | A52_LFE; + this->ao_flags_map[A52_2F2R] = AO_CAP_MODE_4CHANNEL; + this->ao_flags_map[A52_3F2R] = AO_CAP_MODE_5CHANNEL; + + } else if (this->audio_caps & AO_CAP_MODE_5CHANNEL) { + + this->a52_flags_map[A52_2F2R] = A52_2F2R; + this->a52_flags_map[A52_3F2R] = A52_3F2R; + this->ao_flags_map[A52_2F2R] = AO_CAP_MODE_4CHANNEL; + this->ao_flags_map[A52_3F2R] = AO_CAP_MODE_5CHANNEL; + + } else if (this->audio_caps & AO_CAP_MODE_4CHANNEL) { + + this->a52_flags_map[A52_2F2R] = A52_2F2R; + this->a52_flags_map[A52_3F2R] = A52_2F2R; + + this->ao_flags_map[A52_2F2R] = AO_CAP_MODE_4CHANNEL; + this->ao_flags_map[A52_3F2R] = AO_CAP_MODE_4CHANNEL; + + /* else if (this->audio_caps & AO_CAP_MODE_STEREO) + defaults are ok */ + } else if (!(this->audio_caps & AO_CAP_MODE_STEREO)) { + printf ("HELP! a mono-only audio driver?!\n"); + + this->a52_flags_map[A52_MONO] = A52_MONO; + this->a52_flags_map[A52_STEREO] = A52_MONO; + this->a52_flags_map[A52_3F] = A52_MONO; + this->a52_flags_map[A52_2F1R] = A52_MONO; + this->a52_flags_map[A52_3F1R] = A52_MONO; + this->a52_flags_map[A52_2F2R] = A52_MONO; + this->a52_flags_map[A52_3F2R] = A52_MONO; + + this->ao_flags_map[A52_MONO] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_STEREO] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_3F] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_2F1R] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_3F1R] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_2F2R] = AO_CAP_MODE_MONO; + this->ao_flags_map[A52_3F2R] = AO_CAP_MODE_MONO; + } + } + + /* + for (i = 0; i<8; i++) + this->a52_flags_map[i] |= A52_ADJUST_LEVEL; +*/ +#ifdef DEBUG_A52 + a52file = open ("test.a52", O_CREAT | O_WRONLY | O_TRUNC, 0644); +#endif +} + +static inline int16_t blah (int32_t i) +{ + if (i > 0x43c07fff) + return 32767; + else if (i < 0x43bf8000) + return -32768; + else + return i - 0x43c00000; +} + +static inline void float_to_int (float * _f, int16_t * s16, int num_channels) { + int i; + int32_t * f = (int32_t *) _f; /* XXX assumes IEEE float format */ + + for (i = 0; i < 256; i++) { + s16[num_channels*i] = blah (f[i]); + } +} + +static void a52dec_decode_frame (a52dec_decoder_t *this, uint32_t pts) { + + int output_mode = AO_CAP_MODE_STEREO; + + /* + * do we want to decode this frame in software? + */ + + if (!this->bypass_mode) { + + int a52_output_flags, i; + sample_t level = this->a52_level; + + /* + * oki, decode this frame in software + */ + + /* determine output mode */ + + a52_output_flags = this->a52_flags_map[this->a52_flags & A52_CHANNEL_MASK]; + + if (a52_frame (&this->a52_state, + this->frame_buffer, + &a52_output_flags, + &level, 384)) { + printf ("liba52: a52_frame error\n"); + return; + } + + if (this->disable_dynrng) + a52_dynrng (&this->a52_state, NULL, NULL); + + this->have_lfe = a52_output_flags & A52_LFE; + if (this->have_lfe) + output_mode = AO_CAP_MODE_5_1CHANNEL; + else + output_mode = this->ao_flags_map[a52_output_flags]; + + /* + * (re-)open output device + */ + + if (!this->output_open + || (this->a52_sample_rate != this->output_sampling_rate) + || (output_mode != this->output_mode)) { + + if (this->output_open) + this->audio_out->close (this->audio_out); + + + this->output_open = (this->audio_out->open (this->audio_out, 16, + this->a52_sample_rate, + output_mode) == 1); + this->output_sampling_rate = this->a52_sample_rate; + this->output_mode = output_mode; + } + + + if (!this->output_open) + return; + + + /* + * decode a52 and convert/interleave samples + */ + + for (i = 0; i < 6; i++) { + if (a52_block (&this->a52_state, this->samples)) { + printf ("liba52: a52_block error\n"); + return; + } + + switch (output_mode) { + case AO_CAP_MODE_MONO: + float_to_int (&this->samples[0], this->int_samples+(i*256), 1); + break; + case AO_CAP_MODE_STEREO: + float_to_int (&this->samples[0*256], this->int_samples+(i*256*2), 2); + float_to_int (&this->samples[1*256], this->int_samples+(i*256*2)+1, 2); + break; + case AO_CAP_MODE_4CHANNEL: + float_to_int (&this->samples[0*256], this->int_samples+(i*256*4), 4); /* L */ + float_to_int (&this->samples[1*256], this->int_samples+(i*256*4)+1, 4); /* R */ + float_to_int (&this->samples[2*256], this->int_samples+(i*256*4)+2, 4); /* RL */ + float_to_int (&this->samples[3*256], this->int_samples+(i*256*4)+3, 4); /* RR */ + break; + case AO_CAP_MODE_5CHANNEL: + float_to_int (&this->samples[0*256], this->int_samples+(i*256*5)+0, 5); /* L */ + float_to_int (&this->samples[1*256], this->int_samples+(i*256*5)+4, 5); /* C */ + float_to_int (&this->samples[2*256], this->int_samples+(i*256*5)+1, 5); /* R */ + float_to_int (&this->samples[3*256], this->int_samples+(i*256*5)+2, 5); /* RL */ + float_to_int (&this->samples[4*256], this->int_samples+(i*256*5)+3, 5); /* RR */ + break; + case AO_CAP_MODE_5_1CHANNEL: + float_to_int (&this->samples[0*256], this->int_samples+(i*256*6)+5, 6); /* lfe */ + float_to_int (&this->samples[1*256], this->int_samples+(i*256*6)+0, 6); /* L */ + float_to_int (&this->samples[2*256], this->int_samples+(i*256*6)+4, 6); /* C */ + float_to_int (&this->samples[3*256], this->int_samples+(i*256*6)+1, 6); /* R */ + float_to_int (&this->samples[4*256], this->int_samples+(i*256*6)+2, 6); /* RL */ + float_to_int (&this->samples[5*256], this->int_samples+(i*256*6)+3, 6); /* RR */ + break; + default: + printf ("liba52: help - unsupported mode %08x\n", output_mode); + } + } + + /* output decoded samples */ + + this->audio_out->write (this->audio_out, + this->int_samples, + 256*6, + pts); + pts = 0; + + } else { + + /* + * loop through a52 data + */ + + if (!this->output_open) { + + int sample_rate, bit_rate, flags; + + a52_syncinfo (this->frame_buffer, &flags, &sample_rate, &bit_rate); + + this->output_open = (this->audio_out->open (this->audio_out, 16, + sample_rate, + AO_CAP_MODE_A52) == 1); + this->output_mode = AO_CAP_MODE_A52; + } + + if (this->output_open) { + this->audio_out->write (this->audio_out, + (int16_t*)this->frame_buffer, + this->frame_length, + pts); + } + } +} + +void a52dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + uint8_t *current = buf->content; + uint8_t *end = buf->content + buf->size; + uint8_t byte; + + if (buf->decoder_info[0] == 0) + return; + + /* + printf ("liba52: got buffer, pts =%d, pts - last_pts=%d\n", + buf->PTS, buf->PTS - this->last_pts); + + this->last_pts = buf->PTS; + */ + + if (buf->PTS) + this->pts = buf->PTS; + + + while (current != end) { + + if ( (this->sync_todo == 0) && (this->frame_todo == 0) ) { + a52dec_decode_frame (this, this->pts); +#ifdef DEBUG_A52 + write (a52file, this->frame_buffer, this->frame_length); +#endif + this->pts = 0; + this->sync_todo = 7; + this->syncword = 0; + } + + while (1) { + byte = *current++; + + if (this->sync_todo>0) { + + /* search and collect syncinfo */ + + if (this->syncword != 0x0b77) { + this->syncword = (this->syncword << 8) | byte; + + if (this->syncword == 0x0b77) { + + this->frame_buffer[0] = 0x0b; + this->frame_buffer[1] = 0x77; + + this->sync_todo = 5; + this->frame_ptr = this->frame_buffer+2; + } + } else { + *this->frame_ptr++ = byte; + this->sync_todo--; + + if (this->sync_todo==0) { + + this->frame_length = a52_syncinfo (this->frame_buffer, + &this->a52_flags, + &this->a52_sample_rate, + &this->a52_bit_rate); + if (this->frame_length) { + this->frame_todo = this->frame_length - 7; + } else { + this->sync_todo = 7; + this->syncword = 0; + printf ("liba52: skip frame of zero length\n"); + } + + } + + } + } else { + + *this->frame_ptr++ = byte; + this->frame_todo--; + + if (this->frame_todo == 0) { + if (current == end) + return ; + break; + } + } + + if (current == end) + return ; + } + } +} + +void a52dec_close (audio_decoder_t *this_gen) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + + if (this->output_open) + this->audio_out->close (this->audio_out); + + this->output_open = 0; + +#ifdef DEBUG_A52 + close (a52file); +#endif +} + +static char *a52dec_get_id(void) { + return "a/52dec"; +} + +audio_decoder_t *init_audio_decoder_plugin (int iface_version, config_values_t *cfg) { + + a52dec_decoder_t *this ; + + if (iface_version != 2) { + printf( "liba52: plugin doesn't support plugin API version %d.\n" + "liba52: this means there's a version mismatch between xine and this " + "liba52: decoder plugin.\nInstalling current plugins should help.\n", + iface_version); + return NULL; + } + + this = (a52dec_decoder_t *) malloc (sizeof (a52dec_decoder_t)); + + this->audio_decoder.interface_version = 2; + this->audio_decoder.can_handle = a52dec_can_handle; + this->audio_decoder.init = a52dec_init; + this->audio_decoder.decode_data = a52dec_decode_data; + this->audio_decoder.close = a52dec_close; + this->audio_decoder.get_identifier = a52dec_get_id; + this->audio_decoder.priority = 1; + + + this->a52_level = (float) cfg->lookup_int (cfg, "a52_level", 100) / 100.0; + this->disable_dynrng = !cfg->lookup_int (cfg, "a52_dynrng", 0); + + return (audio_decoder_t *) this; +} + |