diff options
Diffstat (limited to 'src/libxineadec')
-rw-r--r-- | src/libxineadec/Makefile.am | 58 | ||||
-rw-r--r-- | src/libxineadec/xine_a52_decoder.c | 866 | ||||
-rw-r--r-- | src/libxineadec/xine_faad_decoder.c | 486 | ||||
-rw-r--r-- | src/libxineadec/xine_mad_decoder.c | 380 | ||||
-rw-r--r-- | src/libxineadec/xine_speex_decoder.c | 419 | ||||
-rw-r--r-- | src/libxineadec/xine_vorbis_decoder.c | 354 |
6 files changed, 1771 insertions, 792 deletions
diff --git a/src/libxineadec/Makefile.am b/src/libxineadec/Makefile.am index 25d1e358a..c552d9a08 100644 --- a/src/libxineadec/Makefile.am +++ b/src/libxineadec/Makefile.am @@ -5,14 +5,6 @@ AM_LDFLAGS = $(xineplug_ldflags) EXTRA_DIST = fooaudio.c -if ENABLE_VORBIS -vorbis_module = xineplug_decode_vorbis.la -endif - -if ENABLE_SPEEX -speex_module = xineplug_decode_speex.la -endif - if ENABLE_MUSEPACK musepack_module = xineplug_decode_mpc.la endif @@ -21,6 +13,27 @@ if ENABLE_DTS dts_module = xineplug_decode_dts.la endif +if ENABLE_MAD +mad_module = xineplug_decode_mad.la +endif + +if ENABLE_A52DEC +a52_module = xineplug_decode_a52.la +endif + +if ENABLE_FAAD +faad_module = xineplug_decode_faad.la +endif + +$(top_builddir)/contrib/a52dec/liba52.la: + $(MAKE) -C $(top_builddir)/contrib/a52dec + +$(top_builddir)/contrib/libfaad/libfaad.la: + $(MAKE) -C $(top_builddir)/contrib/libfaad + +$(top_builddir)/contrib/libmad/libmad.la: + $(MAKE) -C $(top_builddir)/contrib/libmad + $(top_builddir)/contrib/libmpcdec/libmpcdec.la: $(MAKE) -C $(top_builddir)/contrib/libmpcdec @@ -33,10 +46,11 @@ $(top_builddir)/contrib/gsm610/libgsm610.la: xineplug_LTLIBRARIES = \ xineplug_decode_gsm610.la \ xineplug_decode_lpcm.la \ - $(vorbis_module) \ - $(speex_module) \ $(musepack_module) \ - $(dts_module) + $(dts_module) \ + $(mad_module) \ + $(a52_module) \ + $(faad_module) xineplug_decode_gsm610_la_SOURCES = gsm610.c xineplug_decode_gsm610_la_LIBADD = $(XINE_LIB) $(top_builddir)/contrib/gsm610/libgsm610.la @@ -45,14 +59,6 @@ xineplug_decode_gsm610_la_CPPFLAGS = -I$(top_srcdir)/contrib/gsm610 xineplug_decode_lpcm_la_SOURCES = xine_lpcm_decoder.c xineplug_decode_lpcm_la_LIBADD = $(XINE_LIB) -xineplug_decode_vorbis_la_SOURCES = xine_vorbis_decoder.c -xineplug_decode_vorbis_la_LIBADD = $(XINE_LIB) $(VORBIS_LIBS) $(OGG_LIBS) -xineplug_decode_vorbis_la_CFLAGS = $(AM_CFLAGS) $(VORBIS_CFLAGS) - -xineplug_decode_speex_la_SOURCES = xine_speex_decoder.c -xineplug_decode_speex_la_LIBADD = $(XINE_LIB) $(SPEEX_LIBS) -xineplug_decode_speex_la_CFLAGS = $(AM_CFLAGS) $(SPEEX_CFLAGS) - xineplug_decode_mpc_la_SOURCES = xine_musepack_decoder.c xineplug_decode_mpc_la_DEPENDENCIES = $(MPCDEC_DEPS) xineplug_decode_mpc_la_LIBADD = $(XINE_LIB) $(MPCDEC_LIBS) @@ -62,3 +68,17 @@ xineplug_decode_dts_la_SOURCES = xine_dts_decoder.c xineplug_decode_dts_la_DEPENDENCIES = $(LIBDTS_DEPS) xineplug_decode_dts_la_LIBADD = $(XINE_LIB) $(LIBDTS_LIBS) xineplug_decode_dts_la_CFLAGS = $(AM_CFLAGS) $(LIBDTS_CFLAGS) + +xineplug_decode_mad_la_SOURCES = xine_mad_decoder.c +xineplug_decode_mad_la_DEPENDENCIES = $(LIBMAD_DEPS) +xineplug_decode_mad_la_LIBADD = $(XINE_LIB) $(LIBMAD_LIBS) +xineplug_decode_mad_la_CFLAGS = $(AM_CFLAGS) $(LIBMAD_CFLAGS) + +xineplug_decode_a52_la_SOURCES = xine_a52_decoder.c +xineplug_decode_a52_la_DEPENDENCIES = $(A52DEC_DEPS) +xineplug_decode_a52_la_LIBADD = $(XINE_LIB) $(A52DEC_LIBS) -lm +xineplug_decode_a52_la_CFLAGS = $(AM_CFLAGS) $(A52DEC_CFLAGS) + +xineplug_decode_faad_la_SOURCES = xine_faad_decoder.c +xineplug_decode_faad_la_LIBADD = $(XINE_LIB) $(top_builddir)/contrib/libfaad/libfaad.la -lm +xineplug_decode_faad_la_CPPFLAGS = -I$(top_srcdir)/contrib/libfaad diff --git a/src/libxineadec/xine_a52_decoder.c b/src/libxineadec/xine_a52_decoder.c new file mode 100644 index 000000000..f6fa8a9a3 --- /dev/null +++ b/src/libxineadec/xine_a52_decoder.c @@ -0,0 +1,866 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free 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.81 2007/02/20 00:34:57 dgp85 Exp $ + * + * stuff needed to turn liba52 into a xine decoder plugin + */ + +#ifndef __sun +/* required for swab() */ +#define _XOPEN_SOURCE 500 +#endif +/* avoid compiler warnings */ +#define _BSD_SOURCE 1 + +#include <config.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <assert.h> + +#define LOG_MODULE "a52_decoder" +#define LOG_VERBOSE +/* +#define LOG +#define LOG_PTS +*/ + +#include "xine_internal.h" +#include "audio_out.h" + +#ifdef HAVE_A52DEC_A52_H +# include <a52dec/a52.h> +#else +# include "a52.h" +#endif + +#ifdef HAVE_A52DEC_A52_INTERNAL_H +# include <a52dec/a52_internal.h> +#else +# include "a52_internal.h" +#endif + +#include "buffer.h" +#include "xineutils.h" + +#include "../../contrib/a52dec/crc.c" + +#undef DEBUG_A52 +#ifdef DEBUG_A52 +int a52file; +#endif + +typedef struct { + audio_decoder_class_t decoder_class; + config_values_t *config; + + float a52_level; + int disable_dynrng_compress; + int enable_surround_downmix; + +} a52dec_class_t; + +typedef struct a52dec_decoder_s { + audio_decoder_t audio_decoder; + + a52dec_class_t *class; + xine_stream_t *stream; + int64_t pts; + int64_t pts_list[5]; + int32_t pts_list_position; + + uint8_t frame_buffer[3840]; + uint8_t *frame_ptr; + int sync_state; + int frame_length, frame_todo; + uint16_t syncword; + + a52_state_t *a52_state; + int a52_flags; + int a52_bit_rate; + int a52_sample_rate; + int have_lfe; + + int a52_flags_map[11]; + int ao_flags_map[11]; + + int audio_caps; + int bypass_mode; + int output_sampling_rate; + int output_open; + int output_mode; + +} a52dec_decoder_t; + +struct frmsize_s +{ + uint16_t bit_rate; + uint16_t frm_size[3]; +}; + +static const struct frmsize_s frmsizecod_tbl[64] = +{ + { 32 ,{64 ,69 ,96 } }, + { 32 ,{64 ,70 ,96 } }, + { 40 ,{80 ,87 ,120 } }, + { 40 ,{80 ,88 ,120 } }, + { 48 ,{96 ,104 ,144 } }, + { 48 ,{96 ,105 ,144 } }, + { 56 ,{112 ,121 ,168 } }, + { 56 ,{112 ,122 ,168 } }, + { 64 ,{128 ,139 ,192 } }, + { 64 ,{128 ,140 ,192 } }, + { 80 ,{160 ,174 ,240 } }, + { 80 ,{160 ,175 ,240 } }, + { 96 ,{192 ,208 ,288 } }, + { 96 ,{192 ,209 ,288 } }, + { 112 ,{224 ,243 ,336 } }, + { 112 ,{224 ,244 ,336 } }, + { 128 ,{256 ,278 ,384 } }, + { 128 ,{256 ,279 ,384 } }, + { 160 ,{320 ,348 ,480 } }, + { 160 ,{320 ,349 ,480 } }, + { 192 ,{384 ,417 ,576 } }, + { 192 ,{384 ,418 ,576 } }, + { 224 ,{448 ,487 ,672 } }, + { 224 ,{448 ,488 ,672 } }, + { 256 ,{512 ,557 ,768 } }, + { 256 ,{512 ,558 ,768 } }, + { 320 ,{640 ,696 ,960 } }, + { 320 ,{640 ,697 ,960 } }, + { 384 ,{768 ,835 ,1152 } }, + { 384 ,{768 ,836 ,1152 } }, + { 448 ,{896 ,975 ,1344 } }, + { 448 ,{896 ,976 ,1344 } }, + { 512 ,{1024 ,1114 ,1536 } }, + { 512 ,{1024 ,1115 ,1536 } }, + { 576 ,{1152 ,1253 ,1728 } }, + { 576 ,{1152 ,1254 ,1728 } }, + { 640 ,{1280 ,1393 ,1920 } }, + { 640 ,{1280 ,1394 ,1920 } } +}; + +/* config callbacks */ +static void a52_level_change_cb(void *this_gen, xine_cfg_entry_t *entry); +static void dynrng_compress_change_cb(void *this_gen, xine_cfg_entry_t *entry); +static void surround_downmix_change_cb(void *this_gen, xine_cfg_entry_t *entry); + + +static void a52dec_reset (audio_decoder_t *this_gen) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + + this->syncword = 0; + this->sync_state = 0; + this->pts = 0; + this->pts_list[0] = 0; + this->pts_list_position = 0; +} + +static void a52dec_discontinuity (audio_decoder_t *this_gen) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + + this->pts = 0; + this->pts_list[0] = 0; + this->pts_list_position = 0; +} + +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 inline void mute_channel (int16_t * s16, int num_channels) { + int i; + + for (i = 0; i < 256; i++) { + s16[num_channels*i] = 0; + } +} + +static void a52dec_decode_frame (a52dec_decoder_t *this, int64_t pts, int preview_mode) { + + int output_mode = AO_CAP_MODE_STEREO; + + /* + * do we want to decode this frame in software? + */ +#ifdef LOG_PTS + printf("a52dec:decode_frame:pts=%lld\n",pts); +#endif + if (!this->bypass_mode) { + + int a52_output_flags, i; + sample_t level = this->class->a52_level; + audio_buffer_t *buf; + int16_t *int_samples; + sample_t *samples = a52_samples(this->a52_state); + + /* + * 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)) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "liba52: a52_frame error\n"); + return; + } + + if (this->class->disable_dynrng_compress) + a52_dynrng (this->a52_state, NULL, NULL); + + this->have_lfe = a52_output_flags & A52_LFE; + if (this->have_lfe) + if (this->audio_caps & AO_CAP_MODE_5_1CHANNEL) { + output_mode = AO_CAP_MODE_5_1CHANNEL; + } else if (this->audio_caps & AO_CAP_MODE_4_1CHANNEL) { + output_mode = AO_CAP_MODE_4_1CHANNEL; + } else { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "liba52: WHAT DO I DO!!!\n"); + output_mode = this->ao_flags_map[a52_output_flags]; + } + 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->stream->audio_out->close (this->stream->audio_out, this->stream); + + + this->output_open = this->stream->audio_out->open (this->stream->audio_out, + this->stream, 16, + this->a52_sample_rate, + output_mode) ; + this->output_sampling_rate = this->a52_sample_rate; + this->output_mode = output_mode; + } + + + if (!this->output_open || preview_mode) + return; + + + /* + * decode a52 and convert/interleave samples + */ + + buf = this->stream->audio_out->get_buffer (this->stream->audio_out); + int_samples = buf->mem; + buf->num_frames = 256*6; + + for (i = 0; i < 6; i++) { + if (a52_block (this->a52_state)) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "liba52: a52_block error on audio channel %d\n", i); +#if 0 + for(n=0;n<2000;n++) { + printf("%02x ",this->frame_buffer[n]); + if ((n % 32) == 0) printf("\n"); + } + printf("\n"); +#endif + buf->num_frames = 0; + break; + } + + switch (output_mode) { + case AO_CAP_MODE_MONO: + float_to_int (&samples[0], int_samples+(i*256), 1); + break; + case AO_CAP_MODE_STEREO: + float_to_int (&samples[0*256], int_samples+(i*256*2), 2); + float_to_int (&samples[1*256], int_samples+(i*256*2)+1, 2); + break; + case AO_CAP_MODE_4CHANNEL: + float_to_int (&samples[0*256], int_samples+(i*256*4), 4); /* L */ + float_to_int (&samples[1*256], int_samples+(i*256*4)+1, 4); /* R */ + float_to_int (&samples[2*256], int_samples+(i*256*4)+2, 4); /* RL */ + float_to_int (&samples[3*256], int_samples+(i*256*4)+3, 4); /* RR */ + break; + case AO_CAP_MODE_4_1CHANNEL: + float_to_int (&samples[0*256], int_samples+(i*256*6)+5, 6); /* LFE */ + float_to_int (&samples[1*256], int_samples+(i*256*6)+0, 6); /* L */ + float_to_int (&samples[2*256], int_samples+(i*256*6)+1, 6); /* R */ + float_to_int (&samples[3*256], int_samples+(i*256*6)+2, 6); /* RL */ + float_to_int (&samples[4*256], int_samples+(i*256*6)+3, 6); /* RR */ + mute_channel ( int_samples+(i*256*6)+4, 6); /* C */ + break; + case AO_CAP_MODE_5CHANNEL: + float_to_int (&samples[0*256], int_samples+(i*256*6)+0, 6); /* L */ + float_to_int (&samples[1*256], int_samples+(i*256*6)+4, 6); /* C */ + float_to_int (&samples[2*256], int_samples+(i*256*6)+1, 6); /* R */ + float_to_int (&samples[3*256], int_samples+(i*256*6)+2, 6); /* RL */ + float_to_int (&samples[4*256], int_samples+(i*256*6)+3, 6); /* RR */ + mute_channel ( int_samples+(i*256*6)+5, 6); /* LFE */ + break; + case AO_CAP_MODE_5_1CHANNEL: + float_to_int (&samples[0*256], int_samples+(i*256*6)+5, 6); /* lfe */ + float_to_int (&samples[1*256], int_samples+(i*256*6)+0, 6); /* L */ + float_to_int (&samples[2*256], int_samples+(i*256*6)+4, 6); /* C */ + float_to_int (&samples[3*256], int_samples+(i*256*6)+1, 6); /* R */ + float_to_int (&samples[4*256], int_samples+(i*256*6)+2, 6); /* RL */ + float_to_int (&samples[5*256], int_samples+(i*256*6)+3, 6); /* RR */ + break; + default: + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "liba52: help - unsupported mode %08x\n", output_mode); + } + } + + lprintf ("%d frames output\n", buf->num_frames); + + /* output decoded samples */ + + buf->vpts = pts; + + this->stream->audio_out->put_buffer (this->stream->audio_out, buf, this->stream); + + } 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->stream->audio_out->open (this->stream->audio_out, + this->stream, 16, + sample_rate, + AO_CAP_MODE_A52) ; + this->output_mode = AO_CAP_MODE_A52; + } + + if (this->output_open && !preview_mode) { + /* SPDIF Passthrough + * Build SPDIF Header and encaps the A52 audio data in it. + */ + uint32_t syncword, crc1, fscod,frmsizecod,bsid,bsmod,frame_size; + uint8_t *data_out,*data_in; + audio_buffer_t *buf = this->stream->audio_out->get_buffer (this->stream->audio_out); + data_in=(uint8_t *) this->frame_buffer; + data_out=(uint8_t *) buf->mem; + syncword = data_in[0] | (data_in[1] << 8); + crc1 = data_in[2] | (data_in[3] << 8); + fscod = (data_in[4] >> 6) & 0x3; + frmsizecod = data_in[4] & 0x3f; + bsid = (data_in[5] >> 3) & 0x1f; + bsmod = data_in[5] & 0x7; /* bsmod, stream = 0 */ + frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] ; + + data_out[0] = 0x72; data_out[1] = 0xf8; /* spdif syncword */ + data_out[2] = 0x1f; data_out[3] = 0x4e; /* .............. */ + data_out[4] = 0x01; /* AC3 data */ + data_out[5] = bsmod; /* bsmod, stream = 0 */ + data_out[6] = (frame_size << 4) & 0xff; /* frame_size * 16 */ + data_out[7] = ((frame_size ) >> 4) & 0xff; + swab(data_in, &data_out[8], frame_size * 2 ); + + buf->num_frames = 1536; + buf->vpts = pts; + + this->stream->audio_out->put_buffer (this->stream->audio_out, buf, this->stream); + + } + } +} + +static 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 *sync_start=current + 1; + uint8_t *end = buf->content + buf->size; + uint8_t byte; + int32_t n; + uint16_t crc16; + uint16_t crc16_result; + + lprintf ("decode data %d bytes of type %08x, pts=%"PRId64"\n", + buf->size, buf->type, buf->pts); + lprintf ("decode data decoder_info=%d, %d\n",buf->decoder_info[1],buf->decoder_info[2]); + + if (buf->decoder_flags & BUF_FLAG_HEADER) + return; + + /* swap byte pairs if this is RealAudio DNET data */ + if (buf->type == BUF_AUDIO_DNET) { + + lprintf ("byte-swapping dnet\n"); + + while (current != end) { + byte = *current++; + *(current - 1) = *current; + *current++ = byte; + } + + /* reset */ + current = buf->content; + end = buf->content + buf->size; + } + + /* A52 packs come from the DVD in blocks of about 2048 bytes. + * Only 1 PTS values can be assigned to each block. + * An A52 frame is about 1700 bytes long. + * So, a single A52 packs can contain 2 A52 frames (or the beginning of an A52 frame at least). + * If we have a PTS value, which A52 frame does it apply to? The A52 pack tells us that. + * So, the info about which A52 frame the PTS applies to is contained in decoder_info sent from the demuxer. + * + * The PTS value from the A52 pack (DVD sector) can only be applied at the start of an A52 frame. + * We call the start of an A52 frame a frame header. + * So, if a A52 pack has 2 "Number of frame headers" is means that the A52 pack contains 2 A52 frame headers. + * The "First access unit" then tells us which A52 frame the PTS value applies to. + * + * Take the following example: - + * PACK1: PTS = 10. Contains the entire A52 frame1, followed by the beginning of the frame2. PTS applies to frame1. + * PACK2: PTS = 1000, Contains the rest of frame2, and the whole of frame3. and the start of frame4. PTS applies to frame4. + * PACK3: PTS = 0 (none), Contains the rest of frame4. + * + * Output should be: - + * frame1, PTS=10 + * frame2, PTS=0 + * frame3, PTS=0 + * frame4, PTS=1000 + * + * So, we have to keep track of PTS values from previous A52 packs here, otherwise they get put on the wrong frame. + */ + + + /* FIXME: the code here does not match the explanation above */ + if (buf->pts) { + int32_t info; + info = buf->decoder_info[1]; + this->pts = buf->pts; + this->pts_list[this->pts_list_position]=buf->pts; + this->pts_list_position++; + if( this->pts_list_position > 3 ) + this->pts_list_position = 3; + if (info == 2) { + this->pts_list[this->pts_list_position]=0; + this->pts_list_position++; + if( this->pts_list_position > 3 ) + this->pts_list_position = 3; + } + } +#if 0 + for(n=0;n < buf->size;n++) { + if ((n % 32) == 0) printf("\n"); + printf("%x ", current[n]); + } + printf("\n"); +#endif + + lprintf ("processing...state %d\n", this->sync_state); + + while (current < end) { + switch (this->sync_state) { + case 0: /* Looking for sync header */ + this->syncword = (this->syncword << 8) | *current++; + if (this->syncword == 0x0b77) { + + this->frame_buffer[0] = 0x0b; + this->frame_buffer[1] = 0x77; + + this->sync_state = 1; + this->frame_ptr = this->frame_buffer+2; + } + break; + + case 1: /* Looking for enough bytes for sync_info. */ + sync_start = current - 1; + *this->frame_ptr++ = *current++; + if ((this->frame_ptr - this->frame_buffer) > 16) { + int a52_flags_old = this->a52_flags; + int a52_sample_rate_old = this->a52_sample_rate; + int a52_bit_rate_old = this->a52_bit_rate; + + this->frame_length = a52_syncinfo (this->frame_buffer, + &this->a52_flags, + &this->a52_sample_rate, + &this->a52_bit_rate); + + if (this->frame_length < 80) { /* Invalid a52 frame_length */ + this->syncword = 0; + current = sync_start; + this->sync_state = 0; + break; + } + + lprintf("Frame length = %d\n",this->frame_length); + + this->frame_todo = this->frame_length - 17; + this->sync_state = 2; + if (!_x_meta_info_get(this->stream, XINE_META_INFO_AUDIOCODEC) || + a52_flags_old != this->a52_flags || + a52_sample_rate_old != this->a52_sample_rate || + a52_bit_rate_old != this->a52_bit_rate) { + + switch (this->a52_flags & A52_CHANNEL_MASK) { + case A52_3F2R: + if (this->a52_flags & A52_LFE) + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 5.1"); + else + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 5.0"); + break; + case A52_3F1R: + case A52_2F2R: + if (this->a52_flags & A52_LFE) + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 4.1"); + else + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 4.0"); + break; + case A52_2F1R: + case A52_3F: + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 3.0"); + break; + case A52_STEREO: + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 2.0 (stereo)"); + break; + case A52_DOLBY: + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 2.0 (dolby)"); + break; + case A52_MONO: + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52 1.0"); + break; + default: + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "A/52"); + break; + } + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, this->a52_bit_rate); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, this->a52_sample_rate); + } + } + break; + + case 2: /* Filling frame_buffer with sync_info bytes */ + *this->frame_ptr++ = *current++; + this->frame_todo--; + if (this->frame_todo < 1) { + this->sync_state = 3; + } else break; + + case 3: /* Ready for decode */ + crc16 = (uint16_t) ((this->frame_buffer[2] << 8) | this->frame_buffer[3]) ; + crc16_result = crc16_block(&this->frame_buffer[2], this->frame_length - 2) ; /* frame_length */ + if (crc16_result != 0) { /* CRC16 failed */ + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "liba52:a52 frame failed crc16 checksum.\n"); + current = sync_start; + this->pts = 0; + this->syncword = 0; + this->sync_state = 0; + break; + } +#if 0 + a52dec_decode_frame (this, this->pts_list[0], buf->decoder_flags & BUF_FLAG_PREVIEW); +#else + a52dec_decode_frame (this, this->pts, buf->decoder_flags & BUF_FLAG_PREVIEW); +#endif + for(n=0;n<4;n++) { + this->pts_list[n] = this->pts_list[n+1]; + } + this->pts_list_position--; + if( this->pts_list_position < 0 ) + this->pts_list_position = 0; +#if 0 + printf("liba52: pts_list = %lld, %lld, %lld\n", + this->pts_list[0], + this->pts_list[1], + this->pts_list[2]); +#endif + case 4: /* Clear up ready for next frame */ + this->pts = 0; + this->syncword = 0; + this->sync_state = 0; + break; + default: /* No come here */ + break; + } + } + +#ifdef DEBUG_A52 + write (a52file, this->frame_buffer, this->frame_length); +#endif +} + +static void a52dec_dispose (audio_decoder_t *this_gen) { + + a52dec_decoder_t *this = (a52dec_decoder_t *) this_gen; + + if (this->output_open) + this->stream->audio_out->close (this->stream->audio_out, this->stream); + + this->output_open = 0; + + a52_free(this->a52_state); + this->a52_state = NULL; + +#ifdef DEBUG_A52 + close (a52file); +#endif + free (this_gen); +} + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { + + a52dec_decoder_t *this ; + + lprintf ("open_plugin called\n"); + + this = (a52dec_decoder_t *) xine_xmalloc (sizeof (a52dec_decoder_t)); + + this->audio_decoder.decode_data = a52dec_decode_data; + this->audio_decoder.reset = a52dec_reset; + this->audio_decoder.discontinuity = a52dec_discontinuity; + this->audio_decoder.dispose = a52dec_dispose; + this->stream = stream; + this->class = (a52dec_class_t *) class_gen; + + /* int i; */ + + this->audio_caps = stream->audio_out->get_capabilities(stream->audio_out); + this->syncword = 0; + this->sync_state = 0; + this->output_open = 0; + this->pts = 0; + this->pts_list[0] = 0; + this->pts_list_position = 0; + + if( !this->a52_state ) + this->a52_state = a52_init (xine_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] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_3F] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_2F1R] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_3F1R] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_2F2R] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_3F2R] = ((this->class->enable_surround_downmix ? A52_DOLBY : A52_STEREO)); + this->a52_flags_map[A52_DOLBY] = ((this->class->enable_surround_downmix ? A52_DOLBY : 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; + this->ao_flags_map[A52_DOLBY] = 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_4_1CHANNEL) { + + this->a52_flags_map[A52_2F2R] = A52_2F2R; + this->a52_flags_map[A52_3F2R] = A52_2F2R | A52_LFE; + 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_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)) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, _("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->a52_flags_map[A52_DOLBY] = 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; + this->ao_flags_map[A52_DOLBY] = 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 + return &this->audio_decoder; +} + +static char *get_identifier (audio_decoder_class_t *this) { + lprintf ("get_identifier called\n"); + return "a/52dec"; +} + +static char *get_description (audio_decoder_class_t *this) { + lprintf ("get_description called\n"); + return "liba52 based a52 audio decoder plugin"; +} + +static void dispose_class (audio_decoder_class_t *this) { + lprintf ("dispose_class called\n"); + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + a52dec_class_t *this; + config_values_t *cfg; + + this = (a52dec_class_t *) xine_xmalloc (sizeof (a52dec_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + cfg = this->config = xine->config; + + this->a52_level = (float) cfg->register_range (cfg, "audio.a52.level", 100, + 0, 200, + _("A/52 volume"), + _("With A/52 audio, you can modify the volume " + "at the decoder level. This has the advantage " + "of the audio being already decoded for the " + "specified volume, so later operations like " + "channel downmixing will work on an audio stream " + "of the given volume."), + 10, a52_level_change_cb, this) / 100.0; + this->disable_dynrng_compress = !cfg->register_bool (cfg, "audio.a52.dynamic_range", 0, + _("use A/52 dynamic range compression"), + _("Dynamic range compression limits the dynamic " + "range of the audio. This means making the loud " + "sounds softer, and the soft sounds louder, so you can " + "more easily listen to the audio in a noisy " + "environment without disturbing anyone."), + 0, dynrng_compress_change_cb, this); + this->enable_surround_downmix = cfg->register_bool (cfg, "audio.a52.surround_downmix", 0, + _("downmix audio to 2 channel surround stereo"), + _("When you want to listen to multichannel surround " + "sound, but you have only two speakers or a " + "surround decoder or amplifier which does some " + "sort of matrix surround decoding like prologic, " + "you should enable this option so that the " + "additional channels are mixed into the stereo " + "signal."), + 0, surround_downmix_change_cb, this); + lprintf ("init_plugin called\n"); + return this; +} + +static void a52_level_change_cb(void *this_gen, xine_cfg_entry_t *entry) +{ + ((a52dec_class_t *)this_gen)->a52_level = entry->num_value / 100.0; +} + +static void dynrng_compress_change_cb(void *this_gen, xine_cfg_entry_t *entry) +{ + ((a52dec_class_t *)this_gen)->disable_dynrng_compress = !entry->num_value; +} + +static void surround_downmix_change_cb(void *this_gen, xine_cfg_entry_t *entry) +{ + ((a52dec_class_t *)this_gen)->enable_surround_downmix = entry->num_value; +} + + +static uint32_t audio_types[] = { + BUF_AUDIO_A52, + BUF_AUDIO_DNET, + 0 + }; + +static const decoder_info_t dec_info_audio = { + audio_types, /* supported types */ + 5 /* priority */ +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_DECODER | PLUGIN_MUST_PRELOAD, 15, "a/52", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/libxineadec/xine_faad_decoder.c b/src/libxineadec/xine_faad_decoder.c new file mode 100644 index 000000000..169874a44 --- /dev/null +++ b/src/libxineadec/xine_faad_decoder.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2000-2005 the xine project + * + * This file is part of xine, a free 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.49 2007/02/20 00:34:57 dgp85 Exp $ + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define LOG_MODULE "libfaad" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "audio_out.h" +#include "buffer.h" +#include "xineutils.h" +#include "common.h" +#include "structs.h" +#include "decoder.h" +#include "syntax.h" + +#define FAAD_MIN_STREAMSIZE 768 /* 6144 bits/channel */ + +typedef struct { + audio_decoder_class_t decoder_class; +} faad_class_t; + +typedef struct faad_decoder_s { + audio_decoder_t audio_decoder; + + xine_stream_t *stream; + + /* faad2 stuff */ + NeAACDecHandle faac_dec; + NeAACDecConfigurationPtr faac_cfg; + NeAACDecFrameInfo faac_finfo; + int faac_failed; + + int raw_mode; + + unsigned char *buf; + int size; + int rec_audio_src_size; + int max_audio_src_size; + int pts; + + unsigned char *dec_config; + int dec_config_size; + + uint32_t rate; + int bits_per_sample; + unsigned char num_channels; + int sbr; + + int output_open; + + unsigned long total_time; + unsigned long total_data; +} faad_decoder_t; + + +static void faad_reset (audio_decoder_t *this_gen) { + + faad_decoder_t *this = (faad_decoder_t *) this_gen; + this->size = 0; +} + +static void faad_meta_info_set ( faad_decoder_t *this ) { + switch (this->num_channels) { + case 1: + if (this->faac_finfo.sbr == SBR_UPSAMPLED) + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "HE-AAC 1.0 (libfaad)"); + else + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "AAC 1.0 (libfaad)"); + break; + case 2: + /* check if this is downmixed 5.1 */ + if (!this->faac_cfg || !this->faac_cfg->downMatrix) { + if (this->faac_finfo.sbr == SBR_UPSAMPLED) + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "HE-AAC 2.0 (libfaad)"); + else + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "AAC 2.0 (libfaad)"); + break; + } + case 6: + if (this->faac_finfo.sbr == SBR_UPSAMPLED) + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "HE-AAC 5.1 (libfaad)"); + else + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, + "AAC 5.1 (libfaad)"); + break; + } +} + +static int faad_open_dec( faad_decoder_t *this ) { + int used; + + this->faac_dec = NeAACDecOpen(); + if( !this->faac_dec ) { + xprintf( this->stream->xine, XINE_VERBOSITY_LOG, + _("libfaad: libfaad NeAACDecOpen() failed.\n")); + this->faac_failed++; + } else { + if( this->dec_config ) { + used = NeAACDecInit2(this->faac_dec, this->dec_config, this->dec_config_size, + &this->rate, &this->num_channels); + + if( used < 0 ) { + xprintf( this->stream->xine, XINE_VERBOSITY_LOG, + _("libfaad: libfaad NeAACDecInit2 failed.\n")); + this->faac_failed++; + } else + lprintf( "NeAACDecInit2 returned rate=%"PRId32" channels=%d\n", + this->rate, this->num_channels ); + } else { + used = NeAACDecInit(this->faac_dec, this->buf, this->size, + &this->rate, &this->num_channels); + + if( used < 0 ) { + xprintf ( this->stream->xine, XINE_VERBOSITY_LOG, + _("libfaad: libfaad NeAACDecInit failed.\n")); + this->faac_failed++; + } else { + lprintf( "NeAACDecInit() returned rate=%"PRId32" channels=%d (used=%d)\n", + this->rate, this->num_channels, used); + + this->size -= used; + memmove( this->buf, &this->buf[used], this->size ); + } + } + } + + if( !this->bits_per_sample ) + this->bits_per_sample = 16; + + if( this->faac_failed ) { + if( this->faac_dec ) { + NeAACDecClose( this->faac_dec ); + this->faac_dec = NULL; + } + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0); + } else { + faad_meta_info_set(this); + } + + return this->faac_failed; +} + +static int faad_open_output( faad_decoder_t *this ) { + int ao_cap_mode; + + this->rec_audio_src_size = this->num_channels * FAAD_MIN_STREAMSIZE; + + switch( this->num_channels ) { + case 1: + ao_cap_mode=AO_CAP_MODE_MONO; + break; + case 6: + if(this->stream->audio_out->get_capabilities(this->stream->audio_out) & + AO_CAP_MODE_5_1CHANNEL) { + ao_cap_mode = AO_CAP_MODE_5_1CHANNEL; + break; + } else { + this->faac_cfg = NeAACDecGetCurrentConfiguration(this->faac_dec); + this->faac_cfg->downMatrix = 1; + NeAACDecSetConfiguration(this->faac_dec, this->faac_cfg); + this->num_channels = 2; + } + case 2: + ao_cap_mode=AO_CAP_MODE_STEREO; + break; + } + + this->output_open = this->stream->audio_out->open (this->stream->audio_out, + this->stream, + this->bits_per_sample, + this->rate, + ao_cap_mode) ; + return this->output_open; +} + +static void faad_decode_audio ( faad_decoder_t *this, int end_frame ) { + int used, decoded, outsize; + uint8_t *sample_buffer; + uint8_t *inbuf; + audio_buffer_t *audio_buffer; + int sample_size = this->size; + + if( !this->faac_dec ) + return; + + inbuf = this->buf; + while( (!this->raw_mode && end_frame && this->size >= 10) || + (this->raw_mode && this->size >= this->rec_audio_src_size) ) { + + sample_buffer = NeAACDecDecode(this->faac_dec, + &this->faac_finfo, inbuf, sample_size); + + if( !sample_buffer ) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "libfaad: %s\n", NeAACDecGetErrorMessage(this->faac_finfo.error)); + used = 1; + } else { + used = this->faac_finfo.bytesconsumed; + + /* raw AAC parameters might only be known after decoding the first frame */ + if( !this->dec_config && + (this->num_channels != this->faac_finfo.channels || + this->rate != this->faac_finfo.samplerate) ) { + + this->num_channels = this->faac_finfo.channels; + this->rate = this->faac_finfo.samplerate; + + lprintf("faacDecDecode() returned rate=%"PRId32" channels=%d used=%d\n", + this->rate, this->num_channels, used); + + this->stream->audio_out->close (this->stream->audio_out, this->stream); + this->output_open = 0; + faad_open_output( this ); + + faad_meta_info_set( this ); + } + + /* faad doesn't tell us about sbr until after the first frame */ + if (this->sbr != this->faac_finfo.sbr) { + this->sbr = this->faac_finfo.sbr; + faad_meta_info_set( this ); + } + + /* estimate bitrate */ + this->total_time += (1000*this->faac_finfo.samples/(this->rate*this->num_channels)); + this->total_data += 8*used; + + if ((this->total_time > LONG_MAX) || (this->total_data > LONG_MAX)) { + this->total_time >>= 2; + this->total_data >>= 2; + } + + if (this->total_time) + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, + 1000*(this->total_data/this->total_time)); + + decoded = this->faac_finfo.samples * 2; /* 1 sample = 2 bytes */ + + lprintf("decoded %d/%d output %ld\n", + used, this->size, this->faac_finfo.samples ); + + while( decoded ) { + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); + + if( decoded < audio_buffer->mem_size ) + outsize = decoded; + else + outsize = audio_buffer->mem_size; + + xine_fast_memcpy( audio_buffer->mem, sample_buffer, outsize ); + + audio_buffer->num_frames = outsize / (this->num_channels*2); + audio_buffer->vpts = this->pts; + + this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + + this->pts = 0; + decoded -= outsize; + sample_buffer += outsize; + } + } + + if(used >= this->size){ + this->size = 0; + } else { + this->size -= used; + inbuf += used; + } + + if( !this->raw_mode ) + this->size = 0; + } + + if( this->size ) + memmove( this->buf, inbuf, this->size); + +} + +static void faad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + + faad_decoder_t *this = (faad_decoder_t *) this_gen; + + if (buf->decoder_flags & BUF_FLAG_PREVIEW) + return; + + /* store config information from ESDS mp4/qt atom */ + if( !this->faac_dec && (buf->decoder_flags & BUF_FLAG_SPECIAL) && + buf->decoder_info[1] == BUF_SPECIAL_DECODER_CONFIG ) { + + this->dec_config = xine_xmalloc(buf->decoder_info[2]); + this->dec_config_size = buf->decoder_info[2]; + memcpy(this->dec_config, buf->decoder_info_ptr[2], buf->decoder_info[2]); + + if( faad_open_dec(this) ) + return; + + this->raw_mode = 0; + } + + /* get audio parameters from file header + (may be overwritten by libfaad returned parameters) */ + if (buf->decoder_flags & BUF_FLAG_STDHEADER) { + this->rate=buf->decoder_info[1]; + this->bits_per_sample=buf->decoder_info[2] ; + this->num_channels=buf->decoder_info[3] ; + + if( buf->size > sizeof(xine_waveformatex) ) { + xine_waveformatex *wavex = (xine_waveformatex *) buf->content; + + if( wavex->cbSize > 0 ) { + this->dec_config = xine_xmalloc(wavex->cbSize); + this->dec_config_size = wavex->cbSize; + memcpy(this->dec_config, buf->content + sizeof(xine_waveformatex), + wavex->cbSize); + + if( faad_open_dec(this) ) + return; + + this->raw_mode = 0; + } + } + } else { + + lprintf ("decoding %d data bytes...\n", buf->size); + + if( (int)buf->size <= 0 || this->faac_failed ) + return; + + if( !this->size ) + this->pts = buf->pts; + + if( this->size + buf->size > this->max_audio_src_size ) { + this->max_audio_src_size = this->size + 2 * buf->size; + this->buf = realloc( this->buf, this->max_audio_src_size ); + } + + memcpy (&this->buf[this->size], buf->content, buf->size); + this->size += buf->size; + + if( !this->faac_dec && faad_open_dec(this) ) + return; + + /* open audio device as needed */ + if (!this->output_open) { + faad_open_output( this ); + } + + faad_decode_audio(this, buf->decoder_flags & BUF_FLAG_FRAME_END ); + } +} + +static void faad_discontinuity (audio_decoder_t *this_gen) { +} + +static void faad_dispose (audio_decoder_t *this_gen) { + + faad_decoder_t *this = (faad_decoder_t *) this_gen; + + if (this->output_open) + this->stream->audio_out->close (this->stream->audio_out, this->stream); + this->output_open = 0; + + if( this->buf ) + free(this->buf); + this->buf = NULL; + this->size = 0; + this->max_audio_src_size = 0; + + if( this->dec_config ) + free(this->dec_config); + this->dec_config = NULL; + this->dec_config_size = 0; + + if( this->faac_dec ) + NeAACDecClose(this->faac_dec); + this->faac_dec = NULL; + this->faac_failed = 0; + + free (this); +} + + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { + + faad_decoder_t *this ; + + this = (faad_decoder_t *) xine_xmalloc (sizeof (faad_decoder_t)); + + this->audio_decoder.decode_data = faad_decode_data; + this->audio_decoder.reset = faad_reset; + this->audio_decoder.discontinuity = faad_discontinuity; + this->audio_decoder.dispose = faad_dispose; + + this->stream = stream; + this->output_open = 0; + this->raw_mode = 1; + this->faac_dec = NULL; + this->faac_failed = 0; + this->buf = NULL; + this->size = 0; + this->max_audio_src_size = 0; + this->dec_config = NULL; + this->dec_config_size = 0; + this->total_time = 0; + this->total_data = 0; + + this->rate = 0; + + return &this->audio_decoder; +} + +static char *get_identifier (audio_decoder_class_t *this) { + return "FAAD"; +} + +static char *get_description (audio_decoder_class_t *this) { + return "Freeware Advanced Audio Decoder"; +} + +static void dispose_class (audio_decoder_class_t *this) { + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + faad_class_t *this ; + + this = (faad_class_t *) xine_xmalloc (sizeof (faad_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + return this; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_AAC, 0 + }; + +static const decoder_info_t dec_info_audio = { + audio_types, /* supported types */ + 1 /* priority */ +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_DECODER, 15, "faad", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/libxineadec/xine_mad_decoder.c b/src/libxineadec/xine_mad_decoder.c new file mode 100644 index 000000000..98695db68 --- /dev/null +++ b/src/libxineadec/xine_mad_decoder.c @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free 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.57 2006/07/10 22:08:29 dgp85 Exp $ + * + * stuff needed to turn libmad into a xine decoder plugin + */ + +#include <stdlib.h> +#include <string.h> +#include <config.h> + +#ifdef HAVE_MAD_H +#include <mad.h> +#endif + +#define LOG_MODULE "mad_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "audio_out.h" +#include "buffer.h" +#include "xineutils.h" + +#ifdef HAVE_MAD_H +# include <mad.h> +#else +# include "frame.h" +# include "synth.h" +#endif + +#define INPUT_BUF_SIZE 16384 + +typedef struct { + audio_decoder_class_t decoder_class; +} mad_class_t; + +typedef struct mad_decoder_s { + audio_decoder_t audio_decoder; + + xine_stream_t *xstream; + + int64_t pts; + + struct mad_synth synth; + struct mad_stream stream; + struct mad_frame frame; + + int output_sampling_rate; + int output_open; + int output_mode; + + uint8_t buffer[INPUT_BUF_SIZE]; + int bytes_in_buffer; + int preview_mode; + +} mad_decoder_t; + +static void mad_reset (audio_decoder_t *this_gen) { + + mad_decoder_t *this = (mad_decoder_t *) this_gen; + + mad_synth_finish (&this->synth); + mad_frame_finish (&this->frame); + mad_stream_finish(&this->stream); + + this->pts = 0; + this->bytes_in_buffer = 0; + this->preview_mode = 0; + + mad_synth_init (&this->synth); + mad_stream_init (&this->stream); + this->stream.options = MAD_OPTION_IGNORECRC; + mad_frame_init (&this->frame); +} + + +static void mad_discontinuity (audio_decoder_t *this_gen) { + + mad_decoder_t *this = (mad_decoder_t *) this_gen; + + this->pts = 0; +} + +/* utility to scale and round samples to 16 bits */ + +static inline +signed int scale(mad_fixed_t sample) +{ + /* round */ + sample += (1L << (MAD_F_FRACBITS - 16)); + + /* clip */ + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - 16); +} + +/* +static int head_check(mad_decoder_t *this) { + + if( (this->header & 0xffe00000) != 0xffe00000) + return 0; + if(!((this->header>>17)&3)) + return 0; + if( ((this->header>>12)&0xf) == 0xf) + return 0; + if( ((this->header>>10)&0x3) == 0x3 ) + return 0; + return 1; +} +*/ + +static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + + mad_decoder_t *this = (mad_decoder_t *) this_gen; + + lprintf ("decode data, decoder_flags: %d\n", buf->decoder_flags); + + if (buf->size>(INPUT_BUF_SIZE-this->bytes_in_buffer)) { + xprintf (this->xstream->xine, XINE_VERBOSITY_DEBUG, + "libmad: ALERT input buffer too small (%d bytes, %d avail)!\n", + buf->size, INPUT_BUF_SIZE-this->bytes_in_buffer); + buf->size = INPUT_BUF_SIZE-this->bytes_in_buffer; + } + + if ((buf->decoder_flags & BUF_FLAG_HEADER) == 0) { + + /* reset decoder on leaving preview mode */ + if ((buf->decoder_flags & BUF_FLAG_PREVIEW) == 0) { + if (this->preview_mode) { + mad_reset (this_gen); + } + } else { + this->preview_mode = 1; + } + + xine_fast_memcpy (&this->buffer[this->bytes_in_buffer], + buf->content, buf->size); + this->bytes_in_buffer += buf->size; + + /* + printf ("libmad: decode data - doing it\n"); + */ + + mad_stream_buffer (&this->stream, this->buffer, + this->bytes_in_buffer); + + while (1) { + + if (mad_frame_decode (&this->frame, &this->stream) != 0) { + + if (this->stream.next_frame) { + int num_bytes = + this->buffer + this->bytes_in_buffer - this->stream.next_frame; + + /* printf("libmad: MAD_ERROR_BUFLEN\n"); */ + + memmove(this->buffer, this->stream.next_frame, num_bytes); + this->bytes_in_buffer = num_bytes; + } + + switch (this->stream.error) { + + case MAD_ERROR_BUFLEN: + return; + + default: + mad_stream_buffer (&this->stream, this->buffer, + this->bytes_in_buffer); + } + + } else { + int mode = (this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? AO_CAP_MODE_MONO : AO_CAP_MODE_STEREO; + + if (!this->output_open + || (this->output_sampling_rate != this->frame.header.samplerate) + || (this->output_mode != mode)) { + + lprintf ("audio sample rate %d mode %08x\n", this->frame.header.samplerate, mode); + + /* the mpeg audio demuxer can set audio bitrate */ + if (! _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE)) { + _x_stream_info_set(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE, + this->frame.header.bitrate); + } + + /* the mpeg audio demuxer can set this meta info */ + if (! _x_meta_info_get(this->xstream, XINE_META_INFO_AUDIOCODEC)) { + switch (this->frame.header.layer) { + case MAD_LAYER_I: + _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, + "MPEG audio layer 1 (lib: MAD)"); + break; + case MAD_LAYER_II: + _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, + "MPEG audio layer 2 (lib: MAD)"); + break; + case MAD_LAYER_III: + _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, + "MPEG audio layer 3 (lib: MAD)"); + break; + default: + _x_meta_info_set_utf8(this->xstream, XINE_META_INFO_AUDIOCODEC, + "MPEG audio (lib: MAD)"); + } + } + + if (this->output_open) { + this->xstream->audio_out->close (this->xstream->audio_out, this->xstream); + this->output_open = 0; + } + if (!this->output_open) { + this->output_open = this->xstream->audio_out->open(this->xstream->audio_out, + this->xstream, 16, + this->frame.header.samplerate, + mode) ; + } + if (!this->output_open) { + return; + } + this->output_sampling_rate = this->frame.header.samplerate; + this->output_mode = mode; + } + + mad_synth_frame (&this->synth, &this->frame); + + if ( (buf->decoder_flags & BUF_FLAG_PREVIEW) == 0 ) { + + unsigned int nchannels, nsamples; + mad_fixed_t const *left_ch, *right_ch; + struct mad_pcm *pcm = &this->synth.pcm; + audio_buffer_t *audio_buffer; + uint16_t *output; + + audio_buffer = this->xstream->audio_out->get_buffer (this->xstream->audio_out); + output = audio_buffer->mem; + + nchannels = pcm->channels; + nsamples = pcm->length; + left_ch = pcm->samples[0]; + right_ch = pcm->samples[1]; + + while (nsamples--) { + /* output sample(s) in 16-bit signed little-endian PCM */ + + *output++ = scale(*left_ch++); + + if (nchannels == 2) + *output++ = scale(*right_ch++); + + } + + audio_buffer->num_frames = pcm->length; + audio_buffer->vpts = buf->pts; + + this->xstream->audio_out->put_buffer (this->xstream->audio_out, audio_buffer, this->xstream); + + buf->pts = 0; + + } + + lprintf ("decode worked\n"); + } + } + + } +} + +static void mad_dispose (audio_decoder_t *this_gen) { + + mad_decoder_t *this = (mad_decoder_t *) this_gen; + + mad_synth_finish (&this->synth); + mad_frame_finish (&this->frame); + mad_stream_finish(&this->stream); + + if (this->output_open) { + this->xstream->audio_out->close (this->xstream->audio_out, this->xstream); + this->output_open = 0; + } + + free (this_gen); +} + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { + + mad_decoder_t *this ; + + this = (mad_decoder_t *) xine_xmalloc (sizeof (mad_decoder_t)); + + this->audio_decoder.decode_data = mad_decode_data; + this->audio_decoder.reset = mad_reset; + this->audio_decoder.discontinuity = mad_discontinuity; + this->audio_decoder.dispose = mad_dispose; + + this->output_open = 0; + this->bytes_in_buffer = 0; + this->preview_mode = 0; + + this->xstream = stream; + + mad_synth_init (&this->synth); + mad_stream_init (&this->stream); + mad_frame_init (&this->frame); + + this->stream.options = MAD_OPTION_IGNORECRC; + + lprintf ("init\n"); + + return &this->audio_decoder; +} + +/* + * mad plugin class + */ + +static char *get_identifier (audio_decoder_class_t *this) { + return "mad"; +} + +static char *get_description (audio_decoder_class_t *this) { + return "libmad based mpeg audio layer 1/2/3 decoder plugin"; +} + +static void dispose_class (audio_decoder_class_t *this) { + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + mad_class_t *this; + + this = (mad_class_t *) xine_xmalloc (sizeof (mad_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + return this; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_MPEG, 0 +}; + +static const decoder_info_t dec_info_audio = { + audio_types, /* supported types */ + 7 /* priority */ +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_DECODER, 15, "mad", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/libxineadec/xine_speex_decoder.c b/src/libxineadec/xine_speex_decoder.c deleted file mode 100644 index 034e726a6..000000000 --- a/src/libxineadec/xine_speex_decoder.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2000-2003 the xine project - * - * This file is part of xine, a free 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.22 2007/01/19 01:48:05 dgp85 Exp $ - * - * (ogg/)speex audio decoder plugin (libspeex wrapper) for xine - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <string.h> - -#define LOG_MODULE "speex_decoder" -#define LOG_VERBOSE -/* -#define LOG -*/ -#define LOG_BUFFERS 0 - -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" - -#include <ogg/ogg.h> - -#include <speex/speex.h> -#include <speex/speex_header.h> -#include <speex/speex_callbacks.h> -#include <speex/speex_stereo.h> - -#define MAX_FRAME_SIZE 2000 - -typedef struct { - audio_decoder_class_t decoder_class; -} speex_class_t; - -typedef struct speex_decoder_s { - audio_decoder_t audio_decoder; - - int64_t pts; - - int output_sampling_rate; - int output_open; - int output_mode; - - /* speex stuff */ - void *st; - int frame_size; - int rate; - int nframes; - int channels; - SpeexBits bits; - SpeexStereoState stereo; - int expect_metadata; - - int header_count; - - xine_stream_t *stream; - -} speex_decoder_t; - - -static void speex_reset (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - speex_bits_init (&this->bits); -} - -static void speex_discontinuity (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - this->pts=0; -} - -/* Known speex comment keys from ogg123 sources*/ -static struct { - char *key; /* includes the '=' for programming convenience */ - int xine_metainfo_index; -} speex_comment_keys[] = { - {"ARTIST=", XINE_META_INFO_ARTIST}, - {"ALBUM=", XINE_META_INFO_ALBUM}, - {"TITLE=", XINE_META_INFO_TITLE}, - {"GENRE=", XINE_META_INFO_GENRE}, - {"DESCRIPTION=", XINE_META_INFO_COMMENT}, - {"DATE=", XINE_META_INFO_YEAR}, - {NULL, 0} -}; - -#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ - ((buf[base+2]<<16)&0xff0000)| \ - ((buf[base+1]<<8)&0xff00)| \ - (buf[base]&0xff)) - -static -void read_metadata (speex_decoder_t *this, char * comments, int length) -{ - char * c = comments; - int len, i, nb_fields; - char * end; - - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "speex"); - - if (length < 8) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - end = c+length; - len = readint (c, 0); - c += 4; - - if (c+len > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - -#ifdef LOG - /* Encoder */ - printf ("libspeex: "); - fwrite (c, 1, len, stdout); - printf ("\n"); -#endif - - c += len; - - if (c+4 > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - nb_fields = readint (c, 0); - c += 4; - - for (i = 0; i < nb_fields; i++) { - if (c+4 > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - len = readint (c, 0); - c += 4; - if (c+len > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - -#ifdef LOG - printf ("libspeex: "); - fwrite (c, 1, len, stdout); - printf ("\n"); -#endif - - for (i = 0; speex_comment_keys[i].key != NULL; i++) { - - if ( !strncasecmp (speex_comment_keys[i].key, c, - strlen(speex_comment_keys[i].key)) ) { - int keylen = strlen(speex_comment_keys[i].key); - char meta_info[(len - keylen) + 1]; - - lprintf ("known metadata %d %d\n", - i, speex_comment_keys[i].xine_metainfo_index); - - snprintf(meta_info, (len - keylen), "%s", c + keylen); - _x_meta_info_set_utf8(this->stream, speex_comment_keys[i].xine_metainfo_index, meta_info); - } - } - - c += len; - } -} - -static void speex_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - llprintf (LOG_BUFFERS, "decode buf=%8p content=%8p flags=%08x\n", - buf, buf->content, buf->decoder_flags); - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - lprintf ("preview buffer, %d headers to go\n", this->header_count); - - if (this->header_count) { - - if (!this->st) { - SpeexMode * spx_mode; - SpeexHeader * spx_header; - int modeID; - int bitrate; - - speex_bits_init (&this->bits); - - spx_header = speex_packet_to_header (buf->content, buf->size); - - if (!spx_header) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: could not read Speex header\n"); - return; - } - - modeID = spx_header->mode; - spx_mode = (SpeexMode *) speex_mode_list[modeID]; - - if (spx_mode->bitstream_version != spx_header->mode_bitstream_version) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: incompatible Speex mode bitstream version\n"); - return; - } - - this->st = speex_decoder_init (spx_mode); - if (!this->st) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: decoder initialization failed\n"); - return; - } - - this->rate = spx_header->rate; - speex_decoder_ctl (this->st, SPEEX_SET_SAMPLING_RATE, &this->rate); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, - this->rate); - - this->channels = spx_header->nb_channels; - if (this->channels == 2) { - SpeexCallback callback; - - callback.callback_id = SPEEX_INBAND_STEREO; - callback.func = speex_std_stereo_request_handler; - callback.data = &this->stereo; - speex_decoder_ctl (this->st, SPEEX_SET_HANDLER, &callback); - } - - this->nframes = spx_header->frames_per_packet; - if (!this->nframes) this->nframes = 1; - - speex_decoder_ctl (this->st, SPEEX_GET_FRAME_SIZE, &this->frame_size); - - speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); - if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); - - this->header_count += spx_header->extra_headers; - this->expect_metadata = 1; - - free (spx_header); - } else if (this->expect_metadata) { - read_metadata (this, buf->content, buf->size); - } - - this->header_count--; - - if (!this->header_count) { - int mode = _x_ao_channels2mode(this->channels); - - if (!this->output_open) { - this->output_open = - this->stream->audio_out->open(this->stream->audio_out, - this->stream, - 16, - this->rate, - mode); - lprintf ("this->output_open after attempt is %d\n", this->output_open); - } - } - } - - } else if (this->output_open) { - int i, j; - - audio_buffer_t *audio_buffer; - - audio_buffer = - this->stream->audio_out->get_buffer (this->stream->audio_out); - - speex_bits_read_from (&this->bits, buf->content, buf->size); - - for (j = 0; j < this->nframes; j++) { - int ret; - int bitrate; - - ret = speex_decode_int (this->st, &this->bits, audio_buffer->mem); - - if (ret==-1) - break; - if (ret==-2) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding error, corrupted stream?\n"); - break; - } - if (speex_bits_remaining(&this->bits)<0) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding overflow, corrupted stream?\n"); - break; - } - - if (this->channels == 2) { - speex_decode_stereo_int (audio_buffer->mem, this->frame_size, &this->stereo); - } - - speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); - if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); - - audio_buffer->vpts = this->pts; - this->pts=0; - audio_buffer->num_frames = this->frame_size; - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - buf->pts=0; - - } - } - else { - llprintf (LOG_BUFFERS, "output not open\n"); - } -} - -static void speex_dispose (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - if (this->st) { - speex_decoder_destroy (this->st); - } - speex_bits_destroy (&this->bits); - - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - - free (this_gen); -} - -static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, - xine_stream_t *stream) { - - speex_decoder_t *this ; - static SpeexStereoState init_stereo = SPEEX_STEREO_STATE_INIT; - - this = (speex_decoder_t *) xine_xmalloc (sizeof (speex_decoder_t)); - - this->audio_decoder.decode_data = speex_decode_data; - this->audio_decoder.reset = speex_reset; - this->audio_decoder.discontinuity = speex_discontinuity; - this->audio_decoder.dispose = speex_dispose; - this->stream = stream; - - this->output_open = 0; - this->header_count = 1; - this->expect_metadata = 0; - - this->st = NULL; - - this->channels = 1; - - memcpy (&this->stereo, &init_stereo, sizeof (SpeexStereoState)); - - return (audio_decoder_t *) this; -} - -/* - * speex plugin class - */ - -static char *get_identifier (audio_decoder_class_t *this) { - return "speex"; -} - -static char *get_description (audio_decoder_class_t *this) { - return "Speex audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - - speex_class_t *this; - - this = (speex_class_t *) xine_xmalloc (sizeof (speex_class_t)); - - this->decoder_class.open_plugin = open_plugin; - this->decoder_class.get_identifier = get_identifier; - this->decoder_class.get_description = get_description; - this->decoder_class.dispose = dispose_class; - - return this; -} - -static uint32_t audio_types[] = { - BUF_AUDIO_SPEEX, 0 - }; - -static const decoder_info_t dec_info_audio = { - audio_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_DECODER, 15, "speex", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/src/libxineadec/xine_vorbis_decoder.c b/src/libxineadec/xine_vorbis_decoder.c deleted file mode 100644 index 7fc1b9197..000000000 --- a/src/libxineadec/xine_vorbis_decoder.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2000-2003 the xine project - * - * This file is part of xine, a free 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.48 2006/12/04 13:59:38 dgp85 Exp $ - * - * (ogg/)vorbis audio decoder plugin (libvorbis wrapper) for xine - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <string.h> - -#define LOG_MODULE "vorbis_decoder" -#define LOG_VERBOSE -/* -#define LOG -*/ - -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" - -#include <ogg/ogg.h> -#include <vorbis/codec.h> - -#define MAX_NUM_SAMPLES 4096 - -typedef struct { - audio_decoder_class_t decoder_class; -} vorbis_class_t; - -typedef struct vorbis_decoder_s { - audio_decoder_t audio_decoder; - - int64_t pts; - - int output_sampling_rate; - int output_open; - int output_mode; - - ogg_packet op; /* we must use this struct to sent data to libvorbis */ - - /* vorbis stuff */ - vorbis_info vi; /* stores static vorbis bitstream settings */ - vorbis_comment vc; - vorbis_dsp_state vd; /* central working state for packet->PCM decoder */ - vorbis_block vb; /* local working state for packet->PCM decoder */ - - int16_t convbuffer[MAX_NUM_SAMPLES]; - int convsize; - - int header_count; - - xine_stream_t *stream; - -} vorbis_decoder_t; - - -static void vorbis_reset (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - if( !this->header_count ) - vorbis_block_init(&this->vd,&this->vb); -} - -static void vorbis_discontinuity (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - this->pts=0; -} - -/* Known vorbis comment keys from ogg123 sources*/ -static const struct { - const char *key; /* includes the '=' for programming convenience */ - int xine_metainfo_index; -} vorbis_comment_keys[] = { - {"ARTIST=", XINE_META_INFO_ARTIST}, - {"ALBUM=", XINE_META_INFO_ALBUM}, - {"TITLE=", XINE_META_INFO_TITLE}, - {"GENRE=", XINE_META_INFO_GENRE}, - {"DESCRIPTION=", XINE_META_INFO_COMMENT}, - {"COMMENT=", XINE_META_INFO_COMMENT}, - {"DATE=", XINE_META_INFO_YEAR}, - {"TRACKNUMBER=", XINE_META_INFO_TRACK_NUMBER}, - {NULL, 0} -}; - -static void get_metadata (vorbis_decoder_t *this) { - - char **ptr=this->vc.user_comments; - while(*ptr){ - - char *comment = *ptr; - int i; - - lprintf("%s\n", comment); - - for (i = 0; vorbis_comment_keys[i].key != NULL; i++) { - - if ( !strncasecmp (vorbis_comment_keys[i].key, comment, - strlen(vorbis_comment_keys[i].key)) ) { - - lprintf ("known metadata %d %d\n", - i, vorbis_comment_keys[i].xine_metainfo_index); - - _x_meta_info_set_utf8(this->stream, vorbis_comment_keys[i].xine_metainfo_index, - comment + strlen(vorbis_comment_keys[i].key)); - - } - } - ++ptr; - } - - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "vorbis"); -} - -static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - memset( &this->op, 0, sizeof(this->op) ); - this->op.packet = buf->content; - this->op.bytes = buf->size; - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - lprintf ("%d headers to go\n", this->header_count); - - if (this->header_count) { - int res = 0; - - if (this->header_count == 3) - this->op.b_o_s = 1; - - - if( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ){ - /* error case; not a vorbis header */ - xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); - xine_hexdump(this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); - return; - } - - this->header_count--; - - if (!this->header_count) { - - int mode = AO_CAP_MODE_MONO; - - get_metadata (this); - - mode = _x_ao_channels2mode(this->vi.channels); - - this->convsize=MAX_NUM_SAMPLES/this->vi.channels; - - if (!this->output_open) { - this->output_open = this->stream->audio_out->open(this->stream->audio_out, - this->stream, - 16, - this->vi.rate, - mode) ; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, - this->vi.bitrate_nominal); - - } - - /* OK, got and parsed all three headers. Initialize the Vorbis - * packet->PCM decoder. */ - lprintf("all three headers parsed. initializing decoder.\n"); - /* initialize central decode state */ - vorbis_synthesis_init(&this->vd,&this->vi); - /* initialize local state for most of the decode so multiple - * block decodes can proceed in parallel. We could init - * multiple vorbis_block structures for vd here */ - vorbis_block_init(&this->vd,&this->vb); - } - } - - } else if (this->output_open) { - - float **pcm; - int samples; - - if(vorbis_synthesis(&this->vb,&this->op)==0) - vorbis_synthesis_blockin(&this->vd,&this->vb); - - if (buf->pts!=0) - this->pts=buf->pts; - - while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ - - /* **pcm is a multichannel float vector. In stereo, for - * example, pcm[0][...] is left, and pcm[1][...] is right. - * samples is the size of each channel. Convert the float - * values (-1.<=range<=1.) to whatever PCM format and write - * it out - */ - - int i,j; - int clipflag=0; - int bout=(samples<this->convsize?samples:this->convsize); - audio_buffer_t *audio_buffer; - - audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); - - /* convert floats to 16 bit signed ints (host order) and - interleave */ - for(i=0;i<this->vi.channels;i++){ - ogg_int16_t *ptr=audio_buffer->mem+i; - float *mono=pcm[i]; - for(j=0;j<bout;j++){ - int val=mono[j]*32767.f; - /* might as well guard against clipping */ - if(val>32767){ - val=32767; - clipflag=1; - } - if(val<-32768){ - val=-32768; - clipflag=1; - } - *ptr=val; - ptr+=this->vi.channels; - } - } - - audio_buffer->vpts = this->pts; - this->pts=0; - audio_buffer->num_frames = bout; - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - buf->pts=0; - - /* tell libvorbis how many samples we actually consumed */ - vorbis_synthesis_read(&this->vd,bout); - } - } - lprintf("output not open\n"); -} - -static void vorbis_dispose (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - if( !this->header_count ) { - lprintf("deinitializing decoder\n"); - - vorbis_block_clear(&this->vb); - vorbis_dsp_clear(&this->vd); - } - - vorbis_comment_clear(&this->vc); - - vorbis_info_clear(&this->vi); /* must be called last */ - - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - - lprintf("libvorbis instance destroyed\n"); - - free (this_gen); -} - -static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, - xine_stream_t *stream) { - - vorbis_decoder_t *this ; - - this = (vorbis_decoder_t *) xine_xmalloc (sizeof (vorbis_decoder_t)); - - this->audio_decoder.decode_data = vorbis_decode_data; - this->audio_decoder.reset = vorbis_reset; - this->audio_decoder.discontinuity = vorbis_discontinuity; - this->audio_decoder.dispose = vorbis_dispose; - this->stream = stream; - - this->output_open = 0; - this->header_count = 3; - this->convsize = 0; - - vorbis_info_init(&this->vi); - vorbis_comment_init(&this->vc); - - lprintf("libvorbis decoder instance created\n"); - - return (audio_decoder_t *) this; -} - -/* - * vorbis plugin class - */ - -static char *get_identifier (audio_decoder_class_t *this) { - return "vorbis"; -} - -static char *get_description (audio_decoder_class_t *this) { - return "vorbis audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - - vorbis_class_t *this; - - this = (vorbis_class_t *) xine_xmalloc (sizeof (vorbis_class_t)); - - this->decoder_class.open_plugin = open_plugin; - this->decoder_class.get_identifier = get_identifier; - this->decoder_class.get_description = get_description; - this->decoder_class.dispose = dispose_class; - - return this; -} - -static uint32_t audio_types[] = { - BUF_AUDIO_VORBIS, 0 - }; - -static const decoder_info_t dec_info_audio = { - audio_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_DECODER, 15, "vorbis", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; |