summaryrefslogtreecommitdiff
path: root/src/combined
diff options
context:
space:
mode:
Diffstat (limited to 'src/combined')
-rw-r--r--src/combined/Makefile.am63
-rw-r--r--src/combined/ffmpeg/Makefile.am62
-rw-r--r--src/combined/ffmpeg/ff_audio_decoder.c541
-rw-r--r--src/combined/ffmpeg/ff_dvaudio_decoder.c412
-rw-r--r--src/combined/ffmpeg/ff_mpeg_parser.c321
-rw-r--r--src/combined/ffmpeg/ff_mpeg_parser.h81
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c1875
-rw-r--r--src/combined/ffmpeg/ffmpeg_decoder.c55
-rw-r--r--src/combined/ffmpeg/ffmpeg_decoder.h49
-rw-r--r--src/combined/ffmpeg/ffmpeg_encoder.c328
-rw-r--r--src/combined/flac_decoder.c (renamed from src/combined/decoder_flac.c)60
-rw-r--r--src/combined/flac_demuxer.c (renamed from src/combined/demux_flac.c)65
-rw-r--r--src/combined/nsf_combined.c42
-rw-r--r--src/combined/nsf_combined.h (renamed from src/combined/demux_flac.h)20
-rw-r--r--src/combined/nsf_decoder.c247
-rw-r--r--src/combined/nsf_demuxer.c353
-rw-r--r--src/combined/wavpack_combined.c (renamed from src/combined/combined_wavpack.c)10
-rw-r--r--src/combined/wavpack_combined.h (renamed from src/combined/combined_wavpack.h)11
-rw-r--r--src/combined/wavpack_decoder.c (renamed from src/combined/decoder_wavpack.c)26
-rw-r--r--src/combined/wavpack_demuxer.c (renamed from src/combined/demux_wavpack.c)62
-rw-r--r--src/combined/xine_ogg_demuxer.c2156
-rw-r--r--src/combined/xine_speex_decoder.c398
-rw-r--r--src/combined/xine_theora_decoder.c369
-rw-r--r--src/combined/xine_vorbis_decoder.c366
24 files changed, 7775 insertions, 197 deletions
diff --git a/src/combined/Makefile.am b/src/combined/Makefile.am
index 884fcf0cc..92d49a3e5 100644
--- a/src/combined/Makefile.am
+++ b/src/combined/Makefile.am
@@ -1,21 +1,66 @@
+SUBDIRS = ffmpeg
+
include $(top_srcdir)/misc/Makefile.common
-if HAVE_WAVPACK
+AM_CFLAGS = $(DEFAULT_OCFLAGS) $(VISIBILITY_FLAG)
+AM_LDFLAGS = $(xineplug_ldflags)
+
+if ENABLE_WAVPACK
xineplug_wavpack = xineplug_wavpack.la
endif
-if HAVE_LIBFLAC
+if ENABLE_NOSEFART
+xineplug_nsf = xineplug_nsf.la
+endif
+
+if ENABLE_LIBFLAC
xineplug_flac = xineplug_flac.la
endif
-xineplug_LTLIBRARIES = $(xineplug_wavpack) $(xineplug_flac)
+$(top_builddir)/contrib/nosefart/libnosefart.la:
+ $(MAKE) -C $(top_builddir)/contrib/nosefart
-xineplug_wavpack_la_SOURCES = demux_wavpack.c decoder_wavpack.c combined_wavpack.c combined_wavpack.h
-xineplug_wavpack_la_CFLAGS = $(VISIBILITY_FLAG) $(WAVPACK_CFLAGS) -I$(srcdir)/../demuxers
+xineplug_LTLIBRARIES = \
+ $(xineplug_wavpack) \
+ $(xineplug_flac) \
+ $(xineplug_nsf)
+
+xineplug_wavpack_la_SOURCES = wavpack_demuxer.c wavpack_decoder.c wavpack_combined.c wavpack_combined.h
xineplug_wavpack_la_LIBADD = $(XINE_LIB) $(WAVPACK_LIBS)
-xineplug_wavpack_la_LDFLAGS = $(xineplug_ldflags)
+xineplug_wavpack_la_CFLAGS = $(AM_CFLAGS) $(WAVPACK_CFLAGS)
+xineplug_wavpack_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/demuxers
-xineplug_flac_la_SOURCES = demux_flac.c decoder_flac.c demux_flac.h
-xineplug_flac_la_CFLAGS = $(VISIBILITY_FLAG) $(LIBFLAC_CFLAGS)
+xineplug_flac_la_SOURCES = flac_demuxer.c flac_decoder.c
xineplug_flac_la_LIBADD = $(XINE_LIB) $(LIBFLAC_LIBS)
-xineplug_flac_la_LDFLAGS = $(xineplug_ldflags)
+xineplug_flac_la_CFLAGS = $(AM_CFLAGS) $(LIBFLAC_CFLAGS)
+
+xineplug_nsf_la_SOURCES = nsf_decoder.c nsf_demuxer.c nsf_combined.c nsf_combined.h
+xineplug_nsf_la_LIBADD = $(XINE_LIB) $(top_builddir)/contrib/nosefart/libnosefart.la -lm
+xineplug_nsf_la_CFLAGS = $(AM_CFLAGS) -fno-strict-aliasing
+xineplug_nsf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNSF_PLAYER -I$(top_srcdir)/contrib/nosefart -I$(top_srcdir)/src/demuxers
+
+xineplug_xiph_la_SOURCES = xine_ogg_demuxer.c
+xineplug_xiph_la_LIBADD = $(XINE_LIB) $(LTLIBINTL)
+xineplug_xiph_la_CFLAGS = $(AM_CFLAGS)
+xineplug_xiph_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/demuxers
+
+if ENABLE_VORBIS
+xineplug_LTLIBRARIES += xineplug_xiph.la
+xineplug_xiph_la_SOURCES += xine_vorbis_decoder.c
+xineplug_xiph_la_LIBADD += $(VORBIS_LIBS)
+xineplug_xiph_la_CFLAGS += $(VORBIS_CFLAGS)
+endif
+
+if ENABLE_THEORA
+xineplug_LTLIBRARIES += xineplug_xiph.la
+xineplug_xiph_la_SOURCES += xine_theora_decoder.c
+xineplug_xiph_la_LIBADD += $(THEORA_LIBS)
+xineplug_xiph_la_CFLAGS += $(THEORA_CFLAGS)
+endif
+
+if ENABLE_SPEEX
+xineplug_LTLIBRARIES += xineplug_xiph.la
+xineplug_xiph_la_SOURCES += xine_speex_decoder.c
+xineplug_xiph_la_LIBADD += $(SPEEX_LIBS)
+xineplug_xiph_la_CFLAGS += $(SPEEX_CFLAGS)
+endif
diff --git a/src/combined/ffmpeg/Makefile.am b/src/combined/ffmpeg/Makefile.am
new file mode 100644
index 000000000..b9dee7ea6
--- /dev/null
+++ b/src/combined/ffmpeg/Makefile.am
@@ -0,0 +1,62 @@
+include $(top_srcdir)/misc/Makefile.common
+
+AM_CFLAGS = $(DEFAULT_OCFLAGS) $(VISIBILITY_FLAG)
+AM_CPPFLAGS = $(ZLIB_CPPFLAGS)
+AM_LDFLAGS = $(xineplug_ldflags)
+
+if WITH_EXTERNAL_FFMPEG
+AM_CFLAGS += $(FFMPEG_CFLAGS) $(FFMPEG_POSTPROC_CFLAGS)
+link_ffmpeg = $(FFMPEG_LIBS) $(FFMPEG_POSTPROC_LIBS)
+else
+AM_CPPFLAGS += -I$(top_srcdir)/contrib/ffmpeg/libavutil \
+ -I$(top_srcdir)/contrib/ffmpeg/libavcodec \
+ -I$(top_srcdir)/contrib/ffmpeg/libpostproc
+link_ffmpeg = $(top_builddir)/contrib/ffmpeg/libavcodec/libavcodec.a \
+ $(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a \
+ $(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a
+
+$(top_builddir)/contrib/ffmpeg/libavcodec/libavcodec.a:
+ $(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libavcodec/libavcodec.a
+
+$(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a:
+ $(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libavutil/libavutil.a
+
+$(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a:
+ $(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libpostproc/libpostproc.a
+
+$(top_builddir)/contrib/ffmpeg/config.h:
+ $(MAKE) -C $(top_builddir)/contrib/ ffmpeg/config.mak
+
+ffmpeg_config.h: $(top_builddir)/contrib/ffmpeg/config.h
+ cp $(top_builddir)/contrib/ffmpeg/config.h ffmpeg_config.h
+
+BUILT_SOURCES = ffmpeg_config.h
+CLEANFILES = $(BUILT_SOURCES)
+
+endif
+
+# this must always be included, even if the current machine has no DXR3...
+EXTRA_DIST = ffmpeg_encoder.c
+
+xineplug_LTLIBRARIES = xineplug_decode_ff.la xineplug_decode_dvaudio.la
+
+if ENABLE_DXR3
+AM_CFLAGS += $(X_CFLAGS)
+AM_CPPFLAGS += -I$(top_srcdir)/src/dxr3
+xineplug_decode_ff_la_SOURCES = ffmpeg_decoder.c ff_audio_decoder.c ff_video_decoder.c \
+ ffmpeg_encoder.c ff_mpeg_parser.c ffmpeg_decoder.h \
+ ff_mpeg_parser.h
+else
+xineplug_decode_ff_la_SOURCES = ffmpeg_decoder.c ff_audio_decoder.c ff_video_decoder.c \
+ ff_mpeg_parser.c ffmpeg_decoder.h ff_mpeg_parser.h
+endif
+
+nodist_xineplug_decode_ff_la_SOURCES = ffmpeg_config.h
+
+xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \
+ $(link_ffmpeg) $(PTHREAD_LIBS) $(LTLIBINTL)
+xineplug_decode_ff_la_LDFLAGS = $(AM_LDFLAGS) $(IMPURE_TEXT_LDFLAGS)
+
+xineplug_decode_dvaudio_la_SOURCES = ff_dvaudio_decoder.c
+xineplug_decode_dvaudio_la_LIBADD = $(XINE_LIB) $(LTLIBINTL)
+xineplug_decode_dvaudio_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/contrib/ffmpeg/libavcodec
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c
new file mode 100644
index 000000000..f79014fde
--- /dev/null
+++ b/src/combined/ffmpeg/ff_audio_decoder.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2001-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * xine audio decoder plugin using ffmpeg
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+# ifndef HAVE_FFMPEG
+# include "ffmpeg_config.h"
+# endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <math.h>
+
+#define LOG_MODULE "ffmpeg_audio_dec"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#include <xine/xine_internal.h>
+#include <xine/buffer.h>
+#include <xine/xineutils.h>
+#include "bswap.h"
+#include "ffmpeg_decoder.h"
+
+#define AUDIOBUFSIZE (64 * 1024)
+
+typedef struct {
+ audio_decoder_class_t decoder_class;
+} ff_audio_class_t;
+
+typedef struct ff_audio_decoder_s {
+ audio_decoder_t audio_decoder;
+
+ xine_stream_t *stream;
+
+ int output_open;
+ int audio_channels;
+ int audio_bits;
+ int audio_sample_rate;
+
+ unsigned char *buf;
+ int bufsize;
+ int size;
+
+ AVCodecContext *context;
+ AVCodec *codec;
+
+ char *decode_buffer;
+ int decoder_ok;
+
+} ff_audio_decoder_t;
+
+
+static const ff_codec_t ff_audio_lookup[] = {
+ {BUF_AUDIO_WMAV1, CODEC_ID_WMAV1, "MS Windows Media Audio 1 (ffmpeg)"},
+ {BUF_AUDIO_WMAV2, CODEC_ID_WMAV2, "MS Windows Media Audio 2 (ffmpeg)"},
+ {BUF_AUDIO_14_4, CODEC_ID_RA_144, "Real 14.4 (ffmpeg)"},
+ {BUF_AUDIO_28_8, CODEC_ID_RA_288, "Real 28.8 (ffmpeg)"},
+ {BUF_AUDIO_MPEG, CODEC_ID_MP3, "MP3 (ffmpeg)"},
+ {BUF_AUDIO_MSADPCM, CODEC_ID_ADPCM_MS, "MS ADPCM (ffmpeg)"},
+ {BUF_AUDIO_QTIMAADPCM, CODEC_ID_ADPCM_IMA_QT, "QT IMA ADPCM (ffmpeg)"},
+ {BUF_AUDIO_MSIMAADPCM, CODEC_ID_ADPCM_IMA_WAV, "MS IMA ADPCM (ffmpeg)"},
+ {BUF_AUDIO_DK3ADPCM, CODEC_ID_ADPCM_IMA_DK3, "Duck DK3 ADPCM (ffmpeg)"},
+ {BUF_AUDIO_DK4ADPCM, CODEC_ID_ADPCM_IMA_DK4, "Duck DK4 ADPCM (ffmpeg)"},
+ {BUF_AUDIO_VQA_IMA, CODEC_ID_ADPCM_IMA_WS, "Westwood Studios IMA (ffmpeg)"},
+ {BUF_AUDIO_SMJPEG_IMA, CODEC_ID_ADPCM_IMA_SMJPEG, "SMJPEG IMA (ffmpeg)"},
+ {BUF_AUDIO_XA_ADPCM, CODEC_ID_ADPCM_XA, "CD-ROM/XA ADPCM (ffmpeg)"},
+ {BUF_AUDIO_4X_ADPCM, CODEC_ID_ADPCM_4XM, "4X ADPCM (ffmpeg)"},
+ {BUF_AUDIO_EA_ADPCM, CODEC_ID_ADPCM_EA, "Electronic Arts ADPCM (ffmpeg)"},
+ {BUF_AUDIO_MULAW, CODEC_ID_PCM_MULAW, "mu-law logarithmic PCM (ffmpeg)"},
+ {BUF_AUDIO_ALAW, CODEC_ID_PCM_ALAW, "A-law logarithmic PCM (ffmpeg)"},
+ {BUF_AUDIO_ROQ, CODEC_ID_ROQ_DPCM, "RoQ DPCM (ffmpeg)"},
+ {BUF_AUDIO_INTERPLAY, CODEC_ID_INTERPLAY_DPCM, "Interplay DPCM (ffmpeg)"},
+ {BUF_AUDIO_MAC3, CODEC_ID_MACE3, "MACE 3:1 (ffmpeg)"},
+ {BUF_AUDIO_MAC6, CODEC_ID_MACE6, "MACE 6:1 (ffmpeg)"},
+ {BUF_AUDIO_XAN_DPCM, CODEC_ID_XAN_DPCM, "Origin Xan DPCM (ffmpeg)"},
+ {BUF_AUDIO_VMD, CODEC_ID_VMDAUDIO, "Sierra VMD Audio (ffmpeg)"},
+ {BUF_AUDIO_FLAC, CODEC_ID_FLAC, "FLAC (ffmpeg)"},
+ {BUF_AUDIO_SHORTEN, CODEC_ID_SHORTEN, "Shorten (ffmpeg)"},
+ {BUF_AUDIO_ALAC, CODEC_ID_ALAC, "ALAC (ffmpeg)"},
+ {BUF_AUDIO_QDESIGN2, CODEC_ID_QDM2, "QDesign (ffmpeg)"},
+ {BUF_AUDIO_COOK, CODEC_ID_COOK, "RealAudio Cooker (ffmpeg)"},
+ {BUF_AUDIO_TRUESPEECH, CODEC_ID_TRUESPEECH, "TrueSpeech (ffmpeg)"},
+ {BUF_AUDIO_TTA, CODEC_ID_TTA, "True Audio Lossless (ffmpeg)"},
+ {BUF_AUDIO_SMACKER, CODEC_ID_SMACKAUDIO, "Smacker (ffmpeg)"},
+ {BUF_AUDIO_FLVADPCM, CODEC_ID_ADPCM_SWF, "Flash ADPCM (ffmpeg)"},
+ {BUF_AUDIO_WAVPACK, CODEC_ID_WAVPACK, "WavPack (ffmpeg)"},
+};
+
+
+ static void ff_audio_ensure_buffer_size(ff_audio_decoder_t *this, int size) {
+ if (size > this->bufsize) {
+ this->bufsize = size + size / 2;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_audio_dec: increasing buffer to %d to avoid overflow.\n"),
+ this->bufsize);
+ this->buf = realloc( this->buf, this->bufsize );
+ }
+}
+
+static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
+
+ ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
+ int bytes_consumed;
+ int decode_buffer_size;
+ int offset;
+ int out;
+ audio_buffer_t *audio_buffer;
+ int bytes_to_send;
+
+ if ( (buf->decoder_flags & BUF_FLAG_HEADER) &&
+ !(buf->decoder_flags & BUF_FLAG_SPECIAL) ) {
+
+ /* accumulate init data */
+ ff_audio_ensure_buffer_size(this, this->size + buf->size);
+ memcpy(this->buf + this->size, buf->content, buf->size);
+ this->size += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+ size_t i;
+ unsigned int codec_type;
+ xine_waveformatex *audio_header;
+
+ codec_type = buf->type & 0xFFFF0000;
+ this->codec = NULL;
+
+ for(i = 0; i < sizeof(ff_audio_lookup)/sizeof(ff_codec_t); i++)
+ if(ff_audio_lookup[i].type == codec_type) {
+ pthread_mutex_lock (&ffmpeg_lock);
+ this->codec = avcodec_find_decoder(ff_audio_lookup[i].id);
+ pthread_mutex_unlock (&ffmpeg_lock);
+ _x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC,
+ ff_audio_lookup[i].name);
+ break;
+ }
+
+ if (!this->codec) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_audio_dec: couldn't find ffmpeg decoder for buf type 0x%X\n"),
+ codec_type);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0);
+ return;
+ }
+
+ this->context = avcodec_alloc_context();
+
+ if(buf->decoder_flags & BUF_FLAG_STDHEADER) {
+ this->audio_sample_rate = buf->decoder_info[1];
+ this->audio_channels = buf->decoder_info[3];
+
+ if(this->size) {
+ audio_header = (xine_waveformatex *)this->buf;
+
+ this->context->block_align = audio_header->nBlockAlign;
+ this->context->bit_rate = audio_header->nAvgBytesPerSec * 8;
+
+ if(audio_header->cbSize > 0) {
+ this->context->extradata = xine_xmalloc(audio_header->cbSize);
+ this->context->extradata_size = audio_header->cbSize;
+ memcpy( this->context->extradata,
+ (uint8_t *)audio_header + sizeof(xine_waveformatex),
+ audio_header->cbSize );
+ }
+ }
+ } else {
+ short *ptr;
+
+ switch(codec_type) {
+ case BUF_AUDIO_14_4:
+ this->audio_sample_rate = 8000;
+ this->audio_channels = 1;
+
+ this->context->block_align = 240;
+ break;
+ case BUF_AUDIO_28_8:
+ this->audio_sample_rate = _X_BE_16(&this->buf[0x30]);
+ this->audio_channels = this->buf[0x37];
+ /* this->audio_bits = buf->content[0x35] */
+
+ this->context->block_align = _X_BE_16(&this->buf[0x2A]);
+
+ this->context->extradata_size = 5*sizeof(short);
+ this->context->extradata = xine_xmalloc(this->context->extradata_size);
+
+ ptr = (short *) this->context->extradata;
+
+ ptr[0] = _X_BE_16(&this->buf[0x2C]); /* subpacket size */
+ ptr[1] = _X_BE_16(&this->buf[0x28]); /* subpacket height */
+ ptr[2] = _X_BE_16(&this->buf[0x16]); /* subpacket flavour */
+ ptr[3] = _X_BE_32(&this->buf[0x18]); /* coded frame size */
+ ptr[4] = 0; /* codec's data length */
+ break;
+ default:
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ "ffmpeg_audio_dec: unknown header with buf type 0x%X\n", codec_type);
+ break;
+ }
+ }
+
+ /* Current ffmpeg audio decoders always use 16 bits/sample
+ * buf->decoder_info[2] can't be used as it doesn't refer to the output
+ * bits/sample for some codecs (e.g. MS ADPCM) */
+ this->audio_bits = 16;
+
+ this->context->bits_per_sample = this->audio_bits;
+ this->context->sample_rate = this->audio_sample_rate;
+ this->context->channels = this->audio_channels;
+ this->context->codec_id = this->codec->id;
+ this->context->codec_tag = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC);
+
+ this->size = 0;
+
+ this->decode_buffer = xine_xmalloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
+
+ return;
+ }
+ } else if ((buf->decoder_flags & BUF_FLAG_SPECIAL) &&
+ (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM)) {
+
+ this->context->extradata_size = buf->decoder_info[2];
+ this->context->extradata = xine_xmalloc(buf->decoder_info[2] +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(this->context->extradata, buf->decoder_info_ptr[2],
+ buf->decoder_info[2]);
+
+ } else if (!(buf->decoder_flags & BUF_FLAG_SPECIAL)) {
+
+ if( !this->decoder_ok ) {
+ if ( ! this->context || ! this->codec ) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_audio_dec: trying to open null codec\n"));
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0);
+ return;
+ }
+
+ pthread_mutex_lock (&ffmpeg_lock);
+ if (avcodec_open (this->context, this->codec) < 0) {
+ pthread_mutex_unlock (&ffmpeg_lock);
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_audio_dec: couldn't open decoder\n"));
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0);
+ return;
+ }
+ pthread_mutex_unlock (&ffmpeg_lock);
+ this->decoder_ok = 1;
+ }
+
+ if (!this->output_open) {
+ this->output_open = (this->stream->audio_out->open) (this->stream->audio_out,
+ this->stream, this->audio_bits, this->audio_sample_rate,
+ _x_ao_channels2mode(this->audio_channels));
+ }
+
+ /* if the audio still isn't open, bail */
+ if (!this->output_open)
+ return;
+
+ if( buf->decoder_flags & BUF_FLAG_PREVIEW )
+ return;
+
+ ff_audio_ensure_buffer_size(this, this->size + buf->size);
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+ this->size += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */
+
+ offset = 0;
+ while (this->size>0) {
+ decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ bytes_consumed = avcodec_decode_audio2 (this->context,
+ (int16_t *)this->decode_buffer,
+ &decode_buffer_size,
+ &this->buf[offset],
+ this->size);
+
+ if (bytes_consumed<0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: error decompressing audio frame\n");
+ this->size=0;
+ return;
+ } else if (bytes_consumed == 0 && decode_buffer_size == 0) {
+ if (offset)
+ memmove(this->buf, &this->buf[offset], this->size);
+ return;
+ }
+
+ /* dispatch the decoded audio */
+ out = 0;
+ while (out < decode_buffer_size) {
+ audio_buffer =
+ this->stream->audio_out->get_buffer (this->stream->audio_out);
+ if (audio_buffer->mem_size == 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: Help! Allocated audio buffer with nothing in it!\n");
+ return;
+ }
+
+ if ((decode_buffer_size - out) > audio_buffer->mem_size)
+ bytes_to_send = audio_buffer->mem_size;
+ else
+ bytes_to_send = decode_buffer_size - out;
+
+ /* fill up this buffer */
+ xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out],
+ bytes_to_send);
+ /* byte count / 2 (bytes / sample) / channels */
+ audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels;
+
+ audio_buffer->vpts = buf->pts;
+ buf->pts = 0; /* only first buffer gets the real pts */
+ this->stream->audio_out->put_buffer (this->stream->audio_out,
+ audio_buffer, this->stream);
+
+ out += bytes_to_send;
+ }
+
+ this->size -= bytes_consumed;
+ offset += bytes_consumed;
+ }
+
+ /* reset internal accumulation buffer */
+ this->size = 0;
+ }
+ }
+}
+
+static void ff_audio_reset (audio_decoder_t *this_gen) {
+ ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
+
+ this->size = 0;
+
+ /* try to reset the wma decoder */
+ if( this->context && this->decoder_ok ) {
+ pthread_mutex_lock (&ffmpeg_lock);
+ avcodec_close (this->context);
+ avcodec_open (this->context, this->codec);
+ pthread_mutex_unlock (&ffmpeg_lock);
+ }
+}
+
+static void ff_audio_discontinuity (audio_decoder_t *this_gen) {
+}
+
+static void ff_audio_dispose (audio_decoder_t *this_gen) {
+
+ ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
+
+ if( this->context && this->decoder_ok ) {
+ pthread_mutex_lock (&ffmpeg_lock);
+ avcodec_close (this->context);
+ pthread_mutex_unlock (&ffmpeg_lock);
+ }
+
+ if (this->output_open)
+ this->stream->audio_out->close (this->stream->audio_out, this->stream);
+ this->output_open = 0;
+
+ free(this->buf);
+ free(this->decode_buffer);
+
+ if(this->context && this->context->extradata)
+ free(this->context->extradata);
+
+ if(this->context)
+ free(this->context);
+
+ free (this_gen);
+}
+
+static audio_decoder_t *ff_audio_open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ ff_audio_decoder_t *this ;
+
+ this = (ff_audio_decoder_t *) xine_xmalloc (sizeof (ff_audio_decoder_t));
+
+ this->audio_decoder.decode_data = ff_audio_decode_data;
+ this->audio_decoder.reset = ff_audio_reset;
+ this->audio_decoder.discontinuity = ff_audio_discontinuity;
+ this->audio_decoder.dispose = ff_audio_dispose;
+
+ this->output_open = 0;
+ this->audio_channels = 0;
+ this->stream = stream;
+ this->buf = NULL;
+ this->size = 0;
+ this->bufsize = 0;
+ this->decoder_ok = 0;
+
+ ff_audio_ensure_buffer_size(this, AUDIOBUFSIZE);
+
+ return &this->audio_decoder;
+}
+
+void *init_audio_plugin (xine_t *xine, void *data) {
+
+ ff_audio_class_t *this ;
+
+ this = (ff_audio_class_t *) xine_xmalloc (sizeof (ff_audio_class_t));
+
+ this->decoder_class.open_plugin = ff_audio_open_plugin;
+ this->decoder_class.identifier = "ffmpeg audio";
+ this->decoder_class.description = N_("ffmpeg based audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
+
+ pthread_once( &once_control, init_once_routine );
+
+ return this;
+}
+
+static const uint32_t supported_audio_types[] = {
+#if defined(HAVE_FFMPEG) || CONFIG_WMAV1_DECODER
+ BUF_AUDIO_WMAV1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WMAV2_DECODER
+ BUF_AUDIO_WMAV2,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_RA_144_DECODER
+ BUF_AUDIO_14_4,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_RA_288_DECODER
+ BUF_AUDIO_28_8,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MP3_DECODER
+ BUF_AUDIO_MPEG,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_MS_DECODER
+ BUF_AUDIO_MSADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_QT_DECODER
+ BUF_AUDIO_QTIMAADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_WAV_DECODER
+ BUF_AUDIO_MSIMAADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_DK3_DECODER
+ BUF_AUDIO_DK3ADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_DK4_DECODER
+ BUF_AUDIO_DK4ADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_WS_DECODER
+ BUF_AUDIO_VQA_IMA,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_SMJPEG_DECODER
+ BUF_AUDIO_SMJPEG_IMA,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_XA_DECODER
+ BUF_AUDIO_XA_ADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_4XM_DECODER
+ BUF_AUDIO_4X_ADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_EA_DECODER
+ BUF_AUDIO_EA_ADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_PCM_MULAW_DECODER
+ BUF_AUDIO_MULAW,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_PCM_ALAW_DECODER
+ BUF_AUDIO_ALAW,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ROQ_DPCM_DECODER
+ BUF_AUDIO_ROQ,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_INTERPLAY_DPCM_DECODER
+ BUF_AUDIO_INTERPLAY,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MACE3_DECODER
+ BUF_AUDIO_MAC3,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MACE6_DECODER
+ BUF_AUDIO_MAC6,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_XAN_DPCM_DECODER
+ BUF_AUDIO_XAN_DPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VMDAUDIO_DECODER
+ BUF_AUDIO_VMD,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_FLAC_DECODER
+ BUF_AUDIO_FLAC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SHORTEN_DECODER
+ BUF_AUDIO_SHORTEN,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ALAC_DECODER
+ BUF_AUDIO_ALAC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_QDM2_DECODER
+ BUF_AUDIO_QDESIGN2,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_COOK_DECODER
+ BUF_AUDIO_COOK,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_TRUESPEECH_DECODER
+ BUF_AUDIO_TRUESPEECH,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_TTA_DECODER
+ BUF_AUDIO_TTA,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SMACKAUDIO_DECODER
+ BUF_AUDIO_SMACKER,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_SWF_DECODER
+ BUF_AUDIO_FLVADPCM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WAVPACK_DECODER
+ BUF_AUDIO_WAVPACK,
+#endif
+
+ 0
+};
+
+decoder_info_t dec_info_ffmpeg_audio = {
+ supported_audio_types, /* supported types */
+ 6 /* priority */
+};
diff --git a/src/combined/ffmpeg/ff_dvaudio_decoder.c b/src/combined/ffmpeg/ff_dvaudio_decoder.c
new file mode 100644
index 000000000..aced7f5bb
--- /dev/null
+++ b/src/combined/ffmpeg/ff_dvaudio_decoder.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * dv audio decoder based on patch by Dan Dennedy <dan@dennedy.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <math.h>
+
+#define LOG_MODULE "dvaudio"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#include <xine/xine_internal.h>
+#include <xine/buffer.h>
+#include <xine/xineutils.h>
+
+#ifdef _MSC_VER
+/* ffmpeg has own definitions of those types */
+# undef int8_t
+# undef uint8_t
+# undef int16_t
+# undef uint16_t
+# undef int32_t
+# undef uint32_t
+# undef int64_t
+# undef uint64_t
+#endif
+
+#include <avcodec.h>
+#include <dvdata.h> /* This is not installed by FFmpeg, its usage has to be cleared up */
+
+#ifdef _MSC_VER
+# undef malloc
+# undef free
+# undef realloc
+#endif
+
+#define AUDIOBUFSIZE 128*1024
+#define MAXFRAMESIZE 131072
+
+
+typedef struct {
+ audio_decoder_class_t decoder_class;
+} dvaudio_class_t;
+
+typedef struct dvaudio_decoder_s {
+ audio_decoder_t audio_decoder;
+
+ xine_stream_t *stream;
+
+ int output_open;
+ int audio_channels;
+ int audio_bits;
+ int audio_sample_rate;
+
+ unsigned char *buf;
+ int bufsize;
+ int size;
+
+ char *decode_buffer;
+ int decoder_ok;
+
+} dvaudio_decoder_t;
+
+/*
+ * This is the dumbest implementation of all -- it simply looks at
+ * a fixed offset and if pack isn't there -- fails. We might want
+ * to have a fallback mechanism for complete search of missing packs.
+ */
+static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t)
+{
+ int offs;
+
+ switch (t) {
+ case dv_audio_source:
+ offs = (80*6 + 80*16*3 + 3);
+ break;
+ case dv_audio_control:
+ offs = (80*6 + 80*16*4 + 3);
+ break;
+ case dv_video_control:
+ offs = (80*5 + 48 + 5);
+ break;
+ default:
+ return NULL;
+ }
+
+ return (frame[offs] == t ? &frame[offs] : NULL);
+}
+
+static inline uint16_t dv_audio_12to16(uint16_t sample)
+{
+ uint16_t shift, result;
+
+ sample = (sample < 0x800) ? sample : sample | 0xf000;
+ shift = (sample & 0xf00) >> 8;
+
+ if (shift < 0x2 || shift > 0xd) {
+ result = sample;
+ } else if (shift < 0x8) {
+ shift--;
+ result = (sample - (256 * shift)) << shift;
+ } else {
+ shift = 0xe - shift;
+ result = ((sample + ((256 * shift) + 1)) << shift) - 1;
+ }
+
+ return result;
+}
+
+/*
+ * There's a couple of assumptions being made here:
+ * 1. By default we silence erroneous (0x8000/16bit 0x800/12bit) audio samples.
+ * We can pass them upwards when ffmpeg will be ready to deal with them.
+ * 2. We don't do software emphasis.
+ * 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
+ * are converted into 16bit linear ones.
+ */
+static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2)
+{
+ int size, i, j, d, of, smpls, freq, quant, half_ch;
+ uint16_t lc, rc;
+ const DVprofile* sys;
+ const uint8_t* as_pack;
+
+ as_pack = dv_extract_pack(frame, dv_audio_source);
+ if (!as_pack) /* No audio ? */
+ return 0;
+
+ sys = dv_frame_profile(frame);
+ smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
+ freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48KHz, 1 - 44,1kHz, 2 - 32 kHz */
+ quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
+
+ if (quant > 1)
+ return -1; /* Unsupported quantization */
+
+ size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
+ half_ch = sys->difseg_size/2;
+
+ /* for each DIF segment */
+ for (i = 0; i < sys->difseg_size; i++) {
+ frame += 6 * 80; /* skip DIF segment header */
+ if (quant == 1 && i == half_ch) {
+ if (!pcm2)
+ break;
+ else
+ pcm = pcm2;
+ }
+
+ for (j = 0; j < 9; j++) {
+ for (d = 8; d < 80; d += 2) {
+ if (quant == 0) { /* 16bit quantization */
+ of = sys->audio_shuffle[i][j] + (d - 8)/2 * sys->audio_stride;
+ if (of*2 >= size)
+ continue;
+
+#ifdef WORDS_BIGENDIAN
+ pcm[of*2] = frame[d];
+ pcm[of*2+1] = frame[d+1];
+#else
+ pcm[of*2] = frame[d+1];
+ pcm[of*2+1] = frame[d];
+#endif
+ if (pcm[of*2+1] == 0x80 && pcm[of*2] == 0x00)
+ pcm[of*2+1] = 0;
+ } else { /* 12bit quantization */
+ lc = ((uint16_t)frame[d] << 4) |
+ ((uint16_t)frame[d+2] >> 4);
+ rc = ((uint16_t)frame[d+1] << 4) |
+ ((uint16_t)frame[d+2] & 0x0f);
+ lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc));
+ rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc));
+
+ of = sys->audio_shuffle[i%half_ch][j] + (d - 8)/3 * sys->audio_stride;
+ if (of*2 >= size)
+ continue;
+
+#ifdef WORDS_BIGENDIAN
+ pcm[of*2] = lc >> 8;
+ pcm[of*2+1] = lc & 0xff;
+#else
+ pcm[of*2] = lc & 0xff;
+ pcm[of*2+1] = lc >> 8;
+#endif
+ of = sys->audio_shuffle[i%half_ch+half_ch][j] +
+ (d - 8)/3 * sys->audio_stride;
+#ifdef WORDS_BIGENDIAN
+ pcm[of*2] = rc >> 8;
+ pcm[of*2+1] = rc & 0xff;
+#else
+ pcm[of*2] = rc & 0xff;
+ pcm[of*2+1] = rc >> 8;
+#endif
+ ++d;
+ }
+ }
+
+ frame += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */
+ }
+ }
+
+ return size;
+}
+
+static void dvaudio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
+
+ dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
+ int bytes_consumed;
+ int decode_buffer_size;
+ int offset;
+ int out;
+ audio_buffer_t *audio_buffer;
+ int bytes_to_send;
+
+ if (buf->decoder_flags & BUF_FLAG_PREVIEW)
+ return;
+
+ if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
+ this->buf = xine_xmalloc(AUDIOBUFSIZE);
+ this->bufsize = AUDIOBUFSIZE;
+ this->size = 0;
+ this->decode_buffer = xine_xmalloc(MAXFRAMESIZE);
+
+ this->audio_sample_rate = buf->decoder_info[1];
+ this->audio_bits = buf->decoder_info[2];
+ this->audio_channels = buf->decoder_info[3];
+
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "DV Audio");
+
+ this->decoder_ok = 1;
+
+ return;
+ }
+
+ if (this->decoder_ok && !(buf->decoder_flags & (BUF_FLAG_HEADER|BUF_FLAG_SPECIAL))) {
+
+ if (!this->output_open) {
+ this->output_open = (this->stream->audio_out->open) (this->stream->audio_out,
+ this->stream, this->audio_bits, this->audio_sample_rate,
+ _x_ao_channels2mode(this->audio_channels));
+ }
+
+ /* if the audio still isn't open, bail */
+ if (!this->output_open)
+ return;
+
+ if( this->size + buf->size > this->bufsize ) {
+ this->bufsize = this->size + 2 * buf->size;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("dvaudio: increasing buffer to %d to avoid overflow.\n"),
+ this->bufsize);
+ this->buf = realloc( this->buf, this->bufsize );
+ }
+
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+ this->size += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */
+
+ offset = 0;
+ while (this->size>0) {
+ decode_buffer_size = dv_extract_audio(&this->buf[offset], this->decode_buffer, NULL);
+
+ if (decode_buffer_size > -1)
+ bytes_consumed = dv_frame_profile(&this->buf[offset])->frame_size;
+ else
+ bytes_consumed = decode_buffer_size;
+
+ /* dispatch the decoded audio */
+ out = 0;
+ while (out < decode_buffer_size) {
+ audio_buffer =
+ this->stream->audio_out->get_buffer (this->stream->audio_out);
+ if (audio_buffer->mem_size == 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "dvaudio: Help! Allocated audio buffer with nothing in it!\n");
+ return;
+ }
+
+ if ((decode_buffer_size - out) > audio_buffer->mem_size)
+ bytes_to_send = audio_buffer->mem_size;
+ else
+ bytes_to_send = decode_buffer_size - out;
+
+ /* fill up this buffer */
+ xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out],
+ bytes_to_send);
+ /* byte count / 2 (bytes / sample) / channels */
+ audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels;
+
+ audio_buffer->vpts = buf->pts;
+ buf->pts = 0; /* only first buffer gets the real pts */
+ this->stream->audio_out->put_buffer (this->stream->audio_out,
+ audio_buffer, this->stream);
+
+ out += bytes_to_send;
+ }
+
+ this->size -= bytes_consumed;
+ offset += bytes_consumed;
+ }
+
+ /* reset internal accumulation buffer */
+ this->size = 0;
+ }
+ }
+}
+
+static void dvaudio_reset (audio_decoder_t *this_gen) {
+ dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
+
+ this->size = 0;
+}
+
+static void dvaudio_discontinuity (audio_decoder_t *this_gen) {
+}
+
+static void dvaudio_dispose (audio_decoder_t *this_gen) {
+
+ dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
+
+ if (this->output_open)
+ this->stream->audio_out->close (this->stream->audio_out, this->stream);
+ this->output_open = 0;
+
+ free(this->buf);
+ free(this->decode_buffer);
+
+ free (this_gen);
+}
+
+static audio_decoder_t *dvaudio_open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ dvaudio_decoder_t *this ;
+
+ this = (dvaudio_decoder_t *) xine_xmalloc (sizeof (dvaudio_decoder_t));
+
+ this->audio_decoder.decode_data = dvaudio_decode_data;
+ this->audio_decoder.reset = dvaudio_reset;
+ this->audio_decoder.discontinuity = dvaudio_discontinuity;
+ this->audio_decoder.dispose = dvaudio_dispose;
+
+ this->output_open = 0;
+ this->audio_channels = 0;
+ this->stream = stream;
+ this->buf = NULL;
+ this->size = 0;
+ this->decoder_ok = 0;
+
+ return &this->audio_decoder;
+}
+
+static void *init_dvaudio_plugin (xine_t *xine, void *data) {
+
+ dvaudio_class_t *this ;
+
+ this = (dvaudio_class_t *) xine_xmalloc (sizeof (dvaudio_class_t));
+
+ this->decoder_class.open_plugin = dvaudio_open_plugin;
+ this->decoder_class.identifier = "dv audio";
+ this->decoder_class.description = N_("dv audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
+
+ return this;
+}
+
+static uint32_t supported_audio_types[] = {
+ BUF_AUDIO_DV,
+ 0
+};
+
+static const decoder_info_t dec_info_dvaudio = {
+ supported_audio_types, /* supported types */
+ 5 /* priority */
+};
+
+/*
+ * exported plugin catalog entry
+ */
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_AUDIO_DECODER, 16, "dvaudio", XINE_VERSION_CODE, &dec_info_dvaudio, init_dvaudio_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/combined/ffmpeg/ff_mpeg_parser.c b/src/combined/ffmpeg/ff_mpeg_parser.c
new file mode 100644
index 000000000..70901d93b
--- /dev/null
+++ b/src/combined/ffmpeg/ff_mpeg_parser.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2001-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
+ * based on libmpeg2 decoder.
+ */
+#define LOG_MODULE "mpeg_parser"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+#include "ff_mpeg_parser.h"
+
+/* mpeg frame rate table from lavc */
+static const int frame_rate_tab[][2] = {
+ { 0, 0},
+ {24000, 1001},
+ { 24, 1},
+ { 25, 1},
+ {30000, 1001},
+ { 30, 1},
+ { 50, 1},
+ {60000, 1001},
+ { 60, 1},
+ /* Xing's 15fps: (9) */
+ { 15, 1},
+ /* libmpeg3's "Unofficial economy rates": (10-13) */
+ { 5, 1},
+ { 10, 1},
+ { 12, 1},
+ { 15, 1},
+ { 0, 0},
+};
+
+void mpeg_parser_init (mpeg_parser_t *parser)
+{
+ parser->chunk_buffer = xine_xmalloc(BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+ mpeg_parser_reset(parser);
+}
+
+void mpeg_parser_dispose (mpeg_parser_t *parser)
+{
+ if ( parser == NULL ) return;
+
+ free(parser->chunk_buffer);
+}
+
+void mpeg_parser_reset (mpeg_parser_t *parser)
+{
+ parser->shift = 0xffffff00;
+ parser->is_sequence_needed = 1;
+ parser->in_slice = 0;
+ parser->chunk_ptr = parser->chunk_buffer;
+ parser->chunk_start = parser->chunk_buffer;
+ parser->buffer_size = 0;
+ parser->code = 0xb4;
+ parser->picture_coding_type = 0;
+ parser->width = 0;
+ parser->height = 0;
+ parser->rate_code = 0;
+ parser->aspect_ratio_info = 0;
+ parser->frame_duration = 0;
+ parser->is_mpeg1 = 0;
+ parser->has_sequence = 0;
+ parser->frame_aspect_ratio = 0.0;
+}
+
+static void parse_header_picture (mpeg_parser_t *parser, uint8_t * buffer)
+{
+ parser->picture_coding_type = (buffer [1] >> 3) & 7;
+}
+
+static double get_aspect_ratio(mpeg_parser_t *parser)
+{
+ double ratio;
+ double mpeg1_pel_ratio[16] = {1.0 /* forbidden */,
+ 1.0, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157,
+ 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 1.0 /*reserved*/ };
+
+ if( !parser->is_mpeg1 ) {
+ /* these hardcoded values are defined on mpeg2 standard for
+ * aspect ratio. other values are reserved or forbidden. */
+ switch (parser->aspect_ratio_info) {
+ case 2:
+ ratio = 4.0 / 3.0;
+ break;
+ case 3:
+ ratio = 16.0 / 9.0;
+ break;
+ case 4:
+ ratio = 2.11 / 1.0;
+ break;
+ case 1:
+ default:
+ ratio = (double)parser->width / (double)parser->height;
+ break;
+ }
+ } else {
+ /* mpeg1 constants refer to pixel aspect ratio */
+ ratio = (double)parser->width / (double)parser->height;
+ ratio /= mpeg1_pel_ratio[parser->aspect_ratio_info];
+ }
+
+ return ratio;
+}
+
+static int parse_chunk (mpeg_parser_t *parser, int code, uint8_t *buffer, int len)
+{
+ int is_frame_done;
+ int next_code = parser->code;
+
+ /* wait for sequence_header_code */
+ if (parser->is_sequence_needed) {
+ if (code != 0xb3) {
+ lprintf("waiting for sequence header\n");
+ parser->chunk_ptr = parser->chunk_buffer;
+ return 0;
+ }
+ }
+
+ is_frame_done = parser->in_slice && ((!next_code) || (next_code == 0xb7));
+
+ if (is_frame_done)
+ parser->in_slice = 0;
+
+ switch (code) {
+ case 0x00: /* picture_start_code */
+
+ parse_header_picture (parser, buffer);
+
+ parser->in_slice = 1;
+
+ switch (parser->picture_coding_type) {
+ case B_TYPE:
+ lprintf ("B-Frame\n");
+ break;
+
+ case P_TYPE:
+ lprintf ("P-Frame\n");
+ break;
+
+ case I_TYPE:
+ lprintf ("I-Frame\n");
+ break;
+ }
+ break;
+
+ case 0xb2: /* user data code */
+ /* process_userdata(mpeg2dec, buffer); */
+ break;
+
+ case 0xb3: /* sequence_header_code */
+ {
+ int value;
+ uint16_t width, height;
+
+ if (parser->is_sequence_needed) {
+ parser->is_sequence_needed = 0;
+ }
+
+ if ((buffer[6] & 0x20) != 0x20) {
+ lprintf("Invalid sequence: missing marker_bit\n");
+ parser->has_sequence = 0;
+ break; /* missing marker_bit */
+ }
+
+ value = (buffer[0] << 16) |
+ (buffer[1] << 8) |
+ buffer[2];
+ width = ((value >> 12) + 15) & ~15;
+ height = ((value & 0xfff) + 15) & ~15;
+
+ if ((width > 1920) || (height > 1152)) {
+ lprintf("Invalid sequence: width=%d, height=%d\n", width, height);
+ parser->has_sequence = 0;
+ break; /* size restrictions for MP@HL */
+ }
+
+ parser->width = width;
+ parser->height = height;
+ parser->rate_code = buffer[3] & 15;
+ parser->aspect_ratio_info = buffer[3] >> 4;
+
+ if (parser->rate_code < (sizeof(frame_rate_tab)/sizeof(*frame_rate_tab))) {
+ parser->frame_duration = 90000;
+ parser->frame_duration *= frame_rate_tab[parser->rate_code][1];
+ parser->frame_duration /= frame_rate_tab[parser->rate_code][0];
+ } else {
+ printf ("invalid/unknown frame rate code : %d \n",
+ parser->rate_code);
+ parser->frame_duration = 0;
+ }
+
+ parser->has_sequence = 1;
+ parser->is_mpeg1 = 1;
+ }
+ break;
+
+ case 0xb5: /* extension_start_code */
+ switch (buffer[0] & 0xf0) {
+ case 0x10: /* sequence extension */
+ parser->is_mpeg1 = 0;
+ }
+
+ default:
+ if (code >= 0xb9)
+ lprintf ("stream not demultiplexed ?\n");
+
+ if (code >= 0xb0)
+ break;
+ }
+ return is_frame_done;
+}
+
+static inline uint8_t *copy_chunk (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end)
+{
+ uint32_t shift;
+ uint8_t *chunk_ptr;
+ uint8_t *limit;
+ uint8_t byte;
+
+ shift = parser->shift;
+ chunk_ptr = parser->chunk_ptr;
+
+ limit = current + (parser->chunk_buffer + BUFFER_SIZE - chunk_ptr);
+ if (limit > end)
+ limit = end;
+
+ while (1) {
+
+ byte = *current++;
+ *chunk_ptr++ = byte;
+ if (shift != 0x00000100) {
+ shift = (shift | byte) << 8;
+ if (current < limit)
+ continue;
+ if (current == end) {
+ parser->chunk_ptr = chunk_ptr;
+ parser->shift = shift;
+ lprintf("Need more bytes\n");
+ return NULL;
+ } else {
+ /* we filled the chunk buffer without finding a start code */
+ lprintf("Buffer full\n");
+ parser->code = 0xb4; /* sequence_error_code */
+ parser->chunk_ptr = parser->chunk_buffer;
+ return current;
+ }
+ }
+ lprintf("New chunk: 0x%2X\n", byte);
+ parser->chunk_ptr = chunk_ptr;
+ parser->shift = 0xffffff00;
+ parser->code = byte;
+ return current;
+ }
+}
+
+
+uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end,
+ int *flush)
+{
+ int ret;
+ uint8_t code;
+
+ ret = 0;
+ *flush = 0;
+
+ while (current != end) {
+ if (parser->chunk_ptr == parser->chunk_buffer) {
+ /* write the beginning of the chunk */
+ parser->chunk_buffer[0] = 0x00;
+ parser->chunk_buffer[1] = 0x00;
+ parser->chunk_buffer[2] = 0x01;
+ parser->chunk_buffer[3] = parser->code;
+ parser->chunk_ptr += 4;
+ parser->chunk_start = parser->chunk_ptr;
+ parser->has_sequence = 0;
+ }
+
+ code = parser->code;
+
+ current = copy_chunk (parser, current, end);
+ if (current == NULL)
+ return NULL;
+ ret = parse_chunk (parser, code, parser->chunk_start,
+ parser->chunk_ptr - parser->chunk_start - 4);
+ parser->chunk_start = parser->chunk_ptr;
+ if (ret == 1) {
+ if (parser->has_sequence) {
+ parser->frame_aspect_ratio = get_aspect_ratio(parser);
+ }
+ parser->buffer_size = parser->chunk_ptr - parser->chunk_buffer - 4;
+ parser->chunk_ptr = parser->chunk_buffer;
+
+ if (parser->code == 0xb7) /* sequence end, maybe a still menu */
+ *flush = 1;
+
+ return current;
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/combined/ffmpeg/ff_mpeg_parser.h b/src/combined/ffmpeg/ff_mpeg_parser.h
new file mode 100644
index 000000000..504e746f9
--- /dev/null
+++ b/src/combined/ffmpeg/ff_mpeg_parser.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2001-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
+ * based on libmpeg2 decoder.
+ */
+#ifndef HAVE_MPEG_PARSER_H
+#define HAVE_MPEG_PARSER_H
+
+#include <xine/xine_internal.h>
+#include "ffmpeg_decoder.h"
+
+#define BUFFER_SIZE (1194 * 1024) /* libmpeg2's buffer size */
+
+/* picture coding type (mpeg2 header) */
+#define I_TYPE 1
+#define P_TYPE 2
+#define B_TYPE 3
+#define D_TYPE 4
+
+typedef struct mpeg_parser_s {
+ uint8_t *chunk_buffer;
+ uint8_t *chunk_ptr;
+ uint8_t *chunk_start;
+ uint32_t shift;
+ int buffer_size;
+ uint8_t code;
+ uint8_t picture_coding_type;
+
+ uint8_t is_sequence_needed:1;
+ uint8_t is_mpeg1:1; /* public */
+ uint8_t has_sequence:1; /* public */
+ uint8_t in_slice:1;
+
+ uint8_t rate_code:4;
+
+ int aspect_ratio_info;
+
+ /* public properties */
+ uint16_t width;
+ uint16_t height;
+ int frame_duration;
+ double frame_aspect_ratio;
+
+} mpeg_parser_t;
+
+/* parser initialization */
+void mpeg_parser_init (mpeg_parser_t *parser);
+
+/* parser disposal */
+void mpeg_parser_dispose (mpeg_parser_t *parser);
+
+/* read a frame
+ * return a pointer to the first byte of the next frame
+ * or NULL if more bytes are needed
+ * *flush is set to 1 if the decoder must be flushed (needed for still menus)
+ */
+uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end,
+ int *flush);
+
+/* reset the parser */
+void mpeg_parser_reset (mpeg_parser_t *parser);
+
+#endif /* HAVE_MPEG_PARSER_H */
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c
new file mode 100644
index 000000000..b7a5338fc
--- /dev/null
+++ b/src/combined/ffmpeg/ff_video_decoder.c
@@ -0,0 +1,1875 @@
+/*
+ * Copyright (C) 2001-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * xine video decoder plugin using ffmpeg
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+# ifndef HAVE_FFMPEG
+# include "ffmpeg_config.h"
+# endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <math.h>
+#include <assert.h>
+
+#define LOG_MODULE "ffmpeg_video_dec"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+#include <xine/xine_internal.h>
+#include "bswap.h"
+#include <xine/buffer.h>
+#include <xine/xineutils.h>
+#include "ffmpeg_decoder.h"
+#include "ff_mpeg_parser.h"
+
+#include <postprocess.h>
+
+#define VIDEOBUFSIZE (128*1024)
+#define SLICE_BUFFER_SIZE (1194*1024)
+
+#define SLICE_OFFSET_SIZE 128
+
+#define ENABLE_DIRECT_RENDERING
+
+typedef struct ff_video_decoder_s ff_video_decoder_t;
+
+typedef struct ff_video_class_s {
+ video_decoder_class_t decoder_class;
+
+ int pp_quality;
+ int thread_count;
+ int8_t skip_loop_filter_enum;
+ int8_t choose_speed_over_accuracy;
+
+ xine_t *xine;
+} ff_video_class_t;
+
+struct ff_video_decoder_s {
+ video_decoder_t video_decoder;
+
+ ff_video_class_t *class;
+
+ xine_stream_t *stream;
+ int64_t pts;
+ int video_step;
+
+ uint8_t decoder_ok:1;
+ uint8_t decoder_init_mode:1;
+ uint8_t is_mpeg12:1;
+ uint8_t pp_available:1;
+ uint8_t yuv_init:1;
+ uint8_t is_direct_rendering_disabled:1;
+ uint8_t cs_convert_init:1;
+ uint8_t assume_bad_field_picture:1;
+
+ xine_bmiheader bih;
+ unsigned char *buf;
+ int bufsize;
+ int size;
+ int skipframes;
+
+ int slice_offset_size;
+
+ AVFrame *av_frame;
+ AVCodecContext *context;
+ AVCodec *codec;
+
+ int pp_quality;
+ int pp_flags;
+ pp_context_t *pp_context;
+ pp_mode_t *pp_mode;
+
+ /* mpeg-es parsing */
+ mpeg_parser_t *mpeg_parser;
+
+ double aspect_ratio;
+ int aspect_ratio_prio;
+ int frame_flags;
+ int crop_right, crop_bottom;
+
+ int output_format;
+
+ xine_list_t *dr1_frames;
+
+ yuv_planes_t yuv;
+
+ AVPaletteControl palette_control;
+};
+
+
+static void set_stream_info(ff_video_decoder_t *this) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio * 10000);
+}
+
+#ifdef ENABLE_DIRECT_RENDERING
+/* called from ffmpeg to do direct rendering method 1 */
+static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
+ ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque;
+ vo_frame_t *img;
+ int width = context->width;
+ int height = context->height;
+
+ if (!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = width;
+ this->bih.biHeight = height;
+
+ if (this->aspect_ratio_prio == 0) {
+ this->aspect_ratio = (double)width / (double)height;
+ this->aspect_ratio_prio = 1;
+ lprintf("default aspect ratio: %f\n", this->aspect_ratio);
+ set_stream_info(this);
+ }
+ }
+
+ avcodec_align_dimensions(context, &width, &height);
+
+ if( this->context->pix_fmt != PIX_FMT_YUV420P ) {
+ if (!this->is_direct_rendering_disabled) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: unsupported frame format, DR1 disabled.\n"));
+ this->is_direct_rendering_disabled = 1;
+ }
+
+ /* FIXME: why should i have to do that ? */
+ av_frame->data[0]= NULL;
+ av_frame->data[1]= NULL;
+ av_frame->data[2]= NULL;
+ return avcodec_default_get_buffer(context, av_frame);
+ }
+
+ if((width != this->bih.biWidth) || (height != this->bih.biHeight)) {
+ if(this->stream->video_out->get_capabilities(this->stream->video_out) & VO_CAP_CROP) {
+ this->crop_right = width - this->bih.biWidth;
+ this->crop_bottom = height - this->bih.biHeight;
+ } else {
+ if (!this->is_direct_rendering_disabled) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: unsupported frame dimensions, DR1 disabled.\n"));
+ this->is_direct_rendering_disabled = 1;
+ }
+ /* FIXME: why should i have to do that ? */
+ av_frame->data[0]= NULL;
+ av_frame->data[1]= NULL;
+ av_frame->data[2]= NULL;
+ return avcodec_default_get_buffer(context, av_frame);
+ }
+ }
+
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ width,
+ height,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+
+ av_frame->opaque = img;
+
+ av_frame->data[0]= img->base[0];
+ av_frame->data[1]= img->base[1];
+ av_frame->data[2]= img->base[2];
+
+ av_frame->linesize[0] = img->pitches[0];
+ av_frame->linesize[1] = img->pitches[1];
+ av_frame->linesize[2] = img->pitches[2];
+
+ /* We should really keep track of the ages of xine frames (see
+ * avcodec_default_get_buffer in libavcodec/utils.c)
+ * For the moment tell ffmpeg that every frame is new (age = bignumber) */
+ av_frame->age = 256*256*256*64;
+
+ av_frame->type= FF_BUFFER_TYPE_USER;
+
+ xine_list_push_back(this->dr1_frames, av_frame);
+
+ return 0;
+}
+
+static void release_buffer(struct AVCodecContext *context, AVFrame *av_frame){
+ ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque;
+
+ if (av_frame->type == FF_BUFFER_TYPE_USER) {
+ if ( av_frame->opaque ) {
+ vo_frame_t *img = (vo_frame_t *)av_frame->opaque;
+
+ img->free(img);
+ }
+
+ xine_list_iterator_t it;
+
+ it = xine_list_find(this->dr1_frames, av_frame);
+ assert(it);
+ if( it != NULL )
+ xine_list_remove(this->dr1_frames, it);
+ } else {
+ avcodec_default_release_buffer(context, av_frame);
+ }
+
+ av_frame->opaque = NULL;
+ av_frame->data[0]= NULL;
+ av_frame->data[1]= NULL;
+ av_frame->data[2]= NULL;
+}
+#endif
+
+static const ff_codec_t ff_video_lookup[] = {
+ {BUF_VIDEO_MSMPEG4_V1, CODEC_ID_MSMPEG4V1, "Microsoft MPEG-4 v1 (ffmpeg)"},
+ {BUF_VIDEO_MSMPEG4_V2, CODEC_ID_MSMPEG4V2, "Microsoft MPEG-4 v2 (ffmpeg)"},
+ {BUF_VIDEO_MSMPEG4_V3, CODEC_ID_MSMPEG4V3, "Microsoft MPEG-4 v3 (ffmpeg)"},
+ {BUF_VIDEO_WMV7, CODEC_ID_WMV1, "MS Windows Media Video 7 (ffmpeg)"},
+ {BUF_VIDEO_WMV8, CODEC_ID_WMV2, "MS Windows Media Video 8 (ffmpeg)"},
+ {BUF_VIDEO_WMV9, CODEC_ID_WMV3, "MS Windows Media Video 9 (ffmpeg)"},
+ {BUF_VIDEO_VC1, CODEC_ID_VC1, "MS Windows Media Video VC-1 (ffmpeg)"},
+ {BUF_VIDEO_MPEG4, CODEC_ID_MPEG4, "ISO MPEG-4 (ffmpeg)"},
+ {BUF_VIDEO_XVID, CODEC_ID_MPEG4, "ISO MPEG-4 (XviD, ffmpeg)"},
+ {BUF_VIDEO_DIVX5, CODEC_ID_MPEG4, "ISO MPEG-4 (DivX5, ffmpeg)"},
+ {BUF_VIDEO_3IVX, CODEC_ID_MPEG4, "ISO MPEG-4 (3ivx, ffmpeg)"},
+ {BUF_VIDEO_JPEG, CODEC_ID_MJPEG, "Motion JPEG (ffmpeg)"},
+ {BUF_VIDEO_MJPEG, CODEC_ID_MJPEG, "Motion JPEG (ffmpeg)"},
+ {BUF_VIDEO_MJPEG_B, CODEC_ID_MJPEGB, "Motion JPEG B (ffmpeg)"},
+ {BUF_VIDEO_I263, CODEC_ID_H263I, "ITU H.263 (ffmpeg)"},
+ {BUF_VIDEO_H263, CODEC_ID_H263, "H.263 (ffmpeg)"},
+ {BUF_VIDEO_RV10, CODEC_ID_RV10, "Real Video 1.0 (ffmpeg)"},
+ {BUF_VIDEO_RV20, CODEC_ID_RV20, "Real Video 2.0 (ffmpeg)"},
+ {BUF_VIDEO_IV31, CODEC_ID_INDEO3, "Indeo Video 3.1 (ffmpeg)"},
+ {BUF_VIDEO_IV32, CODEC_ID_INDEO3, "Indeo Video 3.2 (ffmpeg)"},
+ {BUF_VIDEO_SORENSON_V1, CODEC_ID_SVQ1, "Sorenson Video 1 (ffmpeg)"},
+ {BUF_VIDEO_SORENSON_V3, CODEC_ID_SVQ3, "Sorenson Video 3 (ffmpeg)"},
+ {BUF_VIDEO_DV, CODEC_ID_DVVIDEO, "DV (ffmpeg)"},
+ {BUF_VIDEO_HUFFYUV, CODEC_ID_HUFFYUV, "HuffYUV (ffmpeg)"},
+ {BUF_VIDEO_VP31, CODEC_ID_VP3, "On2 VP3.1 (ffmpeg)"},
+ {BUF_VIDEO_VP5, CODEC_ID_VP5, "On2 VP5 (ffmpeg)"},
+ {BUF_VIDEO_VP6, CODEC_ID_VP6, "On2 VP6 (ffmpeg)"},
+ {BUF_VIDEO_VP6F, CODEC_ID_VP6F, "On2 VP6 (ffmpeg)"},
+ {BUF_VIDEO_4XM, CODEC_ID_4XM, "4X Video (ffmpeg)"},
+ {BUF_VIDEO_CINEPAK, CODEC_ID_CINEPAK, "Cinepak (ffmpeg)"},
+ {BUF_VIDEO_MSVC, CODEC_ID_MSVIDEO1, "Microsoft Video 1 (ffmpeg)"},
+ {BUF_VIDEO_MSRLE, CODEC_ID_MSRLE, "Microsoft RLE (ffmpeg)"},
+ {BUF_VIDEO_RPZA, CODEC_ID_RPZA, "Apple Quicktime Video/RPZA (ffmpeg)"},
+ {BUF_VIDEO_CYUV, CODEC_ID_CYUV, "Creative YUV (ffmpeg)"},
+ {BUF_VIDEO_ROQ, CODEC_ID_ROQ, "Id Software RoQ (ffmpeg)"},
+ {BUF_VIDEO_IDCIN, CODEC_ID_IDCIN, "Id Software CIN (ffmpeg)"},
+ {BUF_VIDEO_WC3, CODEC_ID_XAN_WC3, "Xan (ffmpeg)"},
+ {BUF_VIDEO_VQA, CODEC_ID_WS_VQA, "Westwood Studios VQA (ffmpeg)"},
+ {BUF_VIDEO_INTERPLAY, CODEC_ID_INTERPLAY_VIDEO, "Interplay MVE (ffmpeg)"},
+ {BUF_VIDEO_FLI, CODEC_ID_FLIC, "FLIC Video (ffmpeg)"},
+ {BUF_VIDEO_8BPS, CODEC_ID_8BPS, "Planar RGB (ffmpeg)"},
+ {BUF_VIDEO_SMC, CODEC_ID_SMC, "Apple Quicktime Graphics/SMC (ffmpeg)"},
+ {BUF_VIDEO_DUCKTM1, CODEC_ID_TRUEMOTION1,"Duck TrueMotion v1 (ffmpeg)"},
+ {BUF_VIDEO_DUCKTM2, CODEC_ID_TRUEMOTION2,"Duck TrueMotion v2 (ffmpeg)"},
+ {BUF_VIDEO_VMD, CODEC_ID_VMDVIDEO, "Sierra VMD Video (ffmpeg)"},
+ {BUF_VIDEO_ZLIB, CODEC_ID_ZLIB, "ZLIB Video (ffmpeg)"},
+ {BUF_VIDEO_MSZH, CODEC_ID_MSZH, "MSZH Video (ffmpeg)"},
+ {BUF_VIDEO_ASV1, CODEC_ID_ASV1, "ASV v1 Video (ffmpeg)"},
+ {BUF_VIDEO_ASV2, CODEC_ID_ASV2, "ASV v2 Video (ffmpeg)"},
+ {BUF_VIDEO_ATIVCR1, CODEC_ID_VCR1, "ATI VCR-1 (ffmpeg)"},
+ {BUF_VIDEO_FLV1, CODEC_ID_FLV1, "Flash Video (ffmpeg)"},
+ {BUF_VIDEO_QTRLE, CODEC_ID_QTRLE, "Apple Quicktime Animation/RLE (ffmpeg)"},
+ {BUF_VIDEO_H264, CODEC_ID_H264, "H.264/AVC (ffmpeg)"},
+ {BUF_VIDEO_H261, CODEC_ID_H261, "H.261 (ffmpeg)"},
+ {BUF_VIDEO_AASC, CODEC_ID_AASC, "Autodesk Video (ffmpeg)"},
+ {BUF_VIDEO_LOCO, CODEC_ID_LOCO, "LOCO (ffmpeg)"},
+ {BUF_VIDEO_QDRW, CODEC_ID_QDRAW, "QuickDraw (ffmpeg)"},
+ {BUF_VIDEO_QPEG, CODEC_ID_QPEG, "Q-Team QPEG (ffmpeg)"},
+ {BUF_VIDEO_TSCC, CODEC_ID_TSCC, "TechSmith Video (ffmpeg)"},
+ {BUF_VIDEO_ULTI, CODEC_ID_ULTI, "IBM UltiMotion (ffmpeg)"},
+ {BUF_VIDEO_WNV1, CODEC_ID_WNV1, "Winnow Video (ffmpeg)"},
+ {BUF_VIDEO_XL, CODEC_ID_VIXL, "Miro/Pinnacle VideoXL (ffmpeg)"},
+ {BUF_VIDEO_RT21, CODEC_ID_INDEO2, "Indeo/RealTime 2 (ffmpeg)"},
+ {BUF_VIDEO_FPS1, CODEC_ID_FRAPS, "Fraps (ffmpeg)"},
+ {BUF_VIDEO_MPEG, CODEC_ID_MPEG1VIDEO, "MPEG 1/2 (ffmpeg)"},
+ {BUF_VIDEO_CSCD, CODEC_ID_CSCD, "CamStudio (ffmpeg)"},
+ {BUF_VIDEO_AVS, CODEC_ID_AVS, "AVS (ffmpeg)"},
+ {BUF_VIDEO_ALGMM, CODEC_ID_MMVIDEO, "American Laser Games MM (ffmpeg)"},
+ {BUF_VIDEO_ZMBV, CODEC_ID_ZMBV, "Zip Motion Blocks Video (ffmpeg)"},
+ {BUF_VIDEO_SMACKER, CODEC_ID_SMACKVIDEO, "Smacker (ffmpeg)"},
+ {BUF_VIDEO_NUV, CODEC_ID_NUV, "NuppelVideo (ffmpeg)"},
+ {BUF_VIDEO_KMVC, CODEC_ID_KMVC, "Karl Morton's Video Codec (ffmpeg)"},
+ {BUF_VIDEO_FLASHSV, CODEC_ID_FLASHSV, "Flash Screen Video (ffmpeg)"},
+ {BUF_VIDEO_CAVS, CODEC_ID_CAVS, "Chinese AVS (ffmpeg)"},
+ {BUF_VIDEO_VMNC, CODEC_ID_VMNC, "VMware Screen Codec (ffmpeg)"},
+ {BUF_VIDEO_THEORA_RAW, CODEC_ID_THEORA, "Theora (ffmpeg)"},
+};
+
+static const char *const skip_loop_filter_enum_names[] = {
+ "default", /* AVDISCARD_DEFAULT */
+ "none", /* AVDISCARD_NONE */
+ "nonref", /* AVDISCARD_NONREF */
+ "bidir", /* AVDISCARD_BIDIR */
+ "nonkey", /* AVDISCARD_NONKEY */
+ "all", /* AVDISCARD_ALL */
+ NULL
+};
+
+static const int skip_loop_filter_enum_values[] = {
+ AVDISCARD_DEFAULT,
+ AVDISCARD_NONE,
+ AVDISCARD_NONREF,
+ AVDISCARD_BIDIR,
+ AVDISCARD_NONKEY,
+ AVDISCARD_ALL
+};
+
+static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) {
+ size_t i;
+
+ /* find the decoder */
+ this->codec = NULL;
+
+ for(i = 0; i < sizeof(ff_video_lookup)/sizeof(ff_codec_t); i++)
+ if(ff_video_lookup[i].type == codec_type) {
+ pthread_mutex_lock(&ffmpeg_lock);
+ this->codec = avcodec_find_decoder(ff_video_lookup[i].id);
+ pthread_mutex_unlock(&ffmpeg_lock);
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC,
+ ff_video_lookup[i].name);
+ break;
+ }
+
+ if (!this->codec) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: couldn't find ffmpeg decoder for buf type 0x%X\n"),
+ codec_type);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0);
+ return;
+ }
+
+ lprintf("lavc decoder found\n");
+
+ /* force (width % 8 == 0), otherwise there will be
+ * display problems with Xv.
+ */
+ this->bih.biWidth = (this->bih.biWidth + 1) & (~1);
+
+ this->context->width = this->bih.biWidth;
+ this->context->height = this->bih.biHeight;
+ this->context->stream_codec_tag = this->context->codec_tag =
+ _x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC);
+
+
+ /* Some codecs (eg rv10) copy flags in init so it's necessary to set
+ * this flag here in case we are going to use direct rendering */
+ if(this->codec->capabilities & CODEC_CAP_DR1) {
+ this->context->flags |= CODEC_FLAG_EMU_EDGE;
+ }
+
+ if (this->class->choose_speed_over_accuracy)
+ this->context->flags2 |= CODEC_FLAG2_FAST;
+
+ pthread_mutex_lock(&ffmpeg_lock);
+ if (avcodec_open (this->context, this->codec) < 0) {
+ pthread_mutex_unlock(&ffmpeg_lock);
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: couldn't open decoder\n"));
+ free(this->context);
+ this->context = NULL;
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0);
+ return;
+ }
+
+ if (this->class->thread_count > 1) {
+ avcodec_thread_init(this->context, this->class->thread_count);
+ this->context->thread_count = this->class->thread_count;
+ }
+
+ this->context->skip_loop_filter = skip_loop_filter_enum_values[this->class->skip_loop_filter_enum];
+
+ pthread_mutex_unlock(&ffmpeg_lock);
+
+ lprintf("lavc decoder opened\n");
+
+ this->decoder_ok = 1;
+
+ if ((codec_type != BUF_VIDEO_MPEG) &&
+ (codec_type != BUF_VIDEO_DV)) {
+
+ if (!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = this->context->width;
+ this->bih.biHeight = this->context->height;
+ }
+
+
+ set_stream_info(this);
+ }
+
+ (this->stream->video_out->open) (this->stream->video_out, this->stream);
+
+ this->skipframes = 0;
+
+ /* enable direct rendering by default */
+ this->output_format = XINE_IMGFMT_YV12;
+#ifdef ENABLE_DIRECT_RENDERING
+ if( this->codec->capabilities & CODEC_CAP_DR1 && this->codec->id != CODEC_ID_H264 ) {
+ this->context->get_buffer = get_buffer;
+ this->context->release_buffer = release_buffer;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: direct rendering enabled\n"));
+ }
+#endif
+
+ /* flag for interlaced streams */
+ this->frame_flags = 0;
+ /* FIXME: which codecs can be interlaced?
+ FIXME: check interlaced DCT and other codec specific info. */
+ switch( codec_type ) {
+ case BUF_VIDEO_DV:
+ this->frame_flags |= VO_INTERLACED_FLAG;
+ break;
+ case BUF_VIDEO_MPEG:
+ this->frame_flags |= VO_INTERLACED_FLAG;
+ break;
+ case BUF_VIDEO_MJPEG:
+ this->frame_flags |= VO_INTERLACED_FLAG;
+ break;
+ case BUF_VIDEO_HUFFYUV:
+ this->frame_flags |= VO_INTERLACED_FLAG;
+ break;
+ case BUF_VIDEO_H264:
+ this->frame_flags |= VO_INTERLACED_FLAG;
+ break;
+ }
+
+}
+
+static void choose_speed_over_accuracy_cb(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->choose_speed_over_accuracy = entry->num_value;
+}
+
+static void skip_loop_filter_enum_cb(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->skip_loop_filter_enum = entry->num_value;
+}
+
+static void thread_count_cb(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->thread_count = entry->num_value;
+}
+
+static void pp_quality_cb(void *user_data, xine_cfg_entry_t *entry) {
+ ff_video_class_t *class = (ff_video_class_t *) user_data;
+
+ class->pp_quality = entry->num_value;
+}
+
+static void pp_change_quality (ff_video_decoder_t *this) {
+ this->pp_quality = this->class->pp_quality;
+
+ if(this->pp_available && this->pp_quality) {
+ if(!this->pp_context && this->context)
+ this->pp_context = pp_get_context(this->context->width, this->context->height,
+ this->pp_flags);
+ if(this->pp_mode)
+ pp_free_mode(this->pp_mode);
+
+ this->pp_mode = pp_get_mode_by_name_and_quality("hb:a,vb:a,dr:a",
+ this->pp_quality);
+ } else {
+ if(this->pp_mode) {
+ pp_free_mode(this->pp_mode);
+ this->pp_mode = NULL;
+ }
+
+ if(this->pp_context) {
+ pp_free_context(this->pp_context);
+ this->pp_context = NULL;
+ }
+ }
+}
+
+static void init_postprocess (ff_video_decoder_t *this) {
+ uint32_t cpu_caps;
+
+ /* Allow post processing on mpeg-4 (based) codecs */
+ switch(this->codec->id) {
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_MSMPEG4V1:
+ case CODEC_ID_MSMPEG4V2:
+ case CODEC_ID_MSMPEG4V3:
+ case CODEC_ID_WMV1:
+ case CODEC_ID_WMV2:
+ this->pp_available = 1;
+ break;
+ default:
+ this->pp_available = 0;
+ break;
+ }
+
+ /* Detect what cpu accel we have */
+ cpu_caps = xine_mm_accel();
+ this->pp_flags = PP_FORMAT_420;
+
+ if(cpu_caps & MM_ACCEL_X86_MMX)
+ this->pp_flags |= PP_CPU_CAPS_MMX;
+
+ if(cpu_caps & MM_ACCEL_X86_MMXEXT)
+ this->pp_flags |= PP_CPU_CAPS_MMX2;
+
+ if(cpu_caps & MM_ACCEL_X86_3DNOW)
+ this->pp_flags |= PP_CPU_CAPS_3DNOW;
+
+ /* Set level */
+ pp_change_quality(this);
+}
+
+static int ff_handle_mpeg_sequence(ff_video_decoder_t *this, mpeg_parser_t *parser) {
+
+ /*
+ * init codec
+ */
+ if (this->decoder_init_mode) {
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC,
+ "mpeg-1 (ffmpeg)");
+
+ init_video_codec (this, BUF_VIDEO_MPEG);
+ this->decoder_init_mode = 0;
+ }
+
+ /* frame format change */
+ if ((parser->width != this->bih.biWidth) ||
+ (parser->height != this->bih.biHeight) ||
+ (parser->frame_aspect_ratio != this->aspect_ratio)) {
+ xine_event_t event;
+ xine_format_change_data_t data;
+
+ this->bih.biWidth = parser->width;
+ this->bih.biHeight = parser->height;
+ this->aspect_ratio = parser->frame_aspect_ratio;
+ this->aspect_ratio_prio = 2;
+ lprintf("mpeg seq aspect ratio: %f\n", this->aspect_ratio);
+ set_stream_info(this);
+
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = this->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = this->bih.biWidth;
+ data.height = this->bih.biHeight;
+ data.aspect = this->aspect_ratio;
+ data.pan_scan = 0;
+ xine_event_send(this->stream, &event);
+ }
+ this->video_step = this->mpeg_parser->frame_duration;
+
+ return 1;
+}
+
+static void ff_convert_frame(ff_video_decoder_t *this, vo_frame_t *img) {
+ int y;
+ uint8_t *dy, *du, *dv, *sy, *su, *sv;
+
+ dy = img->base[0];
+ du = img->base[1];
+ dv = img->base[2];
+ sy = this->av_frame->data[0];
+ su = this->av_frame->data[1];
+ sv = this->av_frame->data[2];
+
+ if (this->context->pix_fmt == PIX_FMT_YUV410P) {
+
+ yuv9_to_yv12(
+ /* Y */
+ this->av_frame->data[0],
+ this->av_frame->linesize[0],
+ img->base[0],
+ img->pitches[0],
+ /* U */
+ this->av_frame->data[1],
+ this->av_frame->linesize[1],
+ img->base[1],
+ img->pitches[1],
+ /* V */
+ this->av_frame->data[2],
+ this->av_frame->linesize[2],
+ img->base[2],
+ img->pitches[2],
+ /* width x height */
+ img->width,
+ img->height);
+
+ } else if (this->context->pix_fmt == PIX_FMT_YUV411P) {
+
+ yuv411_to_yv12(
+ /* Y */
+ this->av_frame->data[0],
+ this->av_frame->linesize[0],
+ img->base[0],
+ img->pitches[0],
+ /* U */
+ this->av_frame->data[1],
+ this->av_frame->linesize[1],
+ img->base[1],
+ img->pitches[1],
+ /* V */
+ this->av_frame->data[2],
+ this->av_frame->linesize[2],
+ img->base[2],
+ img->pitches[2],
+ /* width x height */
+ img->width,
+ img->height);
+
+ } else if (this->context->pix_fmt == PIX_FMT_RGBA32) {
+
+ int x, plane_ptr = 0;
+ uint32_t *argb_pixels;
+ uint32_t argb;
+
+ for(y = 0; y < img->height; y++) {
+ argb_pixels = (uint32_t *)sy;
+ for(x = 0; x < img->width; x++) {
+ uint8_t r, g, b;
+
+ /* this is endian-safe as the ARGB pixels are stored in
+ * machine order */
+ argb = *argb_pixels++;
+ r = (argb >> 16) & 0xFF;
+ g = (argb >> 8) & 0xFF;
+ b = (argb >> 0) & 0xFF;
+
+ this->yuv.y[plane_ptr] = COMPUTE_Y(r, g, b);
+ this->yuv.u[plane_ptr] = COMPUTE_U(r, g, b);
+ this->yuv.v[plane_ptr] = COMPUTE_V(r, g, b);
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else if (this->context->pix_fmt == PIX_FMT_RGB565) {
+
+ int x, plane_ptr = 0;
+ uint8_t *src;
+ uint16_t pixel16;
+
+ for(y = 0; y < img->height; y++) {
+ src = sy;
+ for(x = 0; x < img->width; x++) {
+ uint8_t r, g, b;
+
+ /* a 16-bit RGB565 pixel is supposed to be stored in native-endian
+ * byte order; the following should be endian-safe */
+ pixel16 = *((uint16_t *)src);
+ src += 2;
+ b = (pixel16 << 3) & 0xFF;
+ g = (pixel16 >> 3) & 0xFF;
+ r = (pixel16 >> 8) & 0xFF;
+
+ this->yuv.y[plane_ptr] = COMPUTE_Y(r, g, b);
+ this->yuv.u[plane_ptr] = COMPUTE_U(r, g, b);
+ this->yuv.v[plane_ptr] = COMPUTE_V(r, g, b);
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else if (this->context->pix_fmt == PIX_FMT_RGB555) {
+
+ int x, plane_ptr = 0;
+ uint8_t *src;
+ uint16_t pixel16;
+
+ for(y = 0; y < img->height; y++) {
+ src = sy;
+ for(x = 0; x < img->width; x++) {
+ uint8_t r, g, b;
+
+ /* a 16-bit RGB555 pixel is supposed to be stored in native-endian
+ * byte order; the following should be endian-safe */
+ pixel16 = *((uint16_t *)src);
+ src += 2;
+ b = (pixel16 << 3) & 0xFF;
+ g = (pixel16 >> 2) & 0xFF;
+ r = (pixel16 >> 7) & 0xFF;
+
+ this->yuv.y[plane_ptr] = COMPUTE_Y(r, g, b);
+ this->yuv.u[plane_ptr] = COMPUTE_U(r, g, b);
+ this->yuv.v[plane_ptr] = COMPUTE_V(r, g, b);
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else if (this->context->pix_fmt == PIX_FMT_BGR24) {
+
+ int x, plane_ptr = 0;
+ uint8_t *src;
+
+ for(y = 0; y < img->height; y++) {
+ src = sy;
+ for(x = 0; x < img->width; x++) {
+ uint8_t r, g, b;
+
+ b = *src++;
+ g = *src++;
+ r = *src++;
+
+ this->yuv.y[plane_ptr] = COMPUTE_Y(r, g, b);
+ this->yuv.u[plane_ptr] = COMPUTE_U(r, g, b);
+ this->yuv.v[plane_ptr] = COMPUTE_V(r, g, b);
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else if (this->context->pix_fmt == PIX_FMT_RGB24) {
+
+ int x, plane_ptr = 0;
+ uint8_t *src;
+
+ for(y = 0; y < img->height; y++) {
+ src = sy;
+ for(x = 0; x < img->width; x++) {
+ uint8_t r, g, b;
+
+ r = *src++;
+ g = *src++;
+ b = *src++;
+
+ this->yuv.y[plane_ptr] = COMPUTE_Y(r, g, b);
+ this->yuv.u[plane_ptr] = COMPUTE_U(r, g, b);
+ this->yuv.v[plane_ptr] = COMPUTE_V(r, g, b);
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else if (this->context->pix_fmt == PIX_FMT_PAL8) {
+
+ int x, plane_ptr = 0;
+ uint8_t *src;
+ uint8_t pixel;
+ uint32_t *palette32 = (uint32_t *)su; /* palette is in data[1] */
+ uint32_t rgb_color;
+ uint8_t r, g, b;
+ uint8_t y_palette[256];
+ uint8_t u_palette[256];
+ uint8_t v_palette[256];
+
+ for (x = 0; x < 256; x++) {
+ rgb_color = palette32[x];
+ b = rgb_color & 0xFF;
+ rgb_color >>= 8;
+ g = rgb_color & 0xFF;
+ rgb_color >>= 8;
+ r = rgb_color & 0xFF;
+ y_palette[x] = COMPUTE_Y(r, g, b);
+ u_palette[x] = COMPUTE_U(r, g, b);
+ v_palette[x] = COMPUTE_V(r, g, b);
+ }
+
+ for(y = 0; y < img->height; y++) {
+ src = sy;
+ for(x = 0; x < img->width; x++) {
+ pixel = *src++;
+
+ this->yuv.y[plane_ptr] = y_palette[pixel];
+ this->yuv.u[plane_ptr] = u_palette[pixel];
+ this->yuv.v[plane_ptr] = v_palette[pixel];
+ plane_ptr++;
+ }
+ sy += this->av_frame->linesize[0];
+ }
+
+ yuv444_to_yuy2(&this->yuv, img->base[0], img->pitches[0]);
+
+ } else {
+
+ for (y=0; y<img->height; y++) {
+ xine_fast_memcpy (dy, sy, img->width);
+
+ dy += img->pitches[0];
+
+ sy += this->av_frame->linesize[0];
+ }
+
+ for (y=0; y<(img->height/2); y++) {
+
+ if (this->context->pix_fmt != PIX_FMT_YUV444P) {
+
+ xine_fast_memcpy (du, su, img->width/2);
+ xine_fast_memcpy (dv, sv, img->width/2);
+
+ } else {
+
+ int x;
+ uint8_t *src;
+ uint8_t *dst;
+
+ /* subsample */
+
+ src = su; dst = du;
+ for (x=0; x<(img->width/2); x++) {
+ *dst = *src;
+ dst++;
+ src += 2;
+ }
+ src = sv; dst = dv;
+ for (x=0; x<(img->width/2); x++) {
+ *dst = *src;
+ dst++;
+ src += 2;
+ }
+
+ }
+
+ du += img->pitches[1];
+ dv += img->pitches[2];
+
+ if (this->context->pix_fmt != PIX_FMT_YUV420P) {
+ su += 2*this->av_frame->linesize[1];
+ sv += 2*this->av_frame->linesize[2];
+ } else {
+ su += this->av_frame->linesize[1];
+ sv += this->av_frame->linesize[2];
+ }
+ }
+ }
+}
+
+static void ff_check_bufsize (ff_video_decoder_t *this, int size) {
+ if (size > this->bufsize) {
+ this->bufsize = size + size / 2;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: increasing buffer to %d to avoid overflow.\n"),
+ this->bufsize);
+ this->buf = realloc(this->buf, this->bufsize + FF_INPUT_BUFFER_PADDING_SIZE );
+ }
+}
+
+static void ff_handle_preview_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
+ int codec_type;
+
+ lprintf ("preview buffer\n");
+
+ codec_type = buf->type & 0xFFFF0000;
+ if (codec_type == BUF_VIDEO_MPEG) {
+ this->is_mpeg12 = 1;
+ if ( this->mpeg_parser == NULL ) {
+ this->mpeg_parser = xine_xmalloc(sizeof(mpeg_parser_t));
+ mpeg_parser_init(this->mpeg_parser);
+ this->decoder_init_mode = 0;
+ }
+ }
+
+ if (this->decoder_init_mode && !this->is_mpeg12) {
+ init_video_codec(this, codec_type);
+ init_postprocess(this);
+ this->decoder_init_mode = 0;
+ }
+}
+
+static void ff_handle_header_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
+
+ lprintf ("header buffer\n");
+
+ /* accumulate data */
+ ff_check_bufsize(this, this->size + buf->size);
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+ this->size += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+ int codec_type;
+
+ lprintf ("header complete\n");
+ codec_type = buf->type & 0xFFFF0000;
+
+ if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
+
+ lprintf("standard header\n");
+
+ /* init package containing bih */
+ memcpy ( &this->bih, this->buf, sizeof(xine_bmiheader) );
+
+ if (this->bih.biSize > sizeof(xine_bmiheader)) {
+ this->context->extradata_size = this->bih.biSize - sizeof(xine_bmiheader);
+ this->context->extradata = malloc(this->context->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(this->context->extradata, this->buf + sizeof(xine_bmiheader),
+ this->context->extradata_size);
+ }
+
+ this->context->bits_per_sample = this->bih.biBitCount;
+
+ } else {
+
+ switch (codec_type) {
+ case BUF_VIDEO_RV10:
+ case BUF_VIDEO_RV20:
+ this->bih.biWidth = _X_BE_16(&this->buf[12]);
+ this->bih.biHeight = _X_BE_16(&this->buf[14]);
+
+ this->context->sub_id = _X_BE_32(&this->buf[30]);
+
+ this->context->slice_offset = xine_xmalloc(sizeof(int)*SLICE_OFFSET_SIZE);
+ this->slice_offset_size = SLICE_OFFSET_SIZE;
+
+ lprintf("w=%d, h=%d\n", this->bih.biWidth, this->bih.biHeight);
+
+ break;
+ default:
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_video_dec: unknown header for buf type 0x%X\n", codec_type);
+ return;
+ }
+ }
+
+ /* reset accumulator */
+ this->size = 0;
+ }
+}
+
+static void ff_handle_special_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
+ /* take care of all the various types of special buffers
+ * note that order is important here */
+ lprintf("special buffer\n");
+
+ if (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM &&
+ !this->context->extradata_size) {
+
+ lprintf("BUF_SPECIAL_STSD_ATOM\n");
+ this->context->extradata_size = buf->decoder_info[2];
+ this->context->extradata = xine_xmalloc(buf->decoder_info[2] +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(this->context->extradata, buf->decoder_info_ptr[2],
+ buf->decoder_info[2]);
+
+ } else if (buf->decoder_info[1] == BUF_SPECIAL_DECODER_CONFIG &&
+ !this->context->extradata_size) {
+
+ lprintf("BUF_SPECIAL_DECODER_CONFIG\n");
+ this->context->extradata_size = buf->decoder_info[2];
+ this->context->extradata = xine_xmalloc(buf->decoder_info[2] +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(this->context->extradata, buf->decoder_info_ptr[2],
+ buf->decoder_info[2]);
+
+ } else if (buf->decoder_info[1] == BUF_SPECIAL_PALETTE) {
+ unsigned int i;
+
+ palette_entry_t *demuxer_palette;
+ AVPaletteControl *decoder_palette;
+
+ lprintf("BUF_SPECIAL_PALETTE\n");
+ this->context->palctrl = &this->palette_control;
+ decoder_palette = (AVPaletteControl *)this->context->palctrl;
+ demuxer_palette = (palette_entry_t *)buf->decoder_info_ptr[2];
+
+ for (i = 0; i < buf->decoder_info[2]; i++) {
+ decoder_palette->palette[i] =
+ (demuxer_palette[i].r << 16) |
+ (demuxer_palette[i].g << 8) |
+ (demuxer_palette[i].b << 0);
+ }
+ decoder_palette->palette_changed = 1;
+
+ } else if (buf->decoder_info[1] == BUF_SPECIAL_RV_CHUNK_TABLE) {
+ int i;
+
+ lprintf("BUF_SPECIAL_RV_CHUNK_TABLE\n");
+ this->context->slice_count = buf->decoder_info[2]+1;
+
+ lprintf("slice_count=%d\n", this->context->slice_count);
+
+ if(this->context->slice_count > this->slice_offset_size) {
+ this->context->slice_offset = realloc(this->context->slice_offset,
+ sizeof(int)*this->context->slice_count);
+ this->slice_offset_size = this->context->slice_count;
+ }
+
+ for(i = 0; i < this->context->slice_count; i++) {
+ this->context->slice_offset[i] =
+ ((uint32_t *) buf->decoder_info_ptr[2])[(2*i)+1];
+ lprintf("slice_offset[%d]=%d\n", i, this->context->slice_offset[i]);
+ }
+ }
+}
+
+static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
+
+ vo_frame_t *img;
+ int free_img;
+ int got_picture, len;
+ int offset = 0;
+ int flush = 0;
+ int size = buf->size;
+
+ lprintf("handle_mpeg12_buffer\n");
+
+ while ((size > 0) || (flush == 1)) {
+
+ uint8_t *current;
+ int next_flush;
+
+ got_picture = 0;
+ if (!flush) {
+ current = mpeg_parser_decode_data(this->mpeg_parser,
+ buf->content + offset, buf->content + offset + size,
+ &next_flush);
+ } else {
+ current = buf->content + offset + size; /* end of the buffer */
+ next_flush = 0;
+ }
+ if (current == NULL) {
+ lprintf("current == NULL\n");
+ return;
+ }
+
+ if (this->mpeg_parser->has_sequence) {
+ ff_handle_mpeg_sequence(this, this->mpeg_parser);
+ }
+
+ if (!this->decoder_ok)
+ return;
+
+ if (flush) {
+ lprintf("flush lavc buffers\n");
+ /* hack: ffmpeg outputs the last frame if size=0 */
+ this->mpeg_parser->buffer_size = 0;
+ }
+
+ /* skip decoding b frames if too late */
+ this->context->hurry_up = (this->skipframes > 0);
+
+ lprintf("avcodec_decode_video: size=%d\n", this->mpeg_parser->buffer_size);
+ len = avcodec_decode_video (this->context, this->av_frame,
+ &got_picture, this->mpeg_parser->chunk_buffer,
+ this->mpeg_parser->buffer_size);
+ lprintf("avcodec_decode_video: decoded_size=%d, got_picture=%d\n",
+ len, got_picture);
+ len = current - buf->content - offset;
+ lprintf("avcodec_decode_video: consumed_size=%d\n", len);
+
+ flush = next_flush;
+
+ if ((len < 0) || (len > buf->size)) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_video_dec: error decompressing frame\n");
+ size = 0; /* draw a bad frame and exit */
+ } else {
+ size -= len;
+ offset += len;
+ }
+
+ if (got_picture && this->av_frame->data[0]) {
+ /* got a picture, draw it */
+ if(!this->av_frame->opaque) {
+ /* indirect rendering */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ this->bih.biWidth,
+ this->bih.biHeight,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ free_img = 1;
+ } else {
+ /* DR1 */
+ img = (vo_frame_t*) this->av_frame->opaque;
+ free_img = 0;
+ }
+
+ img->pts = this->pts;
+ this->pts = 0;
+
+ if (this->av_frame->repeat_pict)
+ img->duration = this->video_step * 3 / 2;
+ else
+ img->duration = this->video_step;
+
+ img->crop_right = this->crop_right;
+ img->crop_bottom = this->crop_bottom;
+
+ this->skipframes = img->draw(img, this->stream);
+
+ if(free_img)
+ img->free(img);
+
+ } else {
+
+ if (this->context->hurry_up) {
+ /* skipped frame, output a bad frame */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ this->bih.biWidth,
+ this->bih.biHeight,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ img->pts = 0;
+ img->duration = this->video_step;
+ img->bad_frame = 1;
+ this->skipframes = img->draw(img, this->stream);
+ img->free(img);
+ }
+ }
+ }
+}
+
+static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
+ uint8_t *chunk_buf = this->buf;
+ AVRational avr00 = {0, 1};
+
+ lprintf("handle_buffer\n");
+
+ if (!this->decoder_ok) {
+ if (this->decoder_init_mode) {
+ int codec_type = buf->type & 0xFFFF0000;
+
+ /* init ffmpeg decoder */
+ init_video_codec(this, codec_type);
+ init_postprocess(this);
+ this->decoder_init_mode = 0;
+ } else {
+ return;
+ }
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_START) {
+ lprintf("BUF_FLAG_FRAME_START\n");
+ this->size = 0;
+ }
+
+ /* data accumulation */
+ if (buf->size > 0) {
+ if ((this->size == 0) &&
+ ((buf->size + FF_INPUT_BUFFER_PADDING_SIZE) < buf->max_size) &&
+ (buf->decoder_flags & BUF_FLAG_FRAME_END)) {
+ /* buf contains a complete frame */
+ /* no memcpy needed */
+ chunk_buf = buf->content;
+ this->size = buf->size;
+ lprintf("no memcpy needed to accumulate data\n");
+ } else {
+ /* copy data into our internal buffer */
+ ff_check_bufsize(this, this->size + buf->size);
+ chunk_buf = this->buf; /* ff_check_bufsize might realloc this->buf */
+
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+
+ this->size += buf->size;
+ lprintf("accumulate data into this->buf\n");
+ }
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+
+ vo_frame_t *img;
+ int free_img;
+ int got_picture, len;
+ int got_one_picture = 0;
+ int offset = 0;
+ int codec_type = buf->type & 0xFFFF0000;
+ int video_step_to_use = this->video_step;
+
+ /* pad input data */
+ /* note: bitstream, alt bitstream reader or something will cause
+ * severe mpeg4 artifacts if padding is less than 32 bits.
+ */
+ memset(&chunk_buf[this->size], 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ while (this->size > 0) {
+
+ /* DV frames can be completely skipped */
+ if( codec_type == BUF_VIDEO_DV && this->skipframes ) {
+ this->size = 0;
+ got_picture = 0;
+ } else {
+ /* skip decoding b frames if too late */
+ this->context->hurry_up = (this->skipframes > 0);
+
+ lprintf("buffer size: %d\n", this->size);
+ len = avcodec_decode_video (this->context, this->av_frame,
+ &got_picture, &chunk_buf[offset],
+ this->size);
+ lprintf("consumed size: %d, got_picture: %d\n", len, got_picture);
+ if ((len <= 0) || (len > this->size)) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_video_dec: error decompressing frame\n");
+ this->size = 0;
+
+ } else {
+
+ offset += len;
+ this->size -= len;
+
+ if (this->size > 0) {
+ ff_check_bufsize(this, this->size);
+ memmove (this->buf, &chunk_buf[offset], this->size);
+ chunk_buf = this->buf;
+ }
+ }
+ }
+
+ /* use externally provided video_step or fall back to stream's time_base otherwise */
+ video_step_to_use = (this->video_step || !this->context->time_base.den) ? this->video_step : (int)(90000ll * this->context->time_base.num / this->context->time_base.den);
+
+ /* aspect ratio provided by ffmpeg, override previous setting */
+ if ((this->aspect_ratio_prio < 2) &&
+ av_cmp_q(this->context->sample_aspect_ratio, avr00)) {
+
+ if (!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = this->context->width;
+ this->bih.biHeight = this->context->height;
+ }
+
+ this->aspect_ratio = av_q2d(this->context->sample_aspect_ratio) *
+ (double)this->bih.biWidth / (double)this->bih.biHeight;
+ this->aspect_ratio_prio = 2;
+ lprintf("ffmpeg aspect ratio: %f\n", this->aspect_ratio);
+ set_stream_info(this);
+ }
+
+ if (got_picture && this->av_frame->data[0]) {
+ /* got a picture, draw it */
+ got_one_picture = 1;
+ if(!this->av_frame->opaque) {
+ /* indirect rendering */
+
+ /* initialize the colorspace converter */
+ if (!this->cs_convert_init) {
+ if ((this->context->pix_fmt == PIX_FMT_RGBA32) ||
+ (this->context->pix_fmt == PIX_FMT_RGB565) ||
+ (this->context->pix_fmt == PIX_FMT_RGB555) ||
+ (this->context->pix_fmt == PIX_FMT_BGR24) ||
+ (this->context->pix_fmt == PIX_FMT_RGB24) ||
+ (this->context->pix_fmt == PIX_FMT_PAL8)) {
+ this->output_format = XINE_IMGFMT_YUY2;
+ init_yuv_planes(&this->yuv, this->bih.biWidth, this->bih.biHeight);
+ this->yuv_init = 1;
+ }
+ this->cs_convert_init = 1;
+ }
+
+ if (this->aspect_ratio_prio == 0) {
+ this->aspect_ratio = (double)this->bih.biWidth / (double)this->bih.biHeight;
+ this->aspect_ratio_prio = 1;
+ lprintf("default aspect ratio: %f\n", this->aspect_ratio);
+ set_stream_info(this);
+ }
+
+ /* xine-lib expects the framesize to be a multiple of 16x16 (macroblock) */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ (this->bih.biWidth + 15) & ~15,
+ (this->bih.biHeight + 15) & ~15,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ free_img = 1;
+ } else {
+ /* DR1 */
+ img = (vo_frame_t*) this->av_frame->opaque;
+ free_img = 0;
+ }
+
+ /* post processing */
+ if(this->pp_quality != this->class->pp_quality)
+ pp_change_quality(this);
+
+ if(this->pp_available && this->pp_quality) {
+
+ if(this->av_frame->opaque) {
+ /* DR1 */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ (img->width + 15) & ~15,
+ (img->height + 15) & ~15,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ free_img = 1;
+ }
+
+ pp_postprocess(this->av_frame->data, this->av_frame->linesize,
+ img->base, img->pitches,
+ img->width, img->height,
+ this->av_frame->qscale_table, this->av_frame->qstride,
+ this->pp_mode, this->pp_context,
+ this->av_frame->pict_type);
+
+ } else if (!this->av_frame->opaque) {
+ /* colorspace conversion or copy */
+ ff_convert_frame(this, img);
+ }
+
+ img->pts = this->pts;
+ this->pts = 0;
+
+ /* workaround for weird 120fps streams */
+ if( video_step_to_use == 750 ) {
+ /* fallback to the VIDEO_PTS_MODE */
+ video_step_to_use = 0;
+ }
+
+ if (this->av_frame->repeat_pict)
+ img->duration = video_step_to_use * 3 / 2;
+ else
+ img->duration = video_step_to_use;
+
+ /* additionally crop away the extra pixels due to adjusting frame size above */
+ img->crop_right = this->crop_right + (img->width - this->bih.biWidth);
+ img->crop_bottom = this->crop_bottom + (img->height - this->bih.biHeight);
+
+ /* transfer some more frame settings for deinterlacing */
+ img->progressive_frame = !this->av_frame->interlaced_frame;
+ img->top_field_first = this->av_frame->top_field_first;
+
+ this->skipframes = img->draw(img, this->stream);
+
+ if(free_img)
+ img->free(img);
+ }
+ }
+
+ /* workaround for demux_mpeg_pes sending fields as frames:
+ * do not generate a bad frame for the first field picture
+ */
+ if (!got_one_picture && (this->size || this->video_step || this->assume_bad_field_picture)) {
+ /* skipped frame, output a bad frame (use size 16x16, when size still uninitialized) */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ (this->bih.biWidth <= 0) ? 16 : ((this->bih.biWidth + 15) & ~15),
+ (this->bih.biHeight <= 0) ? 16 : ((this->bih.biHeight + 15) & ~15),
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ /* set PTS to allow early syncing */
+ img->pts = this->pts;
+ this->pts = 0;
+
+ img->duration = video_step_to_use;
+
+ /* additionally crop away the extra pixels due to adjusting frame size above */
+ img->crop_right = ((this->bih.biWidth <= 0) ? 0 : this->crop_right) + (img->width - this->bih.biWidth);
+ img->crop_bottom = ((this->bih.biHeight <= 0) ? 0 : this->crop_bottom) + (img->height - this->bih.biHeight);
+
+ img->bad_frame = 1;
+ this->skipframes = img->draw(img, this->stream);
+ img->free(img);
+ }
+
+ this->assume_bad_field_picture = !got_one_picture;
+ }
+}
+
+static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
+ ff_video_decoder_t *this = (ff_video_decoder_t *) this_gen;
+
+ lprintf ("processing packet type = %08x, len = %d, decoder_flags=%08x\n",
+ buf->type, buf->size, buf->decoder_flags);
+
+ if (buf->decoder_flags & BUF_FLAG_FRAMERATE) {
+ this->video_step = buf->decoder_info[0];
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->video_step);
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_PREVIEW) {
+
+ ff_handle_preview_buffer(this, buf);
+
+ } else {
+
+ if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
+
+ ff_handle_special_buffer(this, buf);
+
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_HEADER) {
+
+ ff_handle_header_buffer(this, buf);
+
+ if (buf->decoder_flags & BUF_FLAG_ASPECT) {
+ if (this->aspect_ratio_prio < 3) {
+ this->aspect_ratio = (double)buf->decoder_info[1] / (double)buf->decoder_info[2];
+ this->aspect_ratio_prio = 3;
+ lprintf("aspect ratio: %f\n", this->aspect_ratio);
+ set_stream_info(this);
+ }
+ }
+
+ } else {
+
+ /* decode */
+ if (buf->pts)
+ this->pts = buf->pts;
+
+ if (this->is_mpeg12) {
+ ff_handle_mpeg12_buffer(this, buf);
+ } else {
+ ff_handle_buffer(this, buf);
+ }
+
+ }
+ }
+}
+
+static void ff_flush (video_decoder_t *this_gen) {
+ lprintf ("ff_flush\n");
+}
+
+static void ff_reset (video_decoder_t *this_gen) {
+ ff_video_decoder_t *this = (ff_video_decoder_t *) this_gen;
+
+ lprintf ("ff_reset\n");
+
+ this->size = 0;
+
+ if(this->context && this->decoder_ok)
+ avcodec_flush_buffers(this->context);
+
+ if (this->is_mpeg12)
+ mpeg_parser_reset(this->mpeg_parser);
+}
+
+static void ff_discontinuity (video_decoder_t *this_gen) {
+ ff_video_decoder_t *this = (ff_video_decoder_t *) this_gen;
+
+ lprintf ("ff_discontinuity\n");
+ this->pts = 0;
+}
+
+static void ff_dispose (video_decoder_t *this_gen) {
+ ff_video_decoder_t *this = (ff_video_decoder_t *) this_gen;
+
+ lprintf ("ff_dispose\n");
+
+ if (this->decoder_ok) {
+ xine_list_iterator_t it;
+ AVFrame *av_frame;
+
+ pthread_mutex_lock(&ffmpeg_lock);
+ avcodec_close (this->context);
+ pthread_mutex_unlock(&ffmpeg_lock);
+
+ /* frame garbage collector here - workaround for buggy ffmpeg codecs that
+ * don't release their DR1 frames */
+ while( (it = xine_list_front(this->dr1_frames)) != NULL )
+ {
+ av_frame = (AVFrame *)xine_list_get_value(this->dr1_frames, it);
+ release_buffer(this->context, av_frame);
+ }
+
+ this->stream->video_out->close(this->stream->video_out, this->stream);
+ this->decoder_ok = 0;
+ }
+
+ if(this->context && this->context->slice_offset)
+ free(this->context->slice_offset);
+
+ if(this->context && this->context->extradata)
+ free(this->context->extradata);
+
+ if(this->yuv_init)
+ free_yuv_planes(&this->yuv);
+
+ if( this->context )
+ free( this->context );
+
+ if( this->av_frame )
+ free( this->av_frame );
+
+ if (this->buf)
+ free(this->buf);
+ this->buf = NULL;
+
+ if(this->pp_context)
+ pp_free_context(this->pp_context);
+
+ if(this->pp_mode)
+ pp_free_mode(this->pp_mode);
+
+ mpeg_parser_dispose(this->mpeg_parser);
+
+ xine_list_delete(this->dr1_frames);
+
+ free (this_gen);
+}
+
+static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ ff_video_decoder_t *this ;
+
+ lprintf ("open_plugin\n");
+
+ this = (ff_video_decoder_t *) xine_xmalloc (sizeof (ff_video_decoder_t));
+
+ this->video_decoder.decode_data = ff_decode_data;
+ this->video_decoder.flush = ff_flush;
+ this->video_decoder.reset = ff_reset;
+ this->video_decoder.discontinuity = ff_discontinuity;
+ this->video_decoder.dispose = ff_dispose;
+ this->size = 0;
+
+ this->stream = stream;
+ this->class = (ff_video_class_t *) class_gen;
+
+ this->av_frame = avcodec_alloc_frame();
+ this->context = avcodec_alloc_context();
+ this->context->opaque = this;
+ this->context->palctrl = NULL;
+
+ this->decoder_ok = 0;
+ this->decoder_init_mode = 1;
+ this->buf = xine_xmalloc(VIDEOBUFSIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+ this->bufsize = VIDEOBUFSIZE;
+
+ this->is_mpeg12 = 0;
+ this->aspect_ratio = 0;
+
+ this->pp_quality = 0;
+ this->pp_context = NULL;
+ this->pp_mode = NULL;
+
+ this->mpeg_parser = NULL;
+
+ this->dr1_frames = xine_list_new();
+
+ return &this->video_decoder;
+}
+
+void *init_video_plugin (xine_t *xine, void *data) {
+
+ ff_video_class_t *this;
+ config_values_t *config;
+
+ this = (ff_video_class_t *) xine_xmalloc (sizeof (ff_video_class_t));
+
+ this->decoder_class.open_plugin = ff_video_open_plugin;
+ this->decoder_class.identifier = "ffmpeg video";
+ this->decoder_class.description = N_("ffmpeg based video decoder plugin");
+ this->decoder_class.dispose = default_video_decoder_class_dispose;
+ this->xine = xine;
+
+ pthread_once( &once_control, init_once_routine );
+
+ /* Configuration for post processing quality - default to mid (3) for the
+ * moment */
+ config = xine->config;
+
+ this->pp_quality = xine->config->register_range(config, "video.processing.ffmpeg_pp_quality", 3,
+ 0, PP_QUALITY_MAX,
+ _("MPEG-4 postprocessing quality"),
+ _("You can adjust the amount of post processing applied to MPEG-4 video.\n"
+ "Higher values result in better quality, but need more CPU. Lower values may "
+ "result in image defects like block artifacts. For high quality content, "
+ "too heavy post processing can actually make the image worse by blurring it "
+ "too much."),
+ 10, pp_quality_cb, this);
+
+ this->thread_count = xine->config->register_num(config, "video.processing.ffmpeg_thread_count", 1,
+ _("FFmpeg video decoding thread count"),
+ _("You can adjust the number of video decoding threads which FFmpeg may use.\n"
+ "Higher values should speed up decoding but it depends on the codec used "
+ "whether parallel decoding is supported. A rule of thumb is to have one "
+ "decoding thread per logical CPU (typically 1 to 4).\n"
+ "A change of this setting will take effect with playing the next stream."),
+ 10, thread_count_cb, this);
+
+ this->skip_loop_filter_enum = xine->config->register_enum(config, "video.processing.ffmpeg_skip_loop_filter", 0,
+ (char **)skip_loop_filter_enum_names,
+ _("Skip loop filter"),
+ _("You can control for which frames the loop filter shall be skipped after "
+ "decoding.\n"
+ "Skipping the loop filter will speedup decoding but may lead to artefacts. "
+ "The number of frames for which it is skipped increases from 'none' to 'all'. "
+ "The default value leaves the decision up to the implementation.\n"
+ "A change of this setting will take effect with playing the next stream."),
+ 10, skip_loop_filter_enum_cb, this);
+
+ this->choose_speed_over_accuracy = xine->config->register_bool(config, "video.processing.ffmpeg_choose_speed_over_accuracy", 0,
+ _("Choose speed over specification compliance"),
+ _("You may want to allow speed cheats which violate codec specification.\n"
+ "Cheating may speed up decoding but can also lead to decoding artefacts.\n"
+ "A change of this setting will take effect with playing the next stream."),
+ 10, choose_speed_over_accuracy_cb, this);
+
+ return this;
+}
+
+static const uint32_t supported_video_types[] = {
+#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V1_DECODER
+ BUF_VIDEO_MSMPEG4_V1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V2_DECODER
+ BUF_VIDEO_MSMPEG4_V2,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V3_DECODER
+ BUF_VIDEO_MSMPEG4_V3,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WMV1_DECODER
+ BUF_VIDEO_WMV7,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WMV2_DECODER
+ BUF_VIDEO_WMV8,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WMV3_DECODER
+ BUF_VIDEO_WMV9,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VC1_DECODER
+ BUF_VIDEO_VC1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER
+ BUF_VIDEO_MPEG4,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER
+ BUF_VIDEO_XVID,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER
+ BUF_VIDEO_DIVX5,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER
+ BUF_VIDEO_3IVX,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MJPEG_DECODER
+ BUF_VIDEO_JPEG,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MJPEG_DECODER
+ BUF_VIDEO_MJPEG,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MJPEGB_DECODER
+ BUF_VIDEO_MJPEG_B,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_H263I_DECODER
+ BUF_VIDEO_I263,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_H263_DECODER
+ BUF_VIDEO_H263,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_RV10_DECODER
+ BUF_VIDEO_RV10,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_RV20_DECODER
+ BUF_VIDEO_RV20,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_INDEO3_DECODER
+ BUF_VIDEO_IV31,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_INDEO3_DECODER
+ BUF_VIDEO_IV32,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SVQ1_DECODER
+ BUF_VIDEO_SORENSON_V1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SVQ3_DECODER
+ BUF_VIDEO_SORENSON_V3,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_DVVIDEO_DECODER
+ BUF_VIDEO_DV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_HUFFYUV_DECODER
+ BUF_VIDEO_HUFFYUV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VP3_DECODER
+ BUF_VIDEO_VP31,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VP5_DECODER
+ BUF_VIDEO_VP5,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VP6_DECODER
+ BUF_VIDEO_VP6,
+ BUF_VIDEO_VP6F,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_4XM_DECODER
+ BUF_VIDEO_4XM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_CINEPAK_DECODER
+ BUF_VIDEO_CINEPAK,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MSVIDEO1_DECODER
+ BUF_VIDEO_MSVC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MSRLE_DECODER
+ BUF_VIDEO_MSRLE,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_RPZA_DECODER
+ BUF_VIDEO_RPZA,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_CYUV_DECODER
+ BUF_VIDEO_CYUV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ROQ_DECODER
+ BUF_VIDEO_ROQ,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_IDCIN_DECODER
+ BUF_VIDEO_IDCIN,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_XAN_WC3_DECODER
+ BUF_VIDEO_WC3,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WS_VQA_DECODER
+ BUF_VIDEO_VQA,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_INTERPLAY_VIDEO_DECODER
+ BUF_VIDEO_INTERPLAY,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_FLIC_DECODER
+ BUF_VIDEO_FLI,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_8BPS_DECODER
+ BUF_VIDEO_8BPS,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SMC_DECODER
+ BUF_VIDEO_SMC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_TRUEMOTION1_DECODER
+ BUF_VIDEO_DUCKTM1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_TRUEMOTION2_DECODER
+ BUF_VIDEO_DUCKTM2,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VMDVIDEO_DECODER
+ BUF_VIDEO_VMD,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ZLIB_DECODER
+ BUF_VIDEO_ZLIB,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MSZH_DECODER
+ BUF_VIDEO_MSZH,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ASV1_DECODER
+ BUF_VIDEO_ASV1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ASV2_DECODER
+ BUF_VIDEO_ASV2,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VCR1_DECODER
+ BUF_VIDEO_ATIVCR1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_FLV_DECODER
+ BUF_VIDEO_FLV1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_QTRLE_DECODER
+ BUF_VIDEO_QTRLE,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_H264_DECODER
+ BUF_VIDEO_H264,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_H261_DECODER
+ BUF_VIDEO_H261,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_AASC_DECODER
+ BUF_VIDEO_AASC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_LOCO_DECODER
+ BUF_VIDEO_LOCO,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_QDRAW_DECODER
+ BUF_VIDEO_QDRW,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_QPEG_DECODER
+ BUF_VIDEO_QPEG,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_TSCC_DECODER
+ BUF_VIDEO_TSCC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ULTI_DECODER
+ BUF_VIDEO_ULTI,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_WNV1_DECODER
+ BUF_VIDEO_WNV1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VIXL_DECODER
+ BUF_VIDEO_XL,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_INDEO2_DECODER
+ BUF_VIDEO_RT21,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_FRAPS_DECODER
+ BUF_VIDEO_FPS1,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MPEG1VIDEO_DECODER
+ BUF_VIDEO_MPEG,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_CSCD_DECODER
+ BUF_VIDEO_CSCD,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_AVS_DECODER
+ BUF_VIDEO_AVS,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_MMVIDEO_DECODER
+ BUF_VIDEO_ALGMM,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_ZMBV_DECODER
+ BUF_VIDEO_ZMBV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_SMACKVIDEO_DECODER
+ BUF_VIDEO_SMACKER,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_NUV_DECODER
+ BUF_VIDEO_NUV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_KMVC_DECODER
+ BUF_VIDEO_KMVC,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_FLASHSV_DECODER
+ BUF_VIDEO_FLASHSV,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_CAVS_DECODER
+ BUF_VIDEO_CAVS,
+#endif
+#if defined(HAVE_FFMPEG) || CONFIG_VMNC_DECODER
+ BUF_VIDEO_VMNC,
+#endif
+ BUF_VIDEO_THEORA_RAW,
+ 0
+};
+
+static const uint32_t wmv8_video_types[] = {
+ BUF_VIDEO_WMV8,
+ 0
+};
+
+static const uint32_t wmv9_video_types[] = {
+ BUF_VIDEO_WMV9,
+ 0
+};
+
+decoder_info_t dec_info_ffmpeg_video = {
+ supported_video_types, /* supported types */
+ 6 /* priority */
+};
+
+decoder_info_t dec_info_ffmpeg_wmv8 = {
+ wmv8_video_types, /* supported types */
+ 0 /* priority */
+};
+
+decoder_info_t dec_info_ffmpeg_wmv9 = {
+ wmv9_video_types, /* supported types */
+ 0 /* priority */
+};
diff --git a/src/combined/ffmpeg/ffmpeg_decoder.c b/src/combined/ffmpeg/ffmpeg_decoder.c
new file mode 100644
index 000000000..8a8a79270
--- /dev/null
+++ b/src/combined/ffmpeg/ffmpeg_decoder.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * xine decoder plugin using ffmpeg
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xine/xine_internal.h>
+
+#include "ffmpeg_decoder.h"
+
+/*
+ * common initialisation
+ */
+
+pthread_once_t once_control = PTHREAD_ONCE_INIT;
+pthread_mutex_t ffmpeg_lock;
+
+void init_once_routine(void) {
+ pthread_mutex_init(&ffmpeg_lock, NULL);
+ avcodec_init();
+ avcodec_register_all();
+}
+
+/*
+ * exported plugin catalog entry
+ */
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_DECODER | PLUGIN_MUST_PRELOAD, 19, "ffmpegvideo", XINE_VERSION_CODE, &dec_info_ffmpeg_video, init_video_plugin },
+ { PLUGIN_VIDEO_DECODER, 19, "ffmpeg-wmv8", XINE_VERSION_CODE, &dec_info_ffmpeg_wmv8, init_video_plugin },
+ { PLUGIN_VIDEO_DECODER, 19, "ffmpeg-wmv9", XINE_VERSION_CODE, &dec_info_ffmpeg_wmv9, init_video_plugin },
+ { PLUGIN_AUDIO_DECODER, 16, "ffmpegaudio", XINE_VERSION_CODE, &dec_info_ffmpeg_audio, init_audio_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/combined/ffmpeg/ffmpeg_decoder.h b/src/combined/ffmpeg/ffmpeg_decoder.h
new file mode 100644
index 000000000..bfe71a6b1
--- /dev/null
+++ b/src/combined/ffmpeg/ffmpeg_decoder.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2001-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ */
+
+#ifndef HAVE_XINE_DECODER_H
+#define HAVE_XINE_DECODER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <avcodec.h>
+
+typedef struct ff_codec_s {
+ uint32_t type;
+ enum CodecID id;
+ const char *name;
+} ff_codec_t;
+
+void *init_audio_plugin (xine_t *xine, void *data);
+void *init_video_plugin (xine_t *xine, void *data);
+
+extern decoder_info_t dec_info_ffmpeg_video;
+extern decoder_info_t dec_info_ffmpeg_wmv8;
+extern decoder_info_t dec_info_ffmpeg_wmv9;
+extern decoder_info_t dec_info_ffmpeg_audio;
+
+extern pthread_once_t once_control;
+void init_once_routine(void);
+
+extern pthread_mutex_t ffmpeg_lock;
+
+#endif
diff --git a/src/combined/ffmpeg/ffmpeg_encoder.c b/src/combined/ffmpeg/ffmpeg_encoder.c
new file mode 100644
index 000000000..7fe65c7fa
--- /dev/null
+++ b/src/combined/ffmpeg/ffmpeg_encoder.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ */
+
+/* mpeg encoders for the dxr3 video out plugin. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+
+#define LOG_MODULE "dxr3_mpeg_encoder"
+/* #define LOG_VERBOSE */
+/* #define LOG */
+
+#include "video_out_dxr3.h"
+
+#include <avcodec.h>
+
+/* buffer size for encoded mpeg1 stream; will hold one intra frame
+ * at 640x480 typical sizes are <50 kB. 512 kB should be plenty */
+#define DEFAULT_BUFFER_SIZE 512*1024
+
+
+/*initialisation function, used by the dxr3 plugin */
+int dxr3_encoder_init(dxr3_driver_t *drv) EXPORTED;
+
+/* functions required by encoder api */
+static int lavc_on_update_format(dxr3_driver_t *drv, dxr3_frame_t *frame);
+static int lavc_on_display_frame(dxr3_driver_t *drv, dxr3_frame_t *frame);
+static int lavc_on_unneeded(dxr3_driver_t *drv);
+
+/*encoder structure*/
+typedef struct lavc_data_s {
+ encoder_data_t encoder_data;
+ AVCodecContext *context; /* handle for encoding */
+ int width, height; /* width and height of the video frame */
+ uint8_t *ffmpeg_buffer; /* lavc buffer */
+ AVFrame *picture; /* picture to be encoded */
+ uint8_t *out[3]; /* aligned buffer for YV12 data */
+ uint8_t *buf; /* unaligned YV12 buffer */
+} lavc_data_t;
+
+
+int dxr3_encoder_init(dxr3_driver_t *drv)
+{
+ lavc_data_t* this;
+ avcodec_init();
+
+ avcodec_register_all();
+ lprintf("lavc init , version %x\n", avcodec_version());
+ this = xine_xmalloc(sizeof(lavc_data_t));
+ if (!this) return 0;
+
+ this->encoder_data.type = ENC_LAVC;
+ this->encoder_data.on_update_format = lavc_on_update_format;
+ this->encoder_data.on_frame_copy = NULL;
+ this->encoder_data.on_display_frame = lavc_on_display_frame;
+ this->encoder_data.on_unneeded = lavc_on_unneeded;
+ this->context = 0;
+
+ drv->enc = &this->encoder_data;
+ return 1;
+}
+
+/* helper function */
+static int lavc_prepare_frame(lavc_data_t *this, dxr3_driver_t *drv, dxr3_frame_t *frame);
+
+static int lavc_on_update_format(dxr3_driver_t *drv, dxr3_frame_t *frame)
+{
+ lavc_data_t *this = (lavc_data_t *)drv->enc;
+ AVCodec *codec;
+ unsigned char use_quantizer;
+
+ if (this->context) {
+ avcodec_close(this->context);
+ free(this->context);
+ free(this->picture);
+ this->context = NULL;
+ this->picture = NULL;
+ }
+
+ /* if YUY2 and dimensions changed, we need to re-allocate the
+ * internal YV12 buffer */
+ if (frame->vo_frame.format == XINE_IMGFMT_YUY2) {
+ int image_size = frame->vo_frame.pitches[0] * frame->oheight;
+
+ this->out[0] = xine_xmalloc_aligned(16, image_size * 3/2,
+ (void *)&this->buf);
+ this->out[1] = this->out[0] + image_size;
+ this->out[2] = this->out[1] + image_size/4;
+
+ /* fill with black (yuv 16,128,128) */
+ memset(this->out[0], 16, image_size);
+ memset(this->out[1], 128, image_size/4);
+ memset(this->out[2], 128, image_size/4);
+ lprintf("Using YUY2->YV12 conversion\n");
+ }
+
+ /* resolution must be a multiple of two */
+ if ((frame->vo_frame.pitches[0] % 2 != 0) || (frame->oheight % 2 != 0)) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: lavc only handles video dimensions which are multiples of 2\n");
+ return 0;
+ }
+
+ /* get mpeg codec handle */
+ codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
+ if (!codec) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: lavc MPEG1 codec not found\n");
+ return 0;
+ }
+ lprintf("lavc MPEG1 encoder found.\n");
+
+ this->width = frame->vo_frame.pitches[0];
+ this->height = frame->oheight;
+
+ this->context = avcodec_alloc_context();
+ if (!this->context) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: Couldn't start the ffmpeg library\n");
+ return 0;
+ }
+ this->picture = avcodec_alloc_frame();
+ if (!this->picture) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: Couldn't allocate ffmpeg frame\n");
+ return 0;
+ }
+
+ /* mpeg1 encoder only support YUV420P */
+ this->context->pix_fmt = PIX_FMT_YUVJ420P;
+
+ /* put sample parameters */
+ this->context->bit_rate = drv->class->xine->config->register_range(drv->class->xine->config,
+ "dxr3.encoding.lavc_bitrate", 10000, 1000, 20000,
+ _("libavcodec mpeg output bitrate (kbit/s)"),
+ _("The bitrate the libavcodec mpeg encoder should use for DXR3's encoding mode. "
+ "Higher values will increase quality and CPU usage.\n"
+ "This setting is only considered, when constant quality mode is disabled."), 10, NULL, NULL);
+ this->context->bit_rate *= 1000; /* config in kbit/s, libavcodec wants bit/s */
+
+ use_quantizer = drv->class->xine->config->register_bool(drv->class->xine->config,
+ "dxr3.encoding.lavc_quantizer", 1,
+ _("constant quality mode"),
+ _("When enabled, libavcodec will use a constant quality mode by dynamically "
+ "compressing the images based on their complexity. When disabled, libavcodec "
+ "will use constant bitrate mode."), 10, NULL, NULL);
+
+ if (use_quantizer) {
+ this->context->qmin = drv->class->xine->config->register_range(drv->class->xine->config,
+ "dxr3.encoding.lavc_qmin", 1, 1, 10,
+ _("minimum compression"),
+ _("The minimum compression to apply to an image in constant quality mode."),
+ 10, NULL, NULL);
+
+ this->context->qmax = drv->class->xine->config->register_range(drv->class->xine->config,
+ "dxr3.encoding.lavc_qmax", 2, 1, 20,
+ _("maximum quantizer"),
+ _("The maximum compression to apply to an image in constant quality mode."),
+ 10, NULL, NULL);
+ }
+
+ lprintf("lavc -> bitrate %d \n", this->context->bit_rate);
+
+ this->context->width = frame->vo_frame.pitches[0];
+ this->context->height = frame->oheight;
+
+ this->context->gop_size = 0; /*intra frames only */
+ this->context->me_method = ME_ZERO; /*motion estimation type*/
+
+ this->context->time_base.den = 90000;
+ if (frame->vo_frame.duration > 90000 / 24)
+ this->context->time_base.num = 90000 / 24;
+ else if (frame->vo_frame.duration < 90000 / 60)
+ this->context->time_base.num = 90000 / 60;
+ else
+ this->context->time_base.num = frame->vo_frame.duration;
+ /* ffmpeg can complain about illegal framerates, but since this seems no
+ * problem for the DXR3, we just tell ffmpeg to be more lax with */
+ this->context->strict_std_compliance = -1;
+
+ /* open avcodec */
+ if (avcodec_open(this->context, codec) < 0) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG, "dxr3_mpeg_encoder: could not open codec\n");
+ return 0;
+ }
+ lprintf("dxr3_mpeg_encoder: lavc MPEG1 codec opened.\n");
+
+ if (!this->ffmpeg_buffer)
+ this->ffmpeg_buffer = (unsigned char *)malloc(DEFAULT_BUFFER_SIZE); /* why allocate more than needed ?! */
+ if (!this->ffmpeg_buffer) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: Couldn't allocate temp buffer for mpeg data\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int lavc_on_display_frame(dxr3_driver_t *drv, dxr3_frame_t *frame)
+{
+ int size;
+ lavc_data_t* this = (lavc_data_t *)drv->enc;
+ ssize_t written;
+
+ if (frame->vo_frame.bad_frame) return 1;
+ /* ignore old frames */
+ if ((frame->vo_frame.pitches[0] != this->context->width) || (frame->oheight != this->context->height)) {
+ frame->vo_frame.free(&frame->vo_frame);
+ lprintf("LAVC ignoring frame !!!\n");
+ return 1;
+ }
+
+ /* prepare frame for conversion, handles YUY2 -> YV12 conversion when necessary */
+ lavc_prepare_frame(this, drv, frame);
+
+ /* do the encoding */
+ size = avcodec_encode_video(this->context, this->ffmpeg_buffer, DEFAULT_BUFFER_SIZE, this->picture);
+
+ frame->vo_frame.free(&frame->vo_frame);
+
+ if (size < 0) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: encoding failed\n");
+ return 0;
+ }
+
+ written = write(drv->fd_video, this->ffmpeg_buffer, size);
+ if (written < 0) {
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: video device write failed (%s)\n", strerror(errno));
+ return 0;
+ }
+ if (written != size)
+ xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
+ "dxr3_mpeg_encoder: Could only write %zd of %d mpeg bytes.\n", written, size);
+ return 1;
+}
+
+static int lavc_on_unneeded(dxr3_driver_t *drv)
+{
+ lavc_data_t *this = (lavc_data_t *)drv->enc;
+ lprintf("flushing buffers\n");
+ if (this->context) {
+ avcodec_close(this->context);
+ free(this->context);
+ free(this->picture);
+ this->context = NULL;
+ this->picture = NULL;
+ }
+ return 1;
+}
+
+static int lavc_prepare_frame(lavc_data_t *this, dxr3_driver_t *drv, dxr3_frame_t *frame)
+{
+ int i, j, w2;
+ uint8_t *yuy2;
+
+ if (frame->vo_frame.bad_frame) return 1;
+
+ if (frame->vo_frame.format == XINE_IMGFMT_YUY2) {
+ /* need YUY2->YV12 conversion */
+ if (!(this->out[0] && this->out[1] && this->out[2]) ) {
+ lprintf("Internal YV12 buffer not created.\n");
+ return 0;
+ }
+ this->picture->data[0] = this->out[0] + frame->vo_frame.pitches[0] * drv->top_bar; /* y */
+ this->picture->data[1] = this->out[1] + (frame->vo_frame.pitches[0] / 2) * (drv->top_bar / 2); /* u */
+ this->picture->data[2] = this->out[2] + (frame->vo_frame.pitches[0] / 2) * (drv->top_bar / 2); /* v */
+ yuy2 = frame->vo_frame.base[0];
+ w2 = frame->vo_frame.pitches[0] / 2;
+ for (i = 0; i < frame->vo_frame.height; i += 2) {
+ for (j = 0; j < w2; j++) {
+ /* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
+ *(this->picture->data[0]++) = *(yuy2++);
+ *(this->picture->data[1]++) = *(yuy2++);
+ *(this->picture->data[0]++) = *(yuy2++);
+ *(this->picture->data[2]++) = *(yuy2++);
+ }
+ /* down sampling */
+ for (j = 0; j < w2; j++) {
+ /* skip every second line for U and V */
+ *(this->picture->data[0]++) = *(yuy2++);
+ yuy2++;
+ *(this->picture->data[0]++) = *(yuy2++);
+ yuy2++;
+ }
+ }
+ /* reset for encoder */
+ this->picture->data[0] = this->out[0];
+ this->picture->data[1] = this->out[1];
+ this->picture->data[2] = this->out[2];
+ }
+ else { /* YV12 **/
+ this->picture->data[0] = frame->real_base[0];
+ this->picture->data[1] = frame->real_base[1];
+ this->picture->data[2] = frame->real_base[2];
+ }
+ this->picture->linesize[0] = this->context->width;
+ this->picture->linesize[1] = this->context->width / 2;
+ this->picture->linesize[2] = this->context->width / 2;
+ return 1;
+}
diff --git a/src/combined/decoder_flac.c b/src/combined/flac_decoder.c
index 2230056cd..43bad327e 100644
--- a/src/combined/decoder_flac.c
+++ b/src/combined/flac_decoder.c
@@ -44,11 +44,9 @@
#define LOG
*/
-#include "xine_internal.h"
-#include "audio_out.h"
-#include "buffer.h"
-
-#include "demux_flac.h"
+#include <xine/xine_internal.h>
+#include <xine/audio_out.h>
+#include <xine/buffer.h>
typedef struct {
audio_decoder_class_t decoder_class;
@@ -59,23 +57,17 @@ typedef struct flac_decoder_s {
int64_t pts;
- int output_sampling_rate;
- int output_open;
- int output_mode;
-
xine_stream_t *stream;
FLAC__StreamDecoder *flac_decoder;
- int sample_rate;
- int bits_per_sample;
- int channels;
-
unsigned char *buf;
int buf_size;
int buf_pos;
int min_size;
+ int output_open;
+
} flac_decoder_t;
/*
@@ -249,21 +241,18 @@ flac_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)
*/
if (buf->decoder_flags & BUF_FLAG_STDHEADER)
{
- int mode = AO_CAP_MODE_MONO;
-
- this->sample_rate = buf->decoder_info[1];
- this->bits_per_sample = buf->decoder_info[2];
- this->channels = buf->decoder_info[3];
-
- mode = _x_ao_channels2mode(this->channels);
+ const int sample_rate = buf->decoder_info[1];
+ const int bits_per_sample = buf->decoder_info[2];
+ const int channels = buf->decoder_info[3];
+ const int mode = _x_ao_channels2mode(channels);
if (!this->output_open)
{
this->output_open = (this->stream->audio_out->open) (
this->stream->audio_out,
this->stream,
- this->bits_per_sample,
- this->sample_rate,
+ bits_per_sample,
+ sample_rate,
mode);
@@ -390,19 +379,6 @@ open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {
/*
* flac plugin class
*/
-
-static char *get_identifier (audio_decoder_class_t *this) {
- return "flacdec";
-}
-
-static char *get_description (audio_decoder_class_t *this) {
- return "flac audio decoder plugin";
-}
-
-static void dispose_class (audio_decoder_class_t *this) {
- free (this);
-}
-
static void *
init_plugin (xine_t *xine, void *data) {
flac_class_t *this;
@@ -410,15 +386,17 @@ init_plugin (xine_t *xine, void *data) {
this = (flac_class_t *) xine_xmalloc (sizeof (flac_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;
+ this->decoder_class.identifier = "flacdec";
+ this->decoder_class.description = N_("flac audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
return this;
}
-static uint32_t audio_types[] = {
+void *demux_flac_init_class (xine_t *xine, void *data);
+
+static const uint32_t audio_types[] = {
BUF_AUDIO_FLAC, 0
};
@@ -429,7 +407,7 @@ static const decoder_info_t dec_info_audio = {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 26, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
- { PLUGIN_AUDIO_DECODER, 15, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin },
+ { PLUGIN_DEMUX, 27, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
+ { PLUGIN_AUDIO_DECODER, 16, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
diff --git a/src/combined/demux_flac.c b/src/combined/flac_demuxer.c
index fdc7ab7ea..22ee2319b 100644
--- a/src/combined/demux_flac.c
+++ b/src/combined/flac_demuxer.c
@@ -51,11 +51,9 @@
#define LOG
*/
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "../demuxers/demux.h"
-
-#include "demux_flac.h"
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/demux.h>
#ifndef LEGACY_FLAC
# define FLAC__SeekableStreamDecoder FLAC__StreamDecoder
@@ -582,20 +580,7 @@ open_plugin (demux_class_t *class_gen,
return NULL;
}
break;
- case METHOD_BY_EXTENSION: {
- char *ending, *mrl;
-
- mrl = input->get_mrl (input);
-
- ending = strrchr (mrl, '.');
-
- if (!ending || (strlen (ending) < 5))
- return NULL;
-
- if (strncasecmp (ending, ".flac", 5))
- return NULL;
- }
- break;
+ case METHOD_BY_MRL:
case METHOD_EXPLICIT:
break;
default:
@@ -714,37 +699,6 @@ open_plugin (demux_class_t *class_gen,
/* FLAC Demuxer class */
-
-static char *
-get_description (demux_class_t *this_gen) {
- return "FLAC demux plugin";
-}
-
-static char *
-get_identifier (demux_class_t *this_gen) {
- return "FLAC";
-}
-
-static char *
-get_extensions (demux_class_t *this_gen) {
- return "flac";
-}
-
-static char *
-get_mimetypes (demux_class_t *this_gen) {
- return "audio/x-flac: flac: FLAC Audio;"
- "audio/flac: flac: FLAC Audio;";
-}
-
-static void
-class_dispose (demux_class_t *this_gen) {
- demux_flac_class_t *this = (demux_flac_class_t *) this_gen;
-
- lprintf("class_dispose\n");
-
- free (this);
-}
-
void *
demux_flac_init_class (xine_t *xine, void *data) {
@@ -757,11 +711,12 @@ demux_flac_init_class (xine_t *xine, void *data) {
this->xine = xine;
this->demux_class.open_plugin = open_plugin;
- this->demux_class.get_description = get_description;
- this->demux_class.get_identifier = get_identifier;
- this->demux_class.get_mimetypes = get_mimetypes;
- this->demux_class.get_extensions = get_extensions;
- this->demux_class.dispose = class_dispose;
+ this->demux_class.description = N_("FLAC demux plugin");
+ this->demux_class.identifier = "FLAC";
+ this->demux_class.mimetypes = "application/x-flac: flac: FLAC Audio;"
+ "application/flac: flac: FLAC Audio;";
+ this->demux_class.extensions = "flac";
+ this->demux_class.dispose = default_demux_class_dispose;
return this;
}
diff --git a/src/combined/nsf_combined.c b/src/combined/nsf_combined.c
new file mode 100644
index 000000000..0364e2db2
--- /dev/null
+++ b/src/combined/nsf_combined.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ */
+
+#include <xine/xine_internal.h>
+#include "nsf_combined.h"
+
+static const demuxer_info_t demux_info_nsf = {
+ 10 /* priority */
+};
+
+static const uint32_t audio_types[] = {
+ BUF_AUDIO_NSF,
+ 0
+};
+
+static const decoder_info_t decoder_info_nsf = {
+ audio_types, /* supported types */
+ 5 /* priority */
+};
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ { PLUGIN_DEMUX, 27, "nsfdemux", XINE_VERSION_CODE, &demux_info_nsf, demux_nsf_init_plugin },
+ { PLUGIN_AUDIO_DECODER, 16, "nsfdec", XINE_VERSION_CODE, &decoder_info_nsf, decoder_nsf_init_plugin },
+ { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
+};
diff --git a/src/combined/demux_flac.h b/src/combined/nsf_combined.h
index a48c73260..4376ecf7a 100644
--- a/src/combined/demux_flac.h
+++ b/src/combined/nsf_combined.h
@@ -1,26 +1,22 @@
-/*
- * Copyright (C) 2000-2003 the xine project
- *
+/*
+ * Copyright (C) 2000-2001 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
-#ifndef HAVE_DEMUX_FLAC_H
-#define HAVE_DEMUX_FLAC_H
-
-void *demux_flac_init_class (xine_t *xine, void *data);
-
-#endif
+void *decoder_nsf_init_plugin (xine_t *xine, void *data);
+void *demux_nsf_init_plugin (xine_t *xine, void *data);
diff --git a/src/combined/nsf_decoder.c b/src/combined/nsf_decoder.c
new file mode 100644
index 000000000..cb3b6e7b0
--- /dev/null
+++ b/src/combined/nsf_decoder.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2000-2001 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * NSF Audio "Decoder" using the Nosefart NSF engine by Matt Conte
+ * http://www.baisoku.org/
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <xine/xine_internal.h>
+#include <xine/audio_out.h>
+#include <xine/buffer.h>
+#include <xine/xineutils.h>
+#include "bswap.h"
+
+/* Nosefart includes */
+#include "types.h"
+#include "nsf.h"
+
+#include "nsf_combined.h"
+
+typedef struct {
+ audio_decoder_class_t decoder_class;
+} nsf_class_t;
+
+typedef struct nsf_decoder_s {
+ audio_decoder_t audio_decoder;
+
+ xine_stream_t *stream;
+
+ int sample_rate; /* audio sample rate */
+ int bits_per_sample; /* bits/sample, usually 8 or 16 */
+ int channels; /* 1 or 2, usually */
+
+ int output_open; /* flag to indicate audio is ready */
+
+ int nsf_size;
+ unsigned char *nsf_file;
+ int nsf_index;
+ int song_number;
+
+ /* nsf-specific variables */
+ int64_t last_pts;
+ unsigned int iteration;
+
+ nsf_t *nsf;
+} nsf_decoder_t;
+
+/**************************************************************************
+ * xine audio plugin functions
+ *************************************************************************/
+
+static void nsf_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
+
+ nsf_decoder_t *this = (nsf_decoder_t *) this_gen;
+ audio_buffer_t *audio_buffer;
+
+ if (buf->decoder_flags & BUF_FLAG_HEADER) {
+
+ /* When the engine sends a BUF_FLAG_HEADER flag, it is time to initialize
+ * the decoder. The buffer element type has 4 decoder_info fields,
+ * 0..3. Field 1 is the sample rate. Field 2 is the bits/sample. Field
+ * 3 is the number of channels. */
+ this->sample_rate = buf->decoder_info[1];
+ this->bits_per_sample = buf->decoder_info[2];
+ this->channels = buf->decoder_info[3];
+
+ /* take this opportunity to initialize stream/meta information */
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC,
+ "NES Music (Nosefart)");
+
+ this->song_number = buf->content[4];
+ /* allocate a buffer for the file */
+ this->nsf_size = _X_BE_32(&buf->content[0]);
+ this->nsf_file = xine_xmalloc(this->nsf_size);
+ this->nsf_index = 0;
+
+ /* peform any other required initialization */
+ this->last_pts = -1;
+ this->iteration = 0;
+
+ return;
+ }
+
+ /* accumulate chunks from the NSF file until whole file is received */
+ if (this->nsf_index < this->nsf_size) {
+ xine_fast_memcpy(&this->nsf_file[this->nsf_index], buf->content,
+ buf->size);
+ this->nsf_index += buf->size;
+
+ if (this->nsf_index == this->nsf_size) {
+ /* file has been received, proceed to initialize engine */
+ nsf_init();
+ this->nsf = nsf_load(NULL, this->nsf_file, this->nsf_size);
+ if (!this->nsf) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "nsf: could not initialize NSF\n");
+ /* make the decoder return on every subsequent buffer */
+ this->nsf_index = 0;
+ return;
+ }
+ this->nsf->current_song = this->song_number;
+ nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate,
+ this->bits_per_sample, this->channels);
+ }
+ return;
+ }
+
+ /* if the audio output is not open yet, open the audio output */
+ if (!this->output_open) {
+ this->output_open = (this->stream->audio_out->open) (
+ this->stream->audio_out,
+ this->stream,
+ this->bits_per_sample,
+ this->sample_rate,
+ _x_ao_channels2mode(this->channels));
+ }
+
+ /* if the audio still isn't open, do not go any further with the decode */
+ if (!this->output_open)
+ return;
+
+ /* check if a song change was requested */
+ if (buf->decoder_info[1]) {
+ this->nsf->current_song = buf->decoder_info[1];
+ nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate,
+ this->bits_per_sample, this->channels);
+ }
+
+ /* time to decode a frame */
+ if (this->last_pts != -1) {
+
+ /* process a frame */
+ nsf_frame(this->nsf);
+
+ /* get an audio buffer */
+ audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out);
+ if (audio_buffer->mem_size == 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "nsf: Help! Allocated audio buffer with nothing in it!\n");
+ return;
+ }
+
+ apu_process(audio_buffer->mem, this->sample_rate / this->nsf->playback_rate);
+ audio_buffer->vpts = buf->pts;
+ audio_buffer->num_frames = this->sample_rate / this->nsf->playback_rate;
+ this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream);
+ }
+ this->last_pts = buf->pts;
+}
+
+/* This function resets the state of the audio decoder. This usually
+ * entails resetting the data accumulation buffer. */
+static void nsf_reset (audio_decoder_t *this_gen) {
+
+ nsf_decoder_t *this = (nsf_decoder_t *) this_gen;
+
+ this->last_pts = -1;
+}
+
+/* This function resets the last pts value of the audio decoder. */
+static void nsf_discontinuity (audio_decoder_t *this_gen) {
+
+ nsf_decoder_t *this = (nsf_decoder_t *) this_gen;
+
+ this->last_pts = -1;
+}
+
+/* This function closes the audio output and frees the private audio decoder
+ * structure. */
+static void nsf_dispose (audio_decoder_t *this_gen) {
+
+ nsf_decoder_t *this = (nsf_decoder_t *) this_gen;
+
+ /* close the audio output */
+ if (this->output_open)
+ this->stream->audio_out->close (this->stream->audio_out, this->stream);
+ this->output_open = 0;
+
+ /* free anything that was allocated during operation */
+ nsf_free(&this->nsf);
+ free(this->nsf_file);
+ free(this);
+}
+
+/* This function allocates, initializes, and returns a private audio
+ * decoder structure. */
+static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ nsf_decoder_t *this ;
+
+ this = (nsf_decoder_t *) xine_xmalloc (sizeof (nsf_decoder_t));
+
+ /* connect the member functions */
+ this->audio_decoder.decode_data = nsf_decode_data;
+ this->audio_decoder.reset = nsf_reset;
+ this->audio_decoder.discontinuity = nsf_discontinuity;
+ this->audio_decoder.dispose = nsf_dispose;
+
+ /* connect the stream */
+ this->stream = stream;
+
+ /* audio output is not open at the start */
+ this->output_open = 0;
+
+ /* initialize the basic audio parameters */
+ this->channels = 0;
+ this->sample_rate = 0;
+ this->bits_per_sample = 0;
+
+ /* return the newly-initialized audio decoder */
+ return &this->audio_decoder;
+}
+
+/* This function allocates a private audio decoder class and initializes
+ * the class's member functions. */
+void *decoder_nsf_init_plugin (xine_t *xine, void *data) {
+
+ nsf_class_t *this ;
+
+ this = (nsf_class_t *) xine_xmalloc (sizeof (nsf_class_t));
+
+ this->decoder_class.open_plugin = open_plugin;
+ this->decoder_class.identifier = "NSF";
+ this->decoder_class.description = N_("NES Music audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
+
+ return this;
+}
diff --git a/src/combined/nsf_demuxer.c b/src/combined/nsf_demuxer.c
new file mode 100644
index 000000000..451e6e938
--- /dev/null
+++ b/src/combined/nsf_demuxer.c
@@ -0,0 +1,353 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ */
+
+/*
+ * NSF File "Demuxer" by Mike Melanson (melanson@pcisys.net)
+ * This is really just a loader for NES Music File Format (extension NSF)
+ * which loads an entire NSF file and passes it over to the NSF audio
+ * decoder.
+ *
+ * After the file is sent over, the demuxer controls the playback by
+ * sending empty buffers with incrementing pts values.
+ *
+ * For more information regarding the NSF format, visit:
+ * http://www.tripoint.org/kevtris/nes/nsfspec.txt
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+/********** logging **********/
+#define LOG_MODULE "demux_nsf"
+/* #define LOG_VERBOSE */
+/* #define LOG */
+
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/compat.h>
+#include <xine/demux.h>
+#include "bswap.h"
+
+#include "nsf_combined.h"
+
+#define NSF_HEADER_SIZE 0x80
+#define NSF_SAMPLERATE 44100
+#define NSF_BITS 8
+#define NSF_CHANNELS 1
+#define NSF_REFRESH_RATE 60
+#define NSF_PTS_INC (90000 / NSF_REFRESH_RATE)
+
+typedef struct {
+ demux_plugin_t demux_plugin;
+
+ xine_stream_t *stream;
+ fifo_buffer_t *video_fifo;
+ fifo_buffer_t *audio_fifo;
+ input_plugin_t *input;
+ int status;
+
+ int total_songs;
+ int current_song;
+ int new_song; /* indicates song change */
+
+ char *title;
+ char *artist;
+ char *copyright;
+
+ off_t filesize;
+
+ int64_t current_pts;
+ int file_sent;
+} demux_nsf_t;
+
+typedef struct {
+ demux_class_t demux_class;
+} demux_nsf_class_t;
+
+/* returns 1 if the NSF file was opened successfully, 0 otherwise */
+static int open_nsf_file(demux_nsf_t *this) {
+ unsigned char header[NSF_HEADER_SIZE];
+
+ this->input->seek(this->input, 0, SEEK_SET);
+ if (this->input->read(this->input, header, NSF_HEADER_SIZE) !=
+ NSF_HEADER_SIZE)
+ return 0;
+
+ /* check for the signature */
+ if ( memcmp(header, "NESM\x1A", 5) != 0 )
+ return 0;
+
+ this->total_songs = header[6];
+ this->current_song = header[7];
+ this->title = strndup((char*)&header[0x0E], 0x20);
+ this->artist = strndup((char*)&header[0x2E], 0x20);
+ this->copyright = strndup((char*)&header[0x4E], 0x20);
+
+ this->filesize = this->input->get_length(this->input);
+
+ return 1;
+}
+
+static int demux_nsf_send_chunk(demux_plugin_t *this_gen) {
+ demux_nsf_t *this = (demux_nsf_t *) this_gen;
+ buf_element_t *buf;
+ int bytes_read;
+ char title[100];
+
+ /* send chunks of the file to the decoder until file is completely
+ * loaded; then send control buffers */
+ if (!this->file_sent) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_AUDIO_NSF;
+ bytes_read = this->input->read(this->input, buf->content, buf->max_size);
+
+ if (bytes_read == 0) {
+ /* the file has been completely loaded, free the buffer and start
+ * sending control buffers */
+ buf->free_buffer(buf);
+ this->file_sent = 1;
+
+ } else {
+
+ /* keep loading the file */
+ if (bytes_read < buf->max_size)
+ buf->size = bytes_read;
+ else
+ buf->size = buf->max_size;
+
+ buf->extra_info->input_normpos = 0;
+ buf->extra_info->input_time = 0;
+ buf->pts = 0;
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+ }
+
+ /* this is not an 'else' because control might fall through from above */
+ if (this->file_sent) {
+ /* send a control buffer */
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+
+ if (this->new_song) {
+
+ buf->decoder_info[1] = this->current_song;
+ this->new_song = 0;
+ sprintf(title, "%s, song %d/%d",
+ this->title, this->current_song, this->total_songs);
+
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title);
+
+ _x_demux_control_newpts(this->stream, this->current_pts, 0);
+
+ } else
+ buf->decoder_info[1] = 0;
+
+ buf->type = BUF_AUDIO_NSF;
+ if(this->total_songs)
+ buf->extra_info->input_normpos = (this->current_song - 1) * 65535 / this->total_songs;
+ buf->extra_info->input_time = this->current_pts / 90;
+ buf->pts = this->current_pts;
+ buf->size = 0;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ this->current_pts += NSF_PTS_INC;
+ }
+
+ return this->status;
+}
+
+static void demux_nsf_send_headers(demux_plugin_t *this_gen) {
+ demux_nsf_t *this = (demux_nsf_t *) this_gen;
+ buf_element_t *buf;
+ char copyright[100];
+
+ this->video_fifo = this->stream->video_fifo;
+ this->audio_fifo = this->stream->audio_fifo;
+
+ this->status = DEMUX_OK;
+
+ /* load stream information */
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 0);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS,
+ NSF_CHANNELS);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE,
+ NSF_SAMPLERATE);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS,
+ NSF_BITS);
+
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title);
+ _x_meta_info_set(this->stream, XINE_META_INFO_ARTIST, this->artist);
+ sprintf(copyright, "(C) %s", this->copyright);
+ _x_meta_info_set(this->stream, XINE_META_INFO_COMMENT, copyright);
+
+ /* send start buffers */
+ _x_demux_control_start(this->stream);
+
+ /* send init info to the audio decoder */
+ if (this->audio_fifo) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_AUDIO_NSF;
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END;
+ buf->decoder_info[0] = 5;
+ buf->decoder_info[1] = NSF_SAMPLERATE;
+ buf->decoder_info[2] = NSF_BITS;
+ buf->decoder_info[3] = NSF_CHANNELS;
+
+ /* send the NSF filesize in the body, big endian format */
+ buf->content[0] = (this->filesize >> 24) & 0xFF;
+ buf->content[1] = (this->filesize >> 16) & 0xFF;
+ buf->content[2] = (this->filesize >> 8) & 0xFF;
+ buf->content[3] = (this->filesize >> 0) & 0xFF;
+ /* send the requested song */
+ buf->content[4] = this->current_song + 5;
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+}
+
+static int demux_nsf_seek (demux_plugin_t *this_gen,
+ off_t start_pos, int start_time, int playing) {
+
+ demux_nsf_t *this = (demux_nsf_t *) this_gen;
+ start_pos = (off_t) ( (double) start_pos / 65535 *
+ this->total_songs );
+
+ /* if thread is not running, initialize demuxer */
+ if( !playing ) {
+
+ /* send new pts */
+ _x_demux_control_newpts(this->stream, 0, 0);
+
+ this->status = DEMUX_OK;
+
+ /* reposition stream at the start for loading */
+ this->input->seek(this->input, 0, SEEK_SET);
+
+ this->file_sent = 0;
+ this->current_pts = 0;
+ this->new_song = 1;
+ } else {
+ this->current_song = start_pos + 1;
+ this->new_song = 1;
+ this->current_pts = 0;
+ _x_demux_flush_engine(this->stream);
+ }
+
+ return this->status;
+}
+
+static void demux_nsf_dispose (demux_plugin_t *this_gen) {
+ demux_nsf_t *this = (demux_nsf_t *) this_gen;
+
+ free(this->title);
+ free(this->artist);
+ free(this->copyright);
+ free(this);
+}
+
+static int demux_nsf_get_status (demux_plugin_t *this_gen) {
+ demux_nsf_t *this = (demux_nsf_t *) this_gen;
+
+ return this->status;
+}
+
+/* return the approximate length in miliseconds */
+static int demux_nsf_get_stream_length (demux_plugin_t *this_gen) {
+ return 0;
+}
+
+static uint32_t demux_nsf_get_capabilities(demux_plugin_t *this_gen) {
+ return DEMUX_CAP_NOCAP;
+}
+
+static int demux_nsf_get_optional_data(demux_plugin_t *this_gen,
+ void *data, int data_type) {
+ return DEMUX_OPTIONAL_UNSUPPORTED;
+}
+
+static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream,
+ input_plugin_t *input) {
+
+ demux_nsf_t *this;
+
+ if (!INPUT_IS_SEEKABLE(input)) {
+ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "input not seekable, can not handle!\n");
+ return NULL;
+ }
+
+ this = xine_xmalloc (sizeof (demux_nsf_t));
+ this->stream = stream;
+ this->input = input;
+
+ this->demux_plugin.send_headers = demux_nsf_send_headers;
+ this->demux_plugin.send_chunk = demux_nsf_send_chunk;
+ this->demux_plugin.seek = demux_nsf_seek;
+ this->demux_plugin.dispose = demux_nsf_dispose;
+ this->demux_plugin.get_status = demux_nsf_get_status;
+ this->demux_plugin.get_stream_length = demux_nsf_get_stream_length;
+ this->demux_plugin.get_capabilities = demux_nsf_get_capabilities;
+ this->demux_plugin.get_optional_data = demux_nsf_get_optional_data;
+ this->demux_plugin.demux_class = class_gen;
+
+ this->status = DEMUX_FINISHED;
+
+ switch (stream->content_detection_method) {
+
+ case METHOD_BY_MRL:
+ case METHOD_BY_CONTENT:
+ case METHOD_EXPLICIT:
+
+ if (!open_nsf_file(this)) {
+ free (this);
+ return NULL;
+ }
+
+ break;
+
+ default:
+ free (this);
+ return NULL;
+ }
+
+ return &this->demux_plugin;
+}
+
+void *demux_nsf_init_plugin (xine_t *xine, void *data) {
+ demux_nsf_class_t *this;
+
+ this = xine_xmalloc (sizeof (demux_nsf_class_t));
+
+ this->demux_class.open_plugin = open_plugin;
+ this->demux_class.description = N_("NES Music file demux plugin");
+ this->demux_class.identifier = "NSF";
+ this->demux_class.mimetypes = NULL;
+ this->demux_class.extensions = "nsf";
+ this->demux_class.dispose = default_demux_class_dispose;
+
+ return this;
+}
diff --git a/src/combined/combined_wavpack.c b/src/combined/wavpack_combined.c
index 893ee99be..8a4b488ae 100644
--- a/src/combined/combined_wavpack.c
+++ b/src/combined/wavpack_combined.c
@@ -20,14 +20,14 @@
* xine interface to libwavpack by Diego Pettenò <flameeyes@gmail.com>
*/
-#include "xine_internal.h"
-#include "combined_wavpack.h"
+#include <xine/xine_internal.h>
+#include "wavpack_combined.h"
static const demuxer_info_t demux_info_wv = {
0 /* priority */
};
-static uint32_t audio_types[] = {
+static const uint32_t audio_types[] = {
BUF_AUDIO_WAVPACK, 0
};
@@ -38,7 +38,7 @@ static const decoder_info_t decoder_info_wv = {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 26, "wavpack", XINE_VERSION_CODE, &demux_info_wv, demux_wv_init_plugin },
- { PLUGIN_AUDIO_DECODER, 15, "wavpackdec", XINE_VERSION_CODE, &decoder_info_wv, decoder_wavpack_init_plugin },
+ { PLUGIN_DEMUX, 27, "wavpack", XINE_VERSION_CODE, &demux_info_wv, demux_wv_init_plugin },
+ { PLUGIN_AUDIO_DECODER, 16, "wavpackdec", XINE_VERSION_CODE, &decoder_info_wv, decoder_wavpack_init_plugin },
{ PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
};
diff --git a/src/combined/combined_wavpack.h b/src/combined/wavpack_combined.h
index 61a504a4f..42b0bfd51 100644
--- a/src/combined/combined_wavpack.h
+++ b/src/combined/wavpack_combined.h
@@ -20,7 +20,8 @@
* xine interface to libwavpack by Diego Pettenò <flameeyes@gmail.com>
*/
-#include "os_types.h"
+#include <xine/os_types.h>
+#include "bswap.h"
typedef struct {
uint32_t idcode; /* This should always be the string "wvpk" */
@@ -35,13 +36,9 @@ typedef struct {
uint32_t samples_count; /* Count of samples in the current frame */
uint32_t flags; /* Misc flags */
uint32_t decoded_crc32; /* CRC32 of the decoded data */
-} __attribute__((packed)) wvheader_t;
+} XINE_PACKED wvheader_t;
-#ifdef WORDS_BIGENDIAN
-static const uint32_t wvpk_signature = ('k' + ('p' << 8) + ('v' << 16) + ('w' << 24));
-#else
-static const uint32_t wvpk_signature = ('w' + ('v' << 8) + ('p' << 16) + ('k' << 24));
-#endif
+static const uint32_t wvpk_signature = ME_FOURCC('w', 'v', 'p', 'k');
void *demux_wv_init_plugin (xine_t *const xine, void *const data);
void *decoder_wavpack_init_plugin (xine_t *xine, void *data);
diff --git a/src/combined/decoder_wavpack.c b/src/combined/wavpack_decoder.c
index f8a301c9f..80a14e678 100644
--- a/src/combined/decoder_wavpack.c
+++ b/src/combined/wavpack_decoder.c
@@ -27,12 +27,12 @@
#define LOG_MODULE "decode_wavpack"
#define LOG_VERBOSE
-#include "xine_internal.h"
-#include "attributes.h"
+#include <xine/xine_internal.h>
+#include <xine/attributes.h>
#include "bswap.h"
#include <wavpack/wavpack.h>
-#include "combined_wavpack.h"
+#include "wavpack_combined.h"
typedef struct {
audio_decoder_class_t decoder_class;
@@ -102,6 +102,8 @@ static int xine_buffer_set_pos_rel(void *const this_gen, const int32_t delta,
return 0;
}
+
+ return -1;
}
static int xine_buffer_set_pos_abs(void *const this_gen, const uint32_t pos) {
@@ -309,27 +311,15 @@ static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stre
* wavpack plugin class
*/
-static char *get_identifier (audio_decoder_class_t *this) {
- return "wavpackdec";
-}
-
-static char *get_description (audio_decoder_class_t *this) {
- return "wavpack audio decoder plugin";
-}
-
-static void dispose_class (audio_decoder_class_t *this) {
- free (this);
-}
-
void *decoder_wavpack_init_plugin (xine_t *xine, void *data) {
wavpack_class_t *this;
this = (wavpack_class_t *) xine_xmalloc (sizeof (wavpack_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;
+ this->decoder_class.identifier = "wavpackdec";
+ this->decoder_class.description = N_("wavpack audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
return this;
}
diff --git a/src/combined/demux_wavpack.c b/src/combined/wavpack_demuxer.c
index a79f70627..403d136d1 100644
--- a/src/combined/demux_wavpack.c
+++ b/src/combined/wavpack_demuxer.c
@@ -28,14 +28,14 @@
#define LOG_VERBOSE
#define LOG
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "demux.h"
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/demux.h>
#include "bswap.h"
-#include "attributes.h"
+#include <xine/attributes.h>
#include <wavpack/wavpack.h>
-#include "combined_wavpack.h"
+#include "wavpack_combined.h"
typedef struct {
demux_plugin_t demux_plugin;
@@ -302,12 +302,6 @@ static int demux_wv_seek (demux_plugin_t *this_gen,
return this->status;
}
-static void demux_wv_dispose (demux_plugin_t *const this_gen) {
- demux_wv_t *const this = (demux_wv_t *) this_gen;
-
- free(this);
-}
-
static int demux_wv_get_status (demux_plugin_t *const this_gen) {
const demux_wv_t *const this = (const demux_wv_t *) this_gen;
@@ -339,7 +333,7 @@ static demux_plugin_t *open_plugin (demux_class_t *const class_gen,
this->demux_plugin.send_headers = demux_wv_send_headers;
this->demux_plugin.send_chunk = demux_wv_send_chunk;
this->demux_plugin.seek = demux_wv_seek;
- this->demux_plugin.dispose = demux_wv_dispose;
+ this->demux_plugin.dispose = default_demux_plugin_dispose;
this->demux_plugin.get_status = demux_wv_get_status;
this->demux_plugin.get_stream_length = demux_wv_get_stream_length;
this->demux_plugin.get_capabilities = demux_wv_get_capabilities;
@@ -349,17 +343,7 @@ static demux_plugin_t *open_plugin (demux_class_t *const class_gen,
this->status = DEMUX_FINISHED;
switch (stream->content_detection_method) {
- case METHOD_BY_EXTENSION: {
- const char *const mrl = input->get_mrl (input);
- const char *const extensions = class_gen->get_extensions (class_gen);
-
- if (!_x_demux_check_extension (mrl, extensions)) {
- free (this);
- return NULL;
- }
- }
- /* Falling through is intended */
-
+ case METHOD_BY_MRL:
case METHOD_BY_CONTENT:
case METHOD_EXPLICIT:
@@ -378,37 +362,15 @@ static demux_plugin_t *open_plugin (demux_class_t *const class_gen,
return &this->demux_plugin;
}
-static const char *get_description (demux_class_t *const this_gen) {
- return "Wavpack demux plugin";
-}
-
-static const char *get_identifier (demux_class_t *const this_gen) {
- return "Wavpack";
-}
-
-static const char *get_extensions (demux_class_t *const this_gen) {
- return "wv";
-}
-
-static const char *get_mimetypes (demux_class_t *const this_gen) {
- return "audio/x-wavpack";
-}
-
-static void class_dispose (demux_class_t *const this_gen) {
- demux_wv_class_t *const this = (demux_wv_class_t *) this_gen;
-
- free (this);
-}
-
void *demux_wv_init_plugin (xine_t *const xine, void *const data) {
demux_wv_class_t *const this = xine_xmalloc (sizeof (demux_wv_class_t));
this->demux_class.open_plugin = open_plugin;
- this->demux_class.get_description = get_description;
- this->demux_class.get_identifier = get_identifier;
- this->demux_class.get_mimetypes = get_mimetypes;
- this->demux_class.get_extensions = get_extensions;
- this->demux_class.dispose = class_dispose;
+ this->demux_class.description = N_("Wavpack demux plugin");
+ this->demux_class.identifier = "Wavpack";
+ this->demux_class.mimetypes = "audio/x-wavpack";
+ this->demux_class.extensions = "wv";
+ this->demux_class.dispose = default_demux_class_dispose;
return this;
}
diff --git a/src/combined/xine_ogg_demuxer.c b/src/combined/xine_ogg_demuxer.c
new file mode 100644
index 000000000..88fcea08a
--- /dev/null
+++ b/src/combined/xine_ogg_demuxer.c
@@ -0,0 +1,2156 @@
+/*
+ * Copyright (C) 2000-2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ */
+
+/*
+ * demultiplexer for ogg streams
+ */
+/* 2003.02.09 (dilb) update of the handling for audio/video infos for strongarm cpus. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <ogg/ogg.h>
+
+#ifdef HAVE_VORBIS
+#include <vorbis/codec.h>
+#endif
+
+#ifdef HAVE_SPEEX
+#include <speex/speex.h>
+#include <speex/speex_header.h>
+#include <speex/speex_stereo.h>
+#include <speex/speex_callbacks.h>
+#endif
+
+#ifdef HAVE_THEORA
+#include <theora/theora.h>
+#endif
+
+#define LOG_MODULE "demux_ogg"
+#define LOG_VERBOSE
+
+/*
+#define LOG
+*/
+
+#define DEBUG_PACKETS 0
+#define DEBUG_PREVIEWS 0
+#define DEBUG_PTS 0
+#define DEBUG_VIDEO_PACKETS 0
+
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/demux.h>
+#include "bswap.h"
+#include "flacutils.h"
+
+#define CHUNKSIZE 8500
+#define PACKET_TYPE_HEADER 0x01
+#define PACKET_TYPE_COMMENT 0x03
+#define PACKET_TYPE_CODEBOOK 0x05
+#define PACKET_TYPE_BITS 0x07
+#define PACKET_LEN_BITS01 0xc0
+#define PACKET_LEN_BITS2 0x02
+#define PACKET_IS_SYNCPOINT 0x08
+
+#define MAX_STREAMS 32
+
+#define PTS_AUDIO 0
+#define PTS_VIDEO 1
+
+#define WRAP_THRESHOLD 900000
+
+#define SUB_BUFSIZE 1024
+
+typedef struct chapter_entry_s {
+ int64_t start_pts;
+ char *name;
+} chapter_entry_t;
+
+typedef struct chapter_info_s {
+ int current_chapter;
+ int max_chapter;
+ chapter_entry_t *entries;
+} chapter_info_t;
+
+typedef struct stream_info_s {
+ ogg_stream_state oss;
+ uint32_t buf_types;
+ int headers;
+ int64_t header_granulepos;
+ int64_t factor;
+ int64_t quotient;
+ int resync;
+ char *language;
+ /* CMML, Ogg Skeleton stream information */
+ int granuleshift;
+ /* Annodex v2 stream information */
+ int hide_first_header;
+ int delivered_bos;
+ int delivered_eos;
+} stream_info_t;
+
+typedef struct demux_ogg_s {
+ demux_plugin_t demux_plugin;
+
+ xine_stream_t *stream;
+ fifo_buffer_t *audio_fifo;
+ fifo_buffer_t *video_fifo;
+ input_plugin_t *input;
+ int status;
+
+ int frame_duration;
+
+#ifdef HAVE_THEORA
+ theora_info t_info;
+ theora_comment t_comment;
+#endif
+
+ ogg_sync_state oy;
+ ogg_page og;
+
+ int64_t start_pts;
+ int64_t last_pts[2];
+
+ int time_length;
+
+ int num_streams;
+ stream_info_t *si[MAX_STREAMS]; /* stream info */
+
+ int num_audio_streams;
+ int num_video_streams;
+ int unhandled_video_streams;
+ int num_spu_streams;
+
+ off_t avg_bitrate;
+
+ char *title;
+ chapter_info_t *chapter_info;
+ xine_event_queue_t *event_queue;
+
+ uint8_t send_newpts:1;
+ uint8_t buf_flag_seek:1;
+ uint8_t keyframe_needed:1;
+ uint8_t ignore_keyframes:1;
+} demux_ogg_t ;
+
+typedef struct {
+ demux_class_t demux_class;
+} demux_ogg_class_t;
+
+typedef struct {
+ demux_class_t demux_class;
+} demux_anx_class_t;
+
+
+#ifdef HAVE_THEORA
+static int intlog(int num) {
+ int ret=0;
+
+ while(num>0){
+ num=num/2;
+ ret=ret+1;
+ }
+ return(ret);
+}
+#endif
+
+static int get_stream (demux_ogg_t *this, int serno) {
+ /*finds the stream_num, which belongs to a ogg serno*/
+ int i;
+
+ for (i = 0; i<this->num_streams; i++) {
+ if (this->si[i]->oss.serialno == serno) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int new_stream_info (demux_ogg_t *this, const int cur_serno) {
+ int stream_num;
+
+ this->si[this->num_streams] = (stream_info_t *)xine_xmalloc(sizeof(stream_info_t));
+ ogg_stream_init(&this->si[this->num_streams]->oss, cur_serno);
+ stream_num = this->num_streams;
+ this->si[stream_num]->buf_types = 0;
+ this->si[stream_num]->header_granulepos = -1;
+ this->si[stream_num]->headers = 0;
+ this->num_streams++;
+
+ return stream_num;
+}
+
+static int64_t get_pts (demux_ogg_t *this, int stream_num , int64_t granulepos ) {
+ /*calculates an pts from an granulepos*/
+ if (granulepos<0) {
+ if ( this->si[stream_num]->header_granulepos>=0 ) {
+ /*return the smallest valid pts*/
+ return 1;
+ } else
+ return 0;
+ } else if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA ||
+ (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) {
+ int64_t iframe, pframe;
+ int granuleshift;
+ granuleshift = this->si[stream_num]->granuleshift;
+ iframe = granulepos >> granuleshift;
+ pframe = granulepos - (iframe << granuleshift);
+ if (this->si[stream_num]->quotient)
+ return 1+((iframe+pframe) * this->si[stream_num]->factor / this->si[stream_num]->quotient);
+ else
+ return 0;
+ } else if (this->si[stream_num]->quotient)
+ return 1+(granulepos * this->si[stream_num]->factor / this->si[stream_num]->quotient);
+ else
+ return 0;
+}
+
+static int read_ogg_packet (demux_ogg_t *this) {
+ char *buffer;
+ long bytes;
+ long total = 0;
+ while (ogg_sync_pageout(&this->oy,&this->og)!=1) {
+ buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE);
+ bytes = this->input->read(this->input, buffer, CHUNKSIZE);
+ if (bytes == 0) {
+ if (total == 0) {
+ lprintf("read_ogg_packet read nothing\n");
+ return 0;
+ }
+ break;
+ }
+ ogg_sync_wrote(&this->oy, bytes);
+ total += bytes;
+ }
+ return 1;
+}
+
+static void get_stream_length (demux_ogg_t *this) {
+ /*determine the streamlenght and set this->time_length accordingly.
+ ATTENTION:current_pos and oggbuffers will be destroyed by this function,
+ there will be no way to continue playback uninterrupted.
+
+ You have to seek afterwards, because after get_stream_length, the
+ current_position is at the end of the file */
+
+ off_t filelength;
+ int done=0;
+ int stream_num;
+
+ this->time_length=-1;
+
+ if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) {
+ filelength=this->input->get_length(this->input);
+
+ if (filelength!=-1) {
+ if (filelength>70000) {
+ this->demux_plugin.seek(&this->demux_plugin,
+ (off_t) ( (double)(filelength-65536)/filelength*65535), 0, 0);
+ }
+ done=0;
+ while (!done) {
+ if (!read_ogg_packet (this)) {
+ if (this->time_length) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE,
+ ((int64_t) 8000*filelength)/this->time_length);
+ /*this is a fine place to compute avg_bitrate*/
+ this->avg_bitrate= 8000*filelength/this->time_length;
+ }
+ return;
+ }
+ stream_num=get_stream(this, ogg_page_serialno (&this->og) );
+ if (stream_num!=-1) {
+ if (this->time_length < (get_pts(this, stream_num, ogg_page_granulepos(&this->og) / 90)))
+ this->time_length = get_pts(this, stream_num, ogg_page_granulepos(&this->og)) / 90;
+ }
+ }
+ }
+ }
+}
+
+#ifdef HAVE_THEORA
+static void send_ogg_packet (demux_ogg_t *this,
+ fifo_buffer_t *fifo,
+ ogg_packet *op,
+ int64_t pts,
+ uint32_t decoder_flags,
+ int stream_num) {
+
+ buf_element_t *buf;
+
+ int done=0,todo=op->bytes;
+ int op_size = sizeof(ogg_packet);
+
+ while (done<todo) {
+ int offset=0;
+ buf = fifo->buffer_pool_alloc (fifo);
+ buf->decoder_flags = decoder_flags;
+ if (done==0) {
+ memcpy (buf->content, op, op_size);
+ offset=op_size;
+ buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_START;
+ }
+
+ if (done+buf->max_size-offset < todo) {
+ memcpy (buf->content+offset, op->packet+done, buf->max_size-offset);
+ buf->size = buf->max_size;
+ done=done+buf->max_size-offset;
+ } else {
+ memcpy (buf->content+offset , op->packet+done, todo-done);
+ buf->size = todo-done+offset;
+ done=todo;
+ buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_END;
+ }
+
+ buf->pts = pts;
+ if( this->input->get_length (this->input) )
+ buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) *
+ 65535 / this->input->get_length (this->input) );
+ buf->extra_info->input_time = buf->pts / 90 ;
+ buf->type = this->si[stream_num]->buf_types;
+
+ fifo->put (fifo, buf);
+ }
+}
+#endif
+
+/* redefine abs as macro to handle 64-bit diffs.
+ i guess llabs may not be available everywhere */
+#define abs(x) ( ((x)<0) ? -(x) : (x) )
+
+static void check_newpts (demux_ogg_t *this, int64_t pts, int video, int preview) {
+ int64_t diff;
+
+ llprintf(DEBUG_PTS, "new pts %" PRId64 " found in stream\n",pts);
+
+ diff = pts - this->last_pts[video];
+
+ if (!preview && (pts>=0) &&
+ (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) {
+
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "diff=%" PRId64 " (pts=%" PRId64 ", last_pts=%" PRId64 ")\n", diff, pts, this->last_pts[video]);
+
+ if (this->buf_flag_seek) {
+ _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK);
+ this->buf_flag_seek = 0;
+ } else {
+ _x_demux_control_newpts(this->stream, pts, 0);
+ }
+ this->send_newpts = 0;
+ this->last_pts[1-video] = 0;
+ }
+
+ if (!preview && (pts>=0) )
+ this->last_pts[video] = pts;
+
+ /* use pts for bitrate measurement */
+
+ /*compute avg_bitrate if time_length isn't set*/
+ if ((pts>180000) && !(this->time_length)) {
+ this->avg_bitrate = this->input->get_current_pos (this->input) * 8 * 90000/ pts;
+
+ if (this->avg_bitrate<1)
+ this->avg_bitrate = 1;
+
+ }
+}
+
+static void ogg_handle_event (demux_ogg_t *this) {
+ xine_event_t *event;
+
+ while ((event = xine_event_get(this->event_queue))) {
+ switch(event->type) {
+ case XINE_EVENT_INPUT_NEXT:
+ {
+ if (this->chapter_info) {
+ int c_chap = this->chapter_info->current_chapter;
+ if (c_chap+1 < this->chapter_info->max_chapter) {
+ int start_time = this->chapter_info->entries[c_chap+1].start_pts / 90;
+ this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1);
+ }
+ }
+ }
+ break;
+ case XINE_EVENT_INPUT_PREVIOUS:
+ {
+ if (this->chapter_info) {
+ int c_chap = this->chapter_info->current_chapter;
+ if (c_chap >= 1) {
+ int start_time = this->chapter_info->entries[c_chap-1].start_pts / 90;
+ this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1);
+ }
+ }
+ }
+ break;
+ }
+ xine_event_free(event);
+ }
+ return;
+}
+
+/*
+ * utility function to read a LANGUAGE= line from the user_comments,
+ * to label audio and spu streams
+ */
+static void read_language_comment (demux_ogg_t *this, ogg_packet *op, int stream_num) {
+#ifdef HAVE_VORBIS
+ char **ptr;
+ char *comment;
+ vorbis_comment vc;
+ vorbis_info vi;
+
+ vorbis_comment_init(&vc);
+ vorbis_info_init(&vi);
+
+ /* this is necessary to make libvorbis accept this vorbis_info*/
+ vi.rate=1;
+
+ if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) {
+ ptr=vc.user_comments;
+ while(*ptr) {
+ comment=*ptr;
+ if ( !strncasecmp ("LANGUAGE=", comment, 9) ) {
+ this->si[stream_num]->language = strdup (comment + strlen ("LANGUAGE=") );
+ }
+ ++ptr;
+ }
+ }
+ vorbis_comment_clear(&vc);
+ vorbis_info_clear(&vi);
+#endif
+}
+
+/*
+ * utility function to read CHAPTER*= and TITLE= from the user_comments,
+ * to name parts of the videostream
+ */
+static void read_chapter_comment (demux_ogg_t *this, ogg_packet *op) {
+#ifdef HAVE_VORBIS
+ char **ptr;
+ char *comment;
+ vorbis_comment vc;
+ vorbis_info vi;
+
+ vorbis_comment_init(&vc);
+ vorbis_info_init(&vi);
+
+ /* this is necessary to make libvorbis accept this vorbis_info*/
+ vi.rate=1;
+
+ if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) {
+ char *chapter_time = 0;
+ char *chapter_name = 0;
+ int chapter_no = 0;
+ ptr=vc.user_comments;
+ while(*ptr) {
+ comment=*ptr;
+ if ( !strncasecmp ("TITLE=", comment,6) ) {
+ this->title = strdup (comment + strlen ("TITLE=") );
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title);
+ }
+ if ( !chapter_time && strlen(comment) == 22 &&
+ !strncasecmp ("CHAPTER" , comment, 7) &&
+ isdigit(*(comment+7)) && isdigit(*(comment+8)) &&
+ (*(comment+9) == '=')) {
+
+ chapter_time = strdup(comment+10);
+ chapter_no = strtol(comment+7, NULL, 10);
+ }
+ if ( !chapter_name && !strncasecmp("CHAPTER", comment, 7) &&
+ isdigit(*(comment+7)) && isdigit(*(comment+8)) &&
+ !strncasecmp ("NAME=", comment+9, 5)) {
+
+ if (strtol(comment+7,NULL,10) == chapter_no) {
+ chapter_name = strdup(comment+14);
+ }
+ }
+ if (chapter_time && chapter_name && chapter_no){
+ int hour, min, sec, msec;
+
+ lprintf("create chapter entry: no=%d name=%s time=%s\n", chapter_no, chapter_name, chapter_time);
+ hour= strtol(chapter_time, NULL, 10);
+ min = strtol(chapter_time+3, NULL, 10);
+ sec = strtol(chapter_time+6, NULL, 10);
+ msec = strtol(chapter_time+9, NULL, 10);
+ lprintf("time: %d %d %d %d\n", hour, min,sec,msec);
+
+ if (!this->chapter_info) {
+ this->chapter_info = (chapter_info_t *)xine_xmalloc(sizeof(chapter_info_t));
+ this->chapter_info->current_chapter = -1;
+ }
+ this->chapter_info->max_chapter = chapter_no;
+ this->chapter_info->entries = realloc( this->chapter_info->entries, chapter_no*sizeof(chapter_entry_t));
+ this->chapter_info->entries[chapter_no-1].name = chapter_name;
+ this->chapter_info->entries[chapter_no-1].start_pts = (msec + (1000.0 * sec) + (60000.0 * min) + (3600000.0 * hour))*90;
+
+ free (chapter_time);
+ chapter_no = 0;
+ chapter_time = chapter_name = 0;
+ }
+ ++ptr;
+ }
+ }
+ vorbis_comment_clear(&vc);
+ vorbis_info_clear(&vi);
+#endif
+}
+
+/*
+ * update the display of the title, if needed
+ */
+static void update_chapter_display (demux_ogg_t *this, int stream_num, ogg_packet *op) {
+ int chapter = 0;
+ int64_t pts = get_pts(this, stream_num, op->granulepos );
+
+ while (chapter < this->chapter_info->max_chapter &&
+ this->chapter_info->entries[chapter].start_pts < pts) {
+ chapter++;
+ }
+ chapter--;
+
+ if (chapter != this->chapter_info->current_chapter){
+ xine_event_t uevent;
+ xine_ui_data_t data;
+ int title_len;
+ char *title;
+
+ this->chapter_info->current_chapter = chapter;
+ if (chapter >= 0) {
+ char t_title[256];
+
+ if (this->title) {
+ snprintf(t_title, sizeof (t_title), "%s / %s", this->title, this->chapter_info->entries[chapter].name);
+ } else {
+ snprintf(t_title, sizeof (t_title), "%s", this->chapter_info->entries[chapter].name);
+ }
+ title = t_title;
+ } else {
+ title = this->title;
+ }
+ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title);
+ lprintf("new TITLE: %s\n", title);
+
+ uevent.type = XINE_EVENT_UI_SET_TITLE;
+ uevent.stream = this->stream;
+ uevent.data = &data;
+ uevent.data_length = sizeof(data);
+ title_len = strlen(title) + 1;
+ memcpy(data.str, title, title_len);
+ data.str_len = title_len;
+ xine_event_send(this->stream, &uevent);
+ }
+}
+
+/*
+ * utility function to pack one ogg_packet into a xine
+ * buffer, fill out all needed fields
+ * and send it to the right fifo
+ */
+
+static void send_ogg_buf (demux_ogg_t *this,
+ ogg_packet *op,
+ int stream_num,
+ uint32_t decoder_flags) {
+
+ int hdrlen;
+ int normpos = 0;
+
+ if( this->input->get_length (this->input) )
+ normpos = (int)( (double) this->input->get_current_pos (this->input) *
+ 65535 / this->input->get_length (this->input) );
+
+
+ hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6;
+ hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1;
+
+ /* for Annodex files: the first packet after the AnxData info packet needs
+ * to have its BOS flag set: we set it here */
+ if (!this->si[stream_num]->delivered_bos) {
+ op->b_o_s = 1;
+ this->si[stream_num]->delivered_bos = 1;
+ }
+
+ if ( this->audio_fifo
+ && (this->si[stream_num]->buf_types & 0xFF000000) == BUF_AUDIO_BASE) {
+ uint8_t *data;
+ int size;
+ int64_t pts;
+
+ if (op->packet[0] == PACKET_TYPE_COMMENT ) {
+ read_language_comment(this, op, stream_num);
+ }
+
+ if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_SPEEX ||
+ (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_FLAC ||
+ (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_VORBIS) {
+ data = op->packet;
+ size = op->bytes;
+ } else {
+ data = op->packet+1+hdrlen;
+ size = op->bytes-1-hdrlen;
+ }
+ llprintf(DEBUG_PACKETS, "audio data size %d\n", size);
+
+ if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) {
+ pts = get_pts(this, stream_num, op->granulepos );
+ check_newpts( this, pts, PTS_AUDIO, decoder_flags );
+ } else
+ pts = 0;
+
+ llprintf(DEBUG_PACKETS,
+ "audiostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n",
+ stream_num,
+ op->granulepos,
+ this->si[stream_num]->header_granulepos,
+ pts);
+
+ _x_demux_send_data(this->audio_fifo, data, size,
+ pts, this->si[stream_num]->buf_types, decoder_flags,
+ normpos,
+ pts / 90, this->time_length, 0);
+
+#ifdef HAVE_THEORA
+ } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_VIDEO_THEORA) {
+
+ int64_t pts;
+ theora_info t_info;
+ theora_comment t_comment;
+
+ theora_info_init (&t_info);
+ theora_comment_init (&t_comment);
+
+ /*Lets see if this is an Header*/
+ if ((theora_decode_header(&t_info, &t_comment, op))>=0) {
+ decoder_flags=decoder_flags|BUF_FLAG_HEADER;
+ lprintf ("found an header\n");
+ }
+
+ if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) {
+ pts = get_pts(this, stream_num, op->granulepos );
+ check_newpts( this, pts, PTS_VIDEO, decoder_flags );
+ } else
+ pts = 0;
+
+ llprintf(DEBUG_PACKETS,
+ "theorastream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n",
+ stream_num,
+ op->granulepos,
+ this->si[stream_num]->header_granulepos,
+ pts);
+
+ send_ogg_packet (this, this->video_fifo, op, pts, decoder_flags, stream_num);
+
+ theora_comment_clear (&t_comment);
+ theora_info_clear (&t_info);
+#endif
+
+ } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) {
+
+ uint8_t *data;
+ int size;
+ int64_t pts;
+
+ llprintf(DEBUG_VIDEO_PACKETS,
+ "video buffer, type=%08x\n", this->si[stream_num]->buf_types);
+
+ if (op->packet[0] == PACKET_TYPE_COMMENT ) {
+ read_chapter_comment(this, op);
+ }else{
+ data = op->packet+1+hdrlen;
+ size = op->bytes-1-hdrlen;
+
+ if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) {
+ pts = get_pts(this, stream_num, op->granulepos );
+ check_newpts( this, pts, PTS_VIDEO, decoder_flags );
+ } else
+ pts = 0;
+
+ llprintf(DEBUG_VIDEO_PACKETS,
+ "videostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n",
+ stream_num,
+ op->granulepos,
+ this->si[stream_num]->header_granulepos,
+ pts);
+
+ _x_demux_send_data(this->video_fifo, data, size,
+ pts, this->si[stream_num]->buf_types, decoder_flags,
+ normpos,
+ pts / 90, this->time_length, 0);
+
+ if (this->chapter_info && op->granulepos != -1) {
+ update_chapter_display(this, stream_num, op);
+ }
+ }
+ } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) {
+ buf_element_t *buf;
+ uint32_t *val;
+ char *str;
+
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+
+ buf->type = this->si[stream_num]->buf_types;
+
+ buf->pts = get_pts (this, stream_num, op->granulepos);
+
+ val = (uint32_t * )buf->content;
+ str = (char *)val;
+
+ memcpy(str, op->packet, op->bytes);
+ str[op->bytes] = '\0';
+
+ buf->size = 12 + op->bytes + 1;
+
+ lprintf ("CMML stream %d (bytes=%ld): PTS %"PRId64": %s\n",
+ stream_num, op->bytes, buf->pts, str);
+
+ this->video_fifo->put (this->video_fifo, buf);
+ } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) {
+
+ buf_element_t *buf;
+ int i;
+ char *subtitle,*str;
+ int lenbytes;
+ int start,end;
+ uint32_t *val;
+
+ for (i = 0, lenbytes = 0; i < hdrlen; i++) {
+ lenbytes = lenbytes << 8;
+ lenbytes += *((unsigned char *) op->packet + hdrlen - i);
+ }
+
+ if (op->packet[0] == PACKET_TYPE_HEADER ) {
+ lprintf ("Textstream-header-packet\n");
+ } else if (op->packet[0] == PACKET_TYPE_COMMENT ) {
+ lprintf ("Textstream-comment-packet\n");
+ read_language_comment(this, op, stream_num);
+ } else {
+ subtitle = (char *)&op->packet[hdrlen + 1];
+
+ if ((strlen(subtitle) > 1) || (*subtitle != ' ')) {
+ start = op->granulepos;
+ end = start+lenbytes;
+ lprintf ("subtitlestream %d: %d -> %d :%s\n",stream_num,start,end,subtitle);
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+
+ buf->type = this->si[stream_num]->buf_types;
+ buf->pts = 0;
+
+ val = (uint32_t * )buf->content;
+ *val++ = start;
+ *val++ = end;
+ str = (char *)val;
+
+ memcpy (str, subtitle, 1+strlen(subtitle));
+
+ this->video_fifo->put (this->video_fifo, buf);
+ }
+ }
+ } else {
+ lprintf("unknown stream type %x\n", this->si[stream_num]->buf_types);
+ }
+}
+
+static void decode_vorbis_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+#ifdef HAVE_VORBIS
+ vorbis_info vi;
+ vorbis_comment vc;
+
+ this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS
+ +this->num_audio_streams++;
+
+ this->si[stream_num]->headers = 3;
+
+ vorbis_info_init(&vi);
+ vorbis_comment_init(&vc);
+ if (vorbis_synthesis_headerin(&vi, &vc, op) >= 0) {
+
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, vi.bitrate_nominal);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, vi.rate);
+
+ this->si[stream_num]->factor = 90000;
+ this->si[stream_num]->quotient = vi.rate;
+
+ if (vi.bitrate_nominal<1)
+ this->avg_bitrate += 100000; /* assume 100 kbit */
+ else
+ this->avg_bitrate += vi.bitrate_nominal;
+
+ } else {
+ this->si[stream_num]->factor = 900;
+ this->si[stream_num]->quotient = 441;
+
+ this->si[stream_num]->headers = 0;
+ xine_log (this->stream->xine, XINE_LOG_MSG,
+ _("ogg: vorbis audio track indicated but no vorbis stream header found.\n"));
+ }
+ vorbis_comment_clear(&vc);
+ vorbis_info_clear(&vi);
+#endif
+}
+
+static void decode_speex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+#ifdef HAVE_SPEEX
+ void *st;
+ SpeexMode *mode;
+ SpeexHeader *header;
+
+ this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX
+ +this->num_audio_streams++;
+
+ this->si[stream_num]->headers = 1;
+
+ header = speex_packet_to_header (op->packet, op->bytes);
+
+ if (header) {
+ int bitrate;
+ mode = (SpeexMode *) speex_mode_list[header->mode];
+
+ st = speex_decoder_init (mode);
+
+ speex_decoder_ctl (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->si[stream_num]->factor = 90000;
+ this->si[stream_num]->quotient = header->rate;
+
+ this->avg_bitrate += bitrate;
+
+ lprintf ("detected Speex stream,\trate %d\tbitrate %d\n", header->rate, bitrate);
+
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, header->rate);
+ this->si[stream_num]->headers += header->extra_headers;
+ }
+#else
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Speex stream detected, unable to play\n");
+
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+#endif
+}
+
+static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ buf_element_t *buf;
+ xine_bmiheader bih;
+ int channel;
+
+ int16_t locbits_per_sample;
+ uint32_t locsubtype;
+ int32_t locsize, locdefault_len, locbuffersize, locwidth, locheight;
+ int64_t loctime_unit, locsamples_per_unit;
+
+ /* read fourcc with machine endianness */
+ locsubtype = *((uint32_t *)&op->packet[9]);
+
+ /* everything else little endian */
+ locsize = _X_LE_32(&op->packet[13]);
+ loctime_unit = _X_LE_64(&op->packet[17]);
+ locsamples_per_unit = _X_LE_64(&op->packet[25]);
+ locdefault_len = _X_LE_32(&op->packet[33]);
+ locbuffersize = _X_LE_32(&op->packet[37]);
+ locbits_per_sample = _X_LE_16(&op->packet[41]);
+ locwidth = _X_LE_32(&op->packet[45]);
+ locheight = _X_LE_32(&op->packet[49]);
+
+ lprintf ("direct show filter created stream detected, hexdump:\n");
+#ifdef LOG
+ xine_hexdump (op->packet, op->bytes);
+#endif
+
+ channel = this->num_video_streams++;
+
+ this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (locsubtype);
+ if( !this->si[stream_num]->buf_types )
+ {
+ this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN;
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, locsubtype);
+ }
+ this->si[stream_num]->buf_types |= channel;
+ this->si[stream_num]->headers = 0; /* header is sent below */
+
+ lprintf ("subtype %.4s\n", (char*)&locsubtype);
+ lprintf ("time_unit %" PRId64 "\n", loctime_unit);
+ lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit);
+ lprintf ("default_len %d\n", locdefault_len);
+ lprintf ("buffersize %d\n", locbuffersize);
+ lprintf ("bits_per_sample %d\n", locbits_per_sample);
+ lprintf ("width %d\n", locwidth);
+ lprintf ("height %d\n", locheight);
+ lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types);
+
+ bih.biSize=sizeof(xine_bmiheader);
+ bih.biWidth = locwidth;
+ bih.biHeight= locheight;
+ bih.biPlanes= 0;
+ memcpy(&bih.biCompression, &locsubtype, 4);
+ bih.biBitCount= 0;
+ bih.biSizeImage=locwidth*locheight;
+ bih.biXPelsPerMeter=1;
+ bih.biYPelsPerMeter=1;
+ bih.biClrUsed=0;
+ bih.biClrImportant=0;
+
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE|
+ BUF_FLAG_FRAME_END;
+ this->frame_duration = loctime_unit * 9 / 1000;
+ this->si[stream_num]->factor = loctime_unit * 9;
+ this->si[stream_num]->quotient = 1000;
+ buf->decoder_info[0] = this->frame_duration;
+ memcpy (buf->content, &bih, sizeof (xine_bmiheader));
+ buf->size = sizeof (xine_bmiheader);
+ buf->type = this->si[stream_num]->buf_types;
+
+ /* video metadata */
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, locsubtype);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, locwidth);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, locheight);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration);
+
+ this->avg_bitrate += 500000; /* FIXME */
+
+ this->video_fifo->put (this->video_fifo, buf);
+}
+
+static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+
+ if (this->audio_fifo) {
+ buf_element_t *buf;
+ int codec;
+ char str[5];
+ int channel;
+
+ int16_t locbits_per_sample, locchannels, locblockalign;
+ int32_t locsize, locdefault_len, locbuffersize, locavgbytespersec;
+ int64_t loctime_unit, locsamples_per_unit;
+
+ locsize = _X_LE_32(&op->packet[13]);
+ loctime_unit = _X_LE_64(&op->packet[17]);
+ locsamples_per_unit = _X_LE_64(&op->packet[25]);
+ locdefault_len = _X_LE_32(&op->packet[33]);
+ locbuffersize = _X_LE_32(&op->packet[37]);
+ locbits_per_sample = _X_LE_16(&op->packet[41]);
+ locchannels = _X_LE_16(&op->packet[45]);
+ locblockalign = _X_LE_16(&op->packet[47]);
+ locavgbytespersec= _X_LE_32(&op->packet[49]);
+
+ lprintf ("direct show filter created audio stream detected, hexdump:\n");
+#ifdef LOG
+ xine_hexdump (op->packet, op->bytes);
+#endif
+
+ memcpy(str, &op->packet[9], 4);
+ str[4] = 0;
+ codec = strtoul(str, NULL, 16);
+
+ channel= this->num_audio_streams++;
+
+ this->si[stream_num]->buf_types = _x_formattag_to_buf_audio(codec);
+ if( this->si[stream_num]->buf_types ) {
+ this->si[stream_num]->buf_types |= channel;
+ } else {
+ this->si[stream_num]->buf_types = BUF_AUDIO_UNKNOWN;
+ _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, codec);
+ /*break;*/
+ }
+
+ lprintf ("subtype 0x%x\n", codec);
+ lprintf ("time_unit %" PRId64 "\n", loctime_unit);
+ lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit);
+ lprintf ("default_len %d\n", locdefault_len);
+ lprintf ("buffersize %d\n", locbuffersize);
+ lprintf ("bits_per_sample %d\n", locbits_per_sample);
+ lprintf ("channels %d\n", locchannels);
+ lprintf ("blockalign %d\n", locblockalign);
+ lprintf ("avgbytespersec %d\n", locavgbytespersec);
+ lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types);
+
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = this->si[stream_num]->buf_types;
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = locsamples_per_unit;
+ buf->decoder_info[2] = locbits_per_sample;
+ buf->decoder_info[3] = locchannels;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ this->si[stream_num]->headers = 0; /* header already sent */
+ this->si[stream_num]->factor = 90000;
+ this->si[stream_num]->quotient = locsamples_per_unit;
+
+ this->avg_bitrate += locavgbytespersec*8;
+
+ /* audio metadata */
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, codec);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, locchannels);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, locbits_per_sample);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, locsamples_per_unit);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, locavgbytespersec * 8);
+
+ } else /* no audio_fifo there */
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+}
+
+static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+
+ lprintf ("older Direct Show filter-generated stream header detected. Hexdump:\n");
+#ifdef LOG
+ xine_hexdump (op->packet, op->bytes);
+#endif
+
+ this->si[stream_num]->headers = 0; /* header is sent below */
+
+ if ( (_X_LE_32(&op->packet[96]) == 0x05589f80) && (op->bytes >= 184)) {
+
+ buf_element_t *buf;
+ xine_bmiheader bih;
+ int channel;
+ uint32_t fcc;
+
+ lprintf ("seems to be a video stream.\n");
+
+ channel = this->num_video_streams++;
+ fcc = *(uint32_t*)(op->packet+68);
+ lprintf ("fourcc %08x\n", fcc);
+
+ this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (fcc);
+ if( !this->si[stream_num]->buf_types )
+ {
+ this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN;
+ _x_report_video_fourcc (this->stream->xine, LOG_MODULE, fcc);
+ }
+ this->si[stream_num]->buf_types |= channel;
+
+ bih.biSize = sizeof(xine_bmiheader);
+ bih.biWidth = _X_LE_32(&op->packet[176]);
+ bih.biHeight = _X_LE_32(&op->packet[180]);
+ bih.biPlanes = 0;
+ memcpy (&bih.biCompression, op->packet+68, 4);
+ bih.biBitCount = _X_LE_16(&op->packet[182]);
+ if (!bih.biBitCount)
+ bih.biBitCount = 24; /* FIXME ? */
+ bih.biSizeImage = (bih.biBitCount>>3)*bih.biWidth*bih.biHeight;
+ bih.biXPelsPerMeter = 1;
+ bih.biYPelsPerMeter = 1;
+ bih.biClrUsed = 0;
+ bih.biClrImportant = 0;
+
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE|
+ BUF_FLAG_FRAME_END;
+ this->frame_duration = (*(int64_t*)(op->packet+164)) * 9 / 1000;
+ this->si[stream_num]->factor = (*(int64_t*)(op->packet+164)) * 9;
+ this->si[stream_num]->quotient = 1000;
+
+ buf->decoder_info[0] = this->frame_duration;
+ memcpy (buf->content, &bih, sizeof (xine_bmiheader));
+ buf->size = sizeof (xine_bmiheader);
+ buf->type = this->si[stream_num]->buf_types;
+ this->video_fifo->put (this->video_fifo, buf);
+
+ lprintf ("subtype %.4s\n", (char*)&fcc);
+ lprintf ("buf_type %08x\n", this->si[stream_num]->buf_types);
+ lprintf ("video size %d x %d\n", bih.biWidth, bih.biHeight);
+ lprintf ("frame duration %d\n", this->frame_duration);
+
+ /* video metadata */
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, bih.biWidth);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, bih.biHeight);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration);
+
+ this->avg_bitrate += 500000; /* FIXME */
+
+ this->ignore_keyframes = 1;
+
+ } else if (_X_LE_32(&op->packet[96]) == 0x05589F81) {
+
+#if 0
+ /* FIXME: no test streams */
+
+ buf_element_t *buf;
+ int codec;
+ char str[5];
+ int channel;
+ int extra_size;
+
+ extra_size = *(int16_t*)(op->packet+140);
+ format = *(int16_t*)(op->packet+124);
+ channels = *(int16_t*)(op->packet+126);
+ samplerate = *(int32_t*)(op->packet+128);
+ nAvgBytesPerSec = *(int32_t*)(op->packet+132);
+ nBlockAlign = *(int16_t*)(op->packet+136);
+ wBitsPerSample = *(int16_t*)(op->packet+138);
+ samplesize = (sh_a->wf->wBitsPerSample+7)/8;
+ cbSize = extra_size;
+ if(extra_size > 0)
+ memcpy(wf+sizeof(WAVEFORMATEX),op->packet+142,extra_size);
+#endif
+
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "FIXME, old audio format not handled\n");
+
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+
+ } else {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "old header detected but stream type is unknown\n");
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+ }
+}
+
+static void decode_text_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ int channel=0;
+ uint32_t *val;
+ buf_element_t *buf;
+
+ lprintf ("textstream detected.\n");
+ this->si[stream_num]->headers = 2;
+ channel = this->num_spu_streams++;
+ this->si[stream_num]->buf_types = BUF_SPU_OGM | channel;
+
+ /*send an empty spu to inform the video_decoder, that there is a stream*/
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = this->si[stream_num]->buf_types;
+ buf->pts = 0;
+ val = (uint32_t * )buf->content;
+ *val++=0;
+ *val++=0;
+ *val++=0;
+ this->video_fifo->put (this->video_fifo, buf);
+}
+
+static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+
+#ifdef HAVE_THEORA
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "demux_ogg: Theorastreamsupport is highly alpha at the moment\n");
+
+ if (theora_decode_header(&this->t_info, &this->t_comment, op) >= 0) {
+
+ this->num_video_streams++;
+
+ this->si[stream_num]->factor = (int64_t) 90000 * (int64_t) this->t_info.fps_denominator;
+
+ if (!this->t_info.fps_numerator) {
+ this->t_info.fps_numerator = 1; /* FIXME: default value ? */
+ }
+ this->si[stream_num]->quotient = this->t_info.fps_numerator;
+
+ this->frame_duration = ((int64_t) 90000*this->t_info.fps_denominator);
+ this->frame_duration /= this->t_info.fps_numerator;
+
+ this->si[stream_num]->granuleshift = intlog(this->t_info.keyframe_frequency_force-1);
+
+ this->si[stream_num]->headers=3;
+ this->si[stream_num]->buf_types = BUF_VIDEO_THEORA;
+
+ _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora");
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->t_info.frame_width);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->t_info.frame_height);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration);
+
+ /*currently aspect_nominator and -denumerator are 0?*/
+ if (this->t_info.aspect_denominator) {
+ int64_t ratio = ((int64_t) this->t_info.aspect_numerator * 10000);
+
+ ratio /= this->t_info.aspect_denominator;
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, ratio);
+ }
+
+ lprintf ("decoded theora header \n");
+ lprintf ("frameduration %d\n",this->frame_duration);
+ lprintf ("w:%d h:%d \n",this->t_info.frame_width,this->t_info.frame_height);
+ lprintf ("an:%d ad:%d \n",this->t_info.aspect_numerator,this->t_info.aspect_denominator);
+ } else {
+ /*Rejected stream*/
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "A theora header was rejected by libtheora\n");
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+ this->si[stream_num]->headers = 0; /* FIXME: don't know */
+ }
+#else
+ this->si[stream_num]->buf_types = BUF_VIDEO_THEORA;
+ this->num_video_streams++;
+ this->unhandled_video_streams++;
+ _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora");
+#endif
+}
+
+static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ xine_flac_metadata_header header;
+ xine_flac_streaminfo_block streaminfo;
+ buf_element_t *buf;
+ xine_waveformatex wave;
+
+ /* Packet type */
+ _x_assert(op->packet[0] == 0x7F);
+
+ /* OggFLAC signature */
+ _x_assert(_X_BE_32(&op->packet[1]) == ME_FOURCC('F', 'L', 'A', 'C'));
+
+ /* Version: supported only 1.0 */
+ _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0);
+
+ /* Header count */
+ this->si[stream_num]->headers = 0/*_X_BE_16(&op->packet[7]) +1*/;
+
+ /* fLaC signature */
+ _x_assert(_X_BE_32(&op->packet[9]) == ME_FOURCC('f', 'L', 'a', 'C'));
+
+ _x_parse_flac_metadata_header(&op->packet[13], &header);
+
+ switch ( header.blocktype ) {
+ case FLAC_BLOCKTYPE_STREAMINFO:
+ _x_assert(header.length == FLAC_STREAMINFO_SIZE);
+ _x_parse_flac_streaminfo_block(&op->packet[17], &streaminfo);
+
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, streaminfo.samplerate);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, streaminfo.channels);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, streaminfo.bits_per_sample);
+
+ break;
+ }
+
+ this->si[stream_num]->buf_types = BUF_AUDIO_FLAC
+ +this->num_audio_streams++;
+
+ this->si[stream_num]->factor = 90000;
+
+ buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
+
+ buf->type = BUF_AUDIO_FLAC;
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
+
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = streaminfo.samplerate;
+ buf->decoder_info[2] = streaminfo.bits_per_sample;
+ buf->decoder_info[3] = streaminfo.channels;
+ buf->size = sizeof(xine_waveformatex) + FLAC_STREAMINFO_SIZE;
+ memcpy(buf->content+sizeof(xine_waveformatex), &op->packet[17], FLAC_STREAMINFO_SIZE);
+ xine_hexdump(&op->packet[17], FLAC_STREAMINFO_SIZE);
+ wave.cbSize = FLAC_STREAMINFO_SIZE;
+ memcpy(buf->content, &wave, sizeof(xine_waveformatex));
+
+ this->audio_fifo->put(this->audio_fifo, buf);
+
+ /* Skip the Ogg framing info */
+ op->bytes -= 9;
+ op->packet += 9;
+}
+
+static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ lprintf ("Annodex stream detected\n");
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+ this->si[stream_num]->headers = 1;
+ this->si[stream_num]->header_granulepos = op->granulepos;
+ _x_meta_info_set(this->stream, XINE_META_INFO_SYSTEMLAYER, "Annodex");
+}
+
+static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ int64_t granule_rate_n, granule_rate_d;
+ uint32_t secondary_headers;
+ char content_type[1024];
+ int content_type_length;
+
+ lprintf("AnxData stream detected\n");
+
+ /* read granule rate */
+ granule_rate_n = _X_LE_64(&op->packet[8]);
+ granule_rate_d = _X_LE_64(&op->packet[16]);
+ secondary_headers = _X_LE_32(&op->packet[24]);
+
+ lprintf("granule_rate %" PRId64 "/%" PRId64 ", %d secondary headers\n",
+ granule_rate_n, granule_rate_d, secondary_headers);
+
+ /* read "Content-Tyoe" MIME header */
+ sscanf(&op->packet[28], "Content-Type: %1023s\r\n", content_type);
+ content_type_length = strlen(content_type);
+
+ lprintf("Content-Type: %s (length:%d)\n", content_type, content_type_length);
+
+ /* how many header packets in the AnxData stream? */
+ this->si[stream_num]->headers = secondary_headers + 1;
+ this->si[stream_num]->hide_first_header = 1;
+
+ /* set factor and quotient */
+ this->si[stream_num]->factor = (int64_t) 90000 * granule_rate_d;
+ this->si[stream_num]->quotient = granule_rate_n;
+
+ lprintf("factor: %" PRId64 ", quotient: %" PRId64 "\n",
+ this->si[stream_num]->factor, this->si[stream_num]->quotient);
+
+ /* what type of stream are we dealing with? */
+ if (!strncmp(content_type, "audio/x-vorbis", content_type_length)) {
+#ifdef HAVE_VORBIS
+ this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS;
+#else
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+#endif
+ this->num_audio_streams++;
+ } else if (!strncmp(content_type, "audio/x-speex", content_type_length)) {
+ this->num_audio_streams++;
+#ifdef HAVE_SPEEX
+ this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX;
+#else
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+#endif
+ } else if (!strncmp(content_type, "video/x-theora", content_type_length)) {
+ this->num_video_streams++;
+#ifdef HAVE_THEORA
+ this->si[stream_num]->buf_types = BUF_VIDEO_THEORA;
+#else
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+#endif
+ } else if (!strncmp(content_type, "text/x-cmml", content_type_length)) {
+ unsigned int channel = this->num_spu_streams++;
+ this->si[stream_num]->headers = 0;
+ this->si[stream_num]->buf_types = BUF_SPU_CMML | channel;
+ this->si[stream_num]->granuleshift = 0;
+ } else {
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+ }
+
+}
+
+static void decode_cmml_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) {
+ unsigned int channel = this->num_spu_streams++;
+ this->si[stream_num]->headers = 0;
+ this->si[stream_num]->buf_types = BUF_SPU_CMML | channel;
+
+ this->si[stream_num]->factor = 90000 * _X_LE_64(&op->packet[20]);
+ this->si[stream_num]->quotient = _X_LE_64(&op->packet[12]);
+ this->si[stream_num]->granuleshift = (int)op->packet[28];
+}
+
+/*
+ * interpret stream start packages, send headers
+ */
+static void send_header (demux_ogg_t *this) {
+
+ int stream_num = -1;
+ int cur_serno;
+ int done = 0;
+ ogg_packet op;
+ xine_event_t ui_event;
+
+ lprintf ("detecting stream types...\n");
+
+ this->ignore_keyframes = 0;
+
+ while (!done) {
+ if (!read_ogg_packet(this)) {
+ return;
+ }
+ /* now we've got at least one new page */
+
+ cur_serno = ogg_page_serialno (&this->og);
+
+ if (ogg_page_bos(&this->og)) {
+ lprintf ("beginning of stream\n");
+ lprintf ("serial number %d\n", cur_serno);
+
+ if( this->num_streams == MAX_STREAMS ) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n");
+ this->status = DEMUX_FINISHED;
+ return;
+ }
+ stream_num = new_stream_info(this, cur_serno);
+
+ } else {
+ stream_num = get_stream(this, cur_serno);
+ if (stream_num == -1) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: stream with no beginning!\n");
+ this->status = DEMUX_FINISHED;
+ return;
+ }
+ }
+
+ ogg_stream_pagein(&this->si[stream_num]->oss, &this->og);
+
+ while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) {
+
+ if (!this->si[stream_num]->buf_types) {
+
+ /* detect buftype */
+ if (!memcmp (&op.packet[1], "vorbis", 6)) {
+ decode_vorbis_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[0], "Speex", 5)) {
+ decode_speex_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[1], "video", 5)) {
+ decode_video_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[1], "audio", 5)) {
+ decode_audio_header(this, stream_num, &op);
+ } else if (op.bytes >= 142
+ && !memcmp (&op.packet[1], "Direct Show Samples embedded in Ogg", 35) ) {
+ decode_dshow_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[1], "text", 4)) {
+ decode_text_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[1], "theora", 6)) {
+ decode_theora_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[1], "FLAC", 4)) {
+ decode_flac_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[0], "Annodex", 7)) {
+ decode_annodex_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[0], "AnxData", 7)) {
+ decode_anxdata_header(this, stream_num, &op);
+ } else if (!memcmp (&op.packet[0], "CMML", 4)) {
+ decode_cmml_header(this, stream_num, &op);
+ } else {
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "demux_ogg: unknown stream type (signature >%.8s<). hex dump of bos packet follows:\n",
+ op.packet);
+ if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
+ xine_hexdump (op.packet, op.bytes);
+
+ this->si[stream_num]->buf_types = BUF_CONTROL_NOP;
+ }
+ }
+
+ /* send preview buffer */
+ if (this->si[stream_num]->headers > 0 ||
+ op.packet[0] == PACKET_TYPE_COMMENT) {
+ if (this->si[stream_num]->hide_first_header)
+ this->si[stream_num]->hide_first_header = 0;
+ else {
+ lprintf ("sending preview buffer of stream type %08x\n",
+ this->si[stream_num]->buf_types);
+
+ send_ogg_buf (this, &op, stream_num, BUF_FLAG_HEADER);
+ this->si[stream_num]->headers --;
+ }
+ }
+
+ /* are we finished ? */
+ if (!ogg_page_bos(&this->og)) {
+ int i;
+ done = 1;
+
+ for (i=0; i<this->num_streams; i++) {
+ if (this->si[i]->headers > 0)
+ done = 0;
+
+ llprintf(DEBUG_PREVIEWS,
+ "%d preview buffers left to send from stream %d\n",
+ this->si[i]->headers, i);
+ }
+ }
+ }
+ }
+
+ ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED;
+ ui_event.data_length = 0;
+ xine_event_send(this->stream, &ui_event);
+
+ /*get the streamlength*/
+ get_stream_length (this);
+
+}
+
+static int demux_ogg_send_chunk (demux_plugin_t *this_gen) {
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+
+ int stream_num;
+ int cur_serno;
+
+ ogg_packet op;
+
+ ogg_handle_event(this);
+
+ llprintf(DEBUG_PACKETS, "send package...\n");
+
+ if (!read_ogg_packet(this)) {
+ this->status = DEMUX_FINISHED;
+ lprintf ("EOF\n");
+ return this->status;
+ }
+
+ /* now we've got one new page */
+
+ cur_serno = ogg_page_serialno (&this->og);
+ stream_num = get_stream(this, cur_serno);
+ if (stream_num < 0) {
+ lprintf ("error: unknown stream, serialnumber %d\n", cur_serno);
+
+ if (!ogg_page_bos(&this->og)) {
+ lprintf ("help, stream with no beginning!\n");
+ }
+ lprintf ("adding late stream with serial number %d (all content will be discarded)\n", cur_serno);
+
+ if( this->num_streams == MAX_STREAMS ) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n");
+ this->status = DEMUX_FINISHED;
+ return this->status;
+ }
+ stream_num = new_stream_info(this, cur_serno);
+ }
+
+ ogg_stream_pagein(&this->si[stream_num]->oss, &this->og);
+
+ if (ogg_page_bos(&this->og)) {
+ lprintf ("beginning of stream: serial number %d - discard\n",
+ ogg_page_serialno (&this->og));
+ while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) ;
+ return this->status;
+ }
+
+ /*while keyframeseeking only process videostream*/
+ if (!this->ignore_keyframes && this->keyframe_needed
+ && ((this->si[stream_num]->buf_types & 0xFF000000) != BUF_VIDEO_BASE))
+ return this->status;
+
+ while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) {
+ /* printf("demux_ogg: packet: %.8s\n", op.packet); */
+ /* printf("demux_ogg: got a packet\n"); */
+
+ if ((*op.packet & PACKET_TYPE_HEADER) &&
+ (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX) && (this->si[stream_num]->buf_types!=BUF_AUDIO_FLAC)) {
+ if (op.granulepos != -1) {
+ this->si[stream_num]->header_granulepos = op.granulepos;
+ lprintf ("header with granulepos, remembering granulepos\n");
+ } else {
+ lprintf ("header => discard\n");
+ }
+ continue;
+ }
+
+ /*discard granulepos-less packets and to early audiopackets*/
+ if (this->si[stream_num]->resync) {
+ if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) {
+ /*never drop subtitles*/
+ this->si[stream_num]->resync=0;
+ } else if ((op.granulepos == -1) && (this->si[stream_num]->header_granulepos == -1)) {
+ continue;
+ } else {
+
+ /*dump too early packets*/
+ if ((get_pts(this,stream_num,op.granulepos)-this->start_pts) > -90000)
+ this->si[stream_num]->resync=0;
+ else
+ continue;
+ }
+ }
+
+ if (!this->ignore_keyframes && this->keyframe_needed) {
+ lprintf ("keyframe needed... buf_type=%08x\n", this->si[stream_num]->buf_types);
+ if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA) {
+#ifdef HAVE_THEORA
+
+ int keyframe_granule_shift;
+ int64_t pframe=-1,iframe=-1;
+
+ keyframe_granule_shift = this->si[stream_num]->granuleshift;
+
+ if(op.granulepos>=0){
+ iframe=op.granulepos>>keyframe_granule_shift;
+ pframe=op.granulepos-(iframe<<keyframe_granule_shift);
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "seeking keyframe i %" PRId64 " p %" PRId64 "\n", iframe, pframe);
+ if (pframe!=0)
+ continue;
+ } else
+ continue;
+ this->keyframe_needed = 0;
+ this->start_pts=get_pts(this,stream_num,op.granulepos);
+#endif
+ } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) {
+
+ /*calculate the current pts*/
+ if (op.granulepos!=-1) {
+ this->start_pts=get_pts(this, stream_num, op.granulepos);
+ } else if (this->start_pts!=-1)
+ this->start_pts=this->start_pts+this->frame_duration;
+
+ /*seek the keyframe*/
+ if ((*op.packet == PACKET_IS_SYNCPOINT) && (this->start_pts!=-1))
+ this->keyframe_needed = 0;
+ else
+ continue;
+
+ } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) continue;
+ }
+ send_ogg_buf (this, &op, stream_num, 0);
+
+ /*delete used header_granulepos*/
+ if (op.granulepos == -1)
+ this->si[stream_num]->header_granulepos = -1;
+
+ }
+ if (ogg_page_eos(&this->og)) {
+ int i;
+ int finished_streams = 0;
+
+ lprintf("end of stream, serialnumber %d\n", cur_serno);
+ this->si[stream_num]->delivered_eos = 1;
+
+ /* check if all logical streams are finished */
+ for (i = 0; i < this->num_streams; i++) {
+ finished_streams += this->si[i]->delivered_eos;
+ }
+
+ /* if all streams are finished, perhaps a chained stream follows */
+ if (finished_streams == this->num_streams) {
+ /* delete current logical streams */
+ for (i = 0; i < this->num_streams; i++) {
+ ogg_stream_clear(&this->si[i]->oss);
+ if (this->si[i]->language) {
+ free (this->si[i]->language);
+ }
+ free (this->si[i]);
+ }
+ this->num_streams = 0;
+ this->num_audio_streams = 0;
+ this->num_video_streams = 0;
+ this->unhandled_video_streams = 0;
+ this->num_spu_streams = 0;
+ this->avg_bitrate = 1;
+
+ /* try to read a chained stream */
+ this->send_newpts = 1;
+ this->last_pts[0] = 0;
+ this->last_pts[1] = 0;
+
+ /* send control buffer to avoid buffer leak */
+ _x_demux_control_end(this->stream, 0);
+ _x_demux_control_start(this->stream);
+ send_header(this);
+ }
+ }
+
+ return this->status;
+}
+
+static void demux_ogg_dispose (demux_plugin_t *this_gen) {
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+ int i;
+
+ for (i=0; i<this->num_streams; i++) {
+ ogg_stream_clear(&this->si[i]->oss);
+
+ if (this->si[i]->language) {
+ free (this->si[i]->language);
+ }
+ free(this->si[i]);
+ }
+
+ ogg_sync_clear(&this->oy);
+
+#ifdef HAVE_THEORA
+ theora_comment_clear (&this->t_comment);
+ theora_info_clear (&this->t_info);
+#endif
+
+ if (this->chapter_info){
+ free (this->chapter_info->entries);
+ free (this->chapter_info);
+ }
+ if (this->title){
+ free (this->title);
+ }
+ if (this->event_queue)
+ xine_event_dispose_queue (this->event_queue);
+
+ free (this);
+}
+
+static int demux_ogg_get_status (demux_plugin_t *this_gen) {
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+
+ return this->status;
+}
+
+static void demux_ogg_send_headers (demux_plugin_t *this_gen) {
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+
+ this->video_fifo = this->stream->video_fifo;
+ this->audio_fifo = this->stream->audio_fifo;
+
+ this->status = DEMUX_OK;
+
+ /*
+ * send start buffers
+ */
+
+ this->last_pts[0] = 0;
+ this->last_pts[1] = 0;
+
+ /*
+ * initialize ogg engine
+ */
+ ogg_sync_init(&this->oy);
+
+ this->num_streams = 0;
+ this->num_audio_streams = 0;
+ this->num_video_streams = 0;
+ this->num_spu_streams = 0;
+ this->avg_bitrate = 1;
+
+ this->input->seek (this->input, 0, SEEK_SET);
+
+ if (this->status == DEMUX_OK) {
+ _x_demux_control_start(this->stream);
+ send_header (this);
+ lprintf ("headers sent, avg bitrate is %" PRId64 "\n", this->avg_bitrate);
+ }
+
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO,
+ this->num_video_streams > 0);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED,
+ this->num_video_streams > this->unhandled_video_streams);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO,
+ this->num_audio_streams > 0);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL,
+ this->num_spu_streams);
+}
+
+static int demux_ogg_seek (demux_plugin_t *this_gen,
+ off_t start_pos, int start_time, int playing) {
+
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+ int i;
+ start_time /= 1000;
+ start_pos = (off_t) ( (double) start_pos / 65535 *
+ this->input->get_length (this->input) );
+ /*
+ * seek to start position
+ */
+
+ if (INPUT_IS_SEEKABLE(this->input)) {
+
+ this->keyframe_needed = (this->num_video_streams>0);
+
+ if ( (!start_pos) && (start_time)) {
+ if (this->time_length != -1) {
+ /*do the seek via time*/
+ int current_time=-1;
+ off_t current_pos;
+ current_pos=this->input->get_current_pos(this->input);
+
+ /*try to find out the current time*/
+ if (this->last_pts[PTS_VIDEO]) {
+ current_time=this->last_pts[PTS_VIDEO]/90000;
+ } else if (this->last_pts[PTS_AUDIO]) {
+ current_time=this->last_pts[PTS_AUDIO]/90000;
+ }
+
+ /*fixme, the file could grow, do something
+ about this->time_length using get_lenght to verify, that the stream
+ hasn` changed its length, otherwise no seek to "new" data is possible*/
+
+ lprintf ("seek to time %d called\n",start_time);
+ lprintf ("current time is %d\n",current_time);
+
+ if (current_time > start_time) {
+ /*seek between beginning and current_pos*/
+
+ /*fixme - sometimes we seek backwards and during
+ keyframeseeking, we undo the seek*/
+
+ start_pos = start_time * current_pos
+ / current_time ;
+ } else {
+ /*seek between current_pos and end*/
+ start_pos = current_pos +
+ ((start_time - current_time) *
+ ( this->input->get_length(this->input) - current_pos ) /
+ ( (this->time_length / 1000) - current_time)
+ );
+ }
+
+ lprintf ("current_pos is %" PRId64 "\n",current_pos);
+ lprintf ("new_pos is %" PRId64 "\n",start_pos);
+
+ } else {
+ /*seek using avg_bitrate*/
+ start_pos = start_time * this->avg_bitrate/8;
+ }
+
+ lprintf ("seeking to %d seconds => %" PRId64 " bytes\n",
+ start_time, start_pos);
+
+ }
+
+ ogg_sync_reset(&this->oy);
+
+ for (i=0; i<this->num_streams; i++) {
+ this->si[i]->header_granulepos = -1;
+ ogg_stream_reset(&this->si[i]->oss);
+ }
+
+ /*some strange streams have no syncpoint flag set at the beginning*/
+ if (start_pos == 0)
+ this->keyframe_needed = 0;
+
+ lprintf ("seek to %" PRId64 " called\n",start_pos);
+
+ this->input->seek (this->input, start_pos, SEEK_SET);
+
+ }
+
+ /* fixme - this would be a nice position to do the following tasks
+ 1. adjust an ogg videostream to a keyframe
+ 2. compare the keyframe_pts with start_time. if the difference is to
+ high (e.g. larger than max keyframe_intervall, do a new seek or
+ continue reading
+ 3. adjust the audiostreams in such a way, that the
+ difference is not to high.
+
+ In short words, do all the cleanups necessary to continue playback
+ without further actions
+ */
+
+ this->send_newpts = 1;
+ this->status = DEMUX_OK;
+
+ if( !playing ) {
+
+ this->buf_flag_seek = 0;
+
+ } else {
+ if (start_pos!=0) {
+ this->buf_flag_seek = 1;
+ /*each stream has to continue with a packet that has an
+ granulepos*/
+ for (i=0; i<this->num_streams; i++) {
+ this->si[i]->resync = 1;
+ }
+
+ this->start_pts=-1;
+ }
+
+ _x_demux_flush_engine(this->stream);
+ }
+
+ return this->status;
+}
+
+static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) {
+
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+
+ if (this->time_length==-1){
+ if (this->avg_bitrate) {
+ return (int)((int64_t)1000 * this->input->get_length (this->input) * 8 /
+ this->avg_bitrate);
+ } else {
+ return 0;
+ }
+ } else {
+ return this->time_length;
+ }
+}
+
+static uint32_t demux_ogg_get_capabilities(demux_plugin_t *this_gen) {
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+ int cap_chapter = 0;
+
+ if (this->chapter_info)
+ cap_chapter = DEMUX_CAP_CHAPTERS;
+
+ return DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG | cap_chapter;
+}
+
+static int format_lang_string (demux_ogg_t * this, uint32_t buf_mask, uint32_t buf_type, int channel, char *str) {
+ int stream_num;
+
+ for (stream_num=0; stream_num<this->num_streams; stream_num++) {
+ if ((this->si[stream_num]->buf_types & buf_mask) == buf_type) {
+ if (this->si[stream_num]->language) {
+ if (snprintf (str, XINE_LANG_MAX, "%s", this->si[stream_num]->language) >= XINE_LANG_MAX)
+ /* the string got truncated */
+ str[XINE_LANG_MAX - 2] = str[XINE_LANG_MAX - 3] = str[XINE_LANG_MAX - 4] = '.';
+ /* TODO: provide long version in XINE_META_INFO_FULL_LANG */
+ } else {
+ snprintf(str, XINE_LANG_MAX, "channel %d",channel);
+ }
+ return DEMUX_OPTIONAL_SUCCESS;
+ }
+ }
+ return DEMUX_OPTIONAL_UNSUPPORTED;
+}
+
+static int demux_ogg_get_optional_data(demux_plugin_t *this_gen,
+ void *data, int data_type) {
+
+ demux_ogg_t *this = (demux_ogg_t *) this_gen;
+
+ char *str=(char *) data;
+ int channel = *((int *)data);
+
+ switch (data_type) {
+ case DEMUX_OPTIONAL_DATA_SPULANG:
+ lprintf ("DEMUX_OPTIONAL_DATA_SPULANG channel = %d\n",channel);
+ if (channel==-1) {
+ strcpy( str, "none");
+ return DEMUX_OPTIONAL_SUCCESS;
+ } else if ((channel>=0) && (channel<this->num_streams)) {
+ return format_lang_string (this, 0xFFFFFFFF, BUF_SPU_OGM+channel, channel, str);
+ }
+ return DEMUX_OPTIONAL_UNSUPPORTED;
+ case DEMUX_OPTIONAL_DATA_AUDIOLANG:
+ lprintf ("DEMUX_OPTIONAL_DATA_AUDIOLANG channel = %d\n",channel);
+ if (channel==-1) {
+ return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE, channel, str);
+ } else if ((channel>=0) && (channel<this->num_streams)) {
+ return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE+channel, channel, str);
+ }
+ return DEMUX_OPTIONAL_UNSUPPORTED;
+ default:
+ return DEMUX_OPTIONAL_UNSUPPORTED;
+ }
+}
+
+static int detect_ogg_content (int detection_method, demux_class_t *class_gen,
+ input_plugin_t *input) {
+
+ switch (detection_method) {
+
+ case METHOD_BY_CONTENT: {
+ uint32_t header;
+
+ if (_x_demux_read_header(input, &header, 4) != 4)
+ return 0;
+
+ return !!( header == ME_FOURCC('O', 'g', 'g', 'S') );
+ }
+
+ case METHOD_BY_MRL:
+ case METHOD_EXPLICIT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static int detect_anx_content (int detection_method, demux_class_t *class_gen,
+ input_plugin_t *input) {
+
+ if (detect_ogg_content(detection_method, class_gen, input) == 0)
+ return 0;
+
+ switch (detection_method) {
+
+#define ANNODEX_SIGNATURE_SEARCH 128
+
+ case METHOD_BY_CONTENT: {
+ uint8_t buf[ANNODEX_SIGNATURE_SEARCH];
+
+ if (_x_demux_read_header(input, buf, ANNODEX_SIGNATURE_SEARCH) !=
+ ANNODEX_SIGNATURE_SEARCH)
+ return 0;
+
+ /* scan for 'Annodex' signature in the first 64 bytes */
+ return !!memmem(buf, ANNODEX_SIGNATURE_SEARCH,
+ "Annodex", sizeof("Annodex")-1);
+ }
+
+#undef ANNODEX_SIGNATURE_SEARCH
+
+ case METHOD_BY_MRL:
+ case METHOD_EXPLICIT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen,
+ xine_stream_t *stream,
+ input_plugin_t *input) {
+
+ demux_ogg_t *this;
+
+ if (detect_anx_content(stream->content_detection_method, class_gen, input) == 0)
+ return NULL;
+
+ /*
+ * if we reach this point, the input has been accepted.
+ */
+
+ this = xine_xmalloc (sizeof (demux_ogg_t));
+ memset (this, 0, sizeof(demux_ogg_t));
+ this->stream = stream;
+ this->input = input;
+
+ /* the Annodex demuxer currently calls into exactly the same functions as
+ * the Ogg demuxer, which seems to make this function a bit redundant, but
+ * this design leaves us a bit more room to change an Annodex demuxer's
+ * behaviour in the future if necessary */
+ this->demux_plugin.send_headers = demux_ogg_send_headers;
+ this->demux_plugin.send_chunk = demux_ogg_send_chunk;
+ this->demux_plugin.seek = demux_ogg_seek;
+ this->demux_plugin.dispose = demux_ogg_dispose;
+ this->demux_plugin.get_status = demux_ogg_get_status;
+ this->demux_plugin.get_stream_length = demux_ogg_get_stream_length;
+ this->demux_plugin.get_capabilities = demux_ogg_get_capabilities;
+ this->demux_plugin.get_optional_data = demux_ogg_get_optional_data;
+ this->demux_plugin.demux_class = class_gen;
+
+ this->status = DEMUX_FINISHED;
+
+#ifdef HAVE_THEORA
+ theora_info_init (&this->t_info);
+ theora_comment_init (&this->t_comment);
+#endif
+
+ this->chapter_info = 0;
+ this->title = 0;
+ this->event_queue = xine_event_new_queue (this->stream);
+
+ return &this->demux_plugin;
+}
+
+static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen,
+ xine_stream_t *stream,
+ input_plugin_t *input) {
+
+ demux_ogg_t *this;
+
+ if (detect_ogg_content(stream->content_detection_method, class_gen, input) == 0)
+ return NULL;
+
+ /*
+ * if we reach this point, the input has been accepted.
+ */
+
+ this = xine_xmalloc (sizeof (demux_ogg_t));
+ memset (this, 0, sizeof(demux_ogg_t));
+ this->stream = stream;
+ this->input = input;
+
+ this->demux_plugin.send_headers = demux_ogg_send_headers;
+ this->demux_plugin.send_chunk = demux_ogg_send_chunk;
+ this->demux_plugin.seek = demux_ogg_seek;
+ this->demux_plugin.dispose = demux_ogg_dispose;
+ this->demux_plugin.get_status = demux_ogg_get_status;
+ this->demux_plugin.get_stream_length = demux_ogg_get_stream_length;
+ this->demux_plugin.get_capabilities = demux_ogg_get_capabilities;
+ this->demux_plugin.get_optional_data = demux_ogg_get_optional_data;
+ this->demux_plugin.demux_class = class_gen;
+
+ this->status = DEMUX_FINISHED;
+
+#ifdef HAVE_THEORA
+ theora_info_init (&this->t_info);
+ theora_comment_init (&this->t_comment);
+#endif
+
+ this->chapter_info = 0;
+ this->title = 0;
+ this->event_queue = xine_event_new_queue (this->stream);
+
+ return &this->demux_plugin;
+}
+
+/*
+ * Annodex demuxer class
+ */
+static void *anx_init_class (xine_t *xine, void *data) {
+ demux_anx_class_t *this;
+
+ this = xine_xmalloc (sizeof (demux_anx_class_t));
+
+ this->demux_class.open_plugin = anx_open_plugin;
+ this->demux_class.description = N_("Annodex demux plugin");
+ this->demux_class.identifier = "Annodex";
+ this->demux_class.mimetypes =
+ "application/annodex: anx: Annodex media;"
+ "application/x-annodex: anx: Annodex media;"
+ "audio/annodex: axa: Annodex audio;"
+ "audio/x-annodex: axa: Annodex audio;"
+ "video/annodex: axv: Annodex video;"
+ "video/x-annodex: axv: Annodex video;";
+ this->demux_class.extensions = "anx axa axv";
+ this->demux_class.dispose = default_demux_class_dispose;
+
+ return this;
+}
+
+/*
+ * ogg demuxer class
+ */
+static void *ogg_init_class (xine_t *xine, void *data) {
+ demux_ogg_class_t *this;
+
+ this = xine_xmalloc (sizeof (demux_ogg_class_t));
+
+ this->demux_class.open_plugin = ogg_open_plugin;
+ this->demux_class.description = N_("OGG demux plugin");
+ this->demux_class.identifier = "OGG";
+ this->demux_class.mimetypes =
+ "application/ogg: ogx: Ogg Stream;"
+ "application/x-ogg: ogx: Ogg Stream;"
+ "audio/ogg: oga: Ogg Audio;"
+ "audio/x-ogg: oga: Ogg Audio;"
+ "video/ogg: ogv: Ogg Video;";
+ "video/x-ogg: ogv: Ogg Video;";
+ this->demux_class.extensions = "ogx ogv oga ogg spx ogm";
+ this->demux_class.dispose = default_demux_class_dispose;
+
+ return this;
+}
+
+/*
+ * exported plugin catalog entry
+ */
+static const demuxer_info_t demux_info_anx = {
+ 20 /* priority */
+};
+
+static const demuxer_info_t demux_info_ogg = {
+ 10 /* priority */
+};
+
+extern const demuxer_info_t dec_info_vorbis;
+void *vorbis_init_plugin (xine_t *xine, void *data);
+extern const demuxer_info_t dec_info_speex;
+void *speex_init_plugin (xine_t *xine, void *data);
+extern const demuxer_info_t dec_info_theora;
+void *theora_init_plugin (xine_t *xine, void *data);
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_DEMUX, 27, "ogg", XINE_VERSION_CODE, &demux_info_ogg, ogg_init_class },
+ { PLUGIN_DEMUX, 27, "anx", XINE_VERSION_CODE, &demux_info_anx, anx_init_class },
+#ifdef HAVE_VORBIS
+ { PLUGIN_AUDIO_DECODER, 16, "vorbis", XINE_VERSION_CODE, &dec_info_vorbis, vorbis_init_plugin },
+#endif
+#ifdef HAVE_SPEEX
+ { PLUGIN_AUDIO_DECODER, 16, "speex", XINE_VERSION_CODE, &dec_info_speex, speex_init_plugin },
+#endif
+#ifdef HAVE_THEORA
+ { PLUGIN_VIDEO_DECODER, 19, "theora", XINE_VERSION_CODE, &dec_info_theora, theora_init_plugin },
+#endif
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/combined/xine_speex_decoder.c b/src/combined/xine_speex_decoder.c
new file mode 100644
index 000000000..865232e30
--- /dev/null
+++ b/src/combined/xine_speex_decoder.c
@@ -0,0 +1,398 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * (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/xine_internal.h>
+#include <xine/audio_out.h>
+#include <xine/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 const struct {
+ char key[16]; /* 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}
+};
+
+#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; i < (sizeof(speex_comment_keys)/sizeof(speex_comment_keys[0])); 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;
+ char *const buf_content = (char*)buf->content;
+
+ 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 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
+ */
+
+void *speex_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.identifier = "speex";
+ this->decoder_class.description = N_("Speex audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
+
+ return this;
+}
+
+static const uint32_t audio_types[] = {
+ BUF_AUDIO_SPEEX, 0
+ };
+
+const decoder_info_t dec_info_speex = {
+ audio_types, /* supported types */
+ 5 /* priority */
+};
diff --git a/src/combined/xine_theora_decoder.c b/src/combined/xine_theora_decoder.c
new file mode 100644
index 000000000..96d4ca8f0
--- /dev/null
+++ b/src/combined/xine_theora_decoder.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2001-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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * xine decoder plugin using libtheora
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <math.h>
+#include <assert.h>
+#include <theora/theora.h>
+
+#define LOG_MODULE "theora_decoder"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#include <xine/xine_internal.h>
+#include <xine/video_out.h>
+#include <xine/buffer.h>
+#include <xine/metronom.h>
+#include <xine/xineutils.h>
+
+typedef struct theora_class_s {
+ video_decoder_class_t decoder_class;
+} theora_class_t;
+
+typedef struct theora_decoder_s {
+ video_decoder_t theora_decoder;
+ theora_class_t *class;
+ theora_info t_info;
+ theora_comment t_comment;
+ theora_state t_state;
+ ogg_packet op;
+ yuv_buffer yuv;
+ xine_stream_t* stream;
+ int reject;
+ int op_max_size;
+ unsigned char* packet;
+ int done;
+ int width, height;
+ double ratio;
+ int offset_x, offset_y;
+ int frame_duration;
+ int skipframes;
+ int hp_read;
+ int initialized;
+} theora_decoder_t;
+
+static void readin_op (theora_decoder_t *this, unsigned char* src, int size) {
+ if ( this->done+size > this->op_max_size) {
+ while (this->op_max_size < this->done+size)
+ this->op_max_size=this->op_max_size*2;
+ this->packet=realloc(this->packet, this->op_max_size);
+ this->op.packet=this->packet;
+ }
+ xine_fast_memcpy ( this->packet+this->done, src, size);
+ this->done=this->done+size;
+}
+
+static void yuv2frame(yuv_buffer *yuv, vo_frame_t *frame, int offset_x, int offset_y) {
+ int i;
+ int crop_offset;
+
+ /* fixme - direct rendering (exchaning pointers) may be possible.
+ * frame->base[0] = yuv->y could work if one could change the
+ * pitches[0,1,2] values, and rely on the drawing routine using
+ * the new pitches. With cropping and offsets, it's a bit trickier,
+ * but it would still be possible.
+ * Attempts at doing this have yielded nothing but SIGSEVs so far.
+ */
+
+ /* Copy yuv data onto the frame. Cropping and offset as specified
+ * by the frame_width, frame_height, offset_x and offset_y fields
+ * in the theora header is carried out.
+ */
+
+ crop_offset=offset_x+yuv->y_stride*offset_y;
+ for(i=0;i<frame->height;i++)
+ xine_fast_memcpy(frame->base[0]+frame->pitches[0]*i,
+ yuv->y+crop_offset+yuv->y_stride*i,
+ frame->width);
+
+ crop_offset=(offset_x/2)+(yuv->uv_stride)*(offset_y/2);
+ for(i=0;i<frame->height/2;i++){
+ xine_fast_memcpy(frame->base[1]+frame->pitches[1]*i,
+ yuv->u+crop_offset+yuv->uv_stride*i,
+ frame->width/2);
+ xine_fast_memcpy(frame->base[2]+frame->pitches[2]*i,
+ yuv->v+crop_offset+yuv->uv_stride*i,
+ frame->width/2);
+
+ }
+}
+
+static int collect_data (theora_decoder_t *this, buf_element_t *buf ) {
+ /* Assembles an ogg_packet which was sent with send_ogg_packet over xinebuffers */
+ /* this->done, this->rejected, this->op and this->decoder->flags are needed*/
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_START) {
+ this->done=0; /*start from the beginnig*/
+ this->reject=0;/*new packet - new try*/
+
+ /*copy the ogg_packet struct and the sum, correct the adress of the packet*/
+ xine_fast_memcpy (&this->op, buf->content, sizeof(ogg_packet));
+ this->op.packet=this->packet;
+
+ readin_op (this, buf->content + sizeof(ogg_packet), buf->size - sizeof(ogg_packet) );
+ /*read the rest of the data*/
+
+ } else {
+ if (this->done==0 || this->reject) {
+ /*we are starting to collect an packet without the beginnig
+ reject the rest*/
+ printf ("libtheora: rejecting packet\n");
+ this->reject=1;
+ return 0;
+ }
+ readin_op (this, buf->content, buf->size );
+ }
+
+ if ((buf->decoder_flags & BUF_FLAG_FRAME_END) && !this->reject) {
+ if ( this->done != this->op.bytes ) {
+ printf ("libtheora: A packet changed its size during transfer - rejected\n");
+ printf (" size %d should be %ld\n", this->done , this->op.bytes);
+ this->op.bytes=this->done;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static void theora_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
+ /*
+ * decode data from buf and feed decoded frames to
+ * video output
+ */
+ theora_decoder_t *this = (theora_decoder_t *) this_gen;
+ vo_frame_t *frame;
+ yuv_buffer yuv;
+ int ret;
+
+ if (!collect_data(this, buf)) return;
+ /*return, until a entire packets is collected*/
+
+ if ( (buf->decoder_flags & BUF_FLAG_HEADER) &&
+ !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) {
+ /*get the first 3 packets and decode the header during preview*/
+
+ if (this->hp_read==0) {
+ /*decode first hp*/
+ if (theora_decode_header(&this->t_info, &this->t_comment, &this->op)>=0) {
+ this->hp_read++;
+ return;
+ }
+ }
+
+ if (this->hp_read==1) {
+ /*decode three header packets*/
+ if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) {
+ printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read);
+ } else {
+ this->hp_read++;
+ return;
+ }
+ }
+
+ if (this->hp_read==2) {
+ if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) {
+ printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read);
+ }
+ /*headers are now decoded. initialize the decoder*/
+ theora_decode_init (&this->t_state, &this->t_info);
+
+ lprintf("theora stream is Theora %dx%d %.02f fps video.\n"
+ " frame content is %dx%d with offset (%d,%d).\n"
+ " pixel aspect is %d:%d.\n",
+ this->t_info.width,this->t_info.height,
+ (double)this->t_info.fps_numerator/this->t_info.fps_denominator,
+ this->t_info.frame_width, this->t_info.frame_height,
+ this->t_info.offset_x, this->t_info.offset_y,
+ this->t_info.aspect_numerator, this->t_info.aspect_denominator);
+
+ this->frame_duration=((int64_t)90000*this->t_info.fps_denominator)/this->t_info.fps_numerator;
+ this->width=this->t_info.frame_width;
+ this->height=this->t_info.frame_height;
+ if (this->t_info.aspect_numerator==0 || this->t_info.aspect_denominator==0)
+ /* 0-values are undefined, so don't do any scaling. */
+ this->ratio=(double)this->width/(double)this->height;
+ else
+ /* Yes, this video needs to be scaled. */
+ this->ratio=(double)(this->width*this->t_info.aspect_numerator) /
+ (double)(this->height*this->t_info.aspect_denominator);
+ this->offset_x=this->t_info.offset_x;
+ this->offset_y=this->t_info.offset_y;
+ this->initialized=1;
+ this->hp_read++;
+ }
+
+ } else if (buf->decoder_flags & BUF_FLAG_HEADER) {
+ /*ignore headerpackets*/
+
+ return;
+
+ } else {
+ /*decode videodata*/
+
+ if (!this->initialized) {
+ printf ("libtheora: cannot decode stream without header\n");
+ return;
+ }
+
+ ret=theora_decode_packetin( &this->t_state, &this->op);
+
+ if ( ret!=0) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "libtheora:Received an bad packet\n");
+ } else if (!this->skipframes) {
+
+ theora_decode_YUVout(&this->t_state,&yuv);
+
+ /*fixme - aspectratio from theora is not considered*/
+ frame = this->stream->video_out->get_frame( this->stream->video_out,
+ this->width, this->height,
+ this->ratio,
+ XINE_IMGFMT_YV12,
+ VO_BOTH_FIELDS);
+ yuv2frame(&yuv, frame, this->offset_x, this->offset_y);
+
+ frame->pts = buf->pts;
+ frame->duration=this->frame_duration;
+ this->skipframes=frame->draw(frame, this->stream);
+ frame->free(frame);
+ } else {
+ this->skipframes=this->skipframes-1;
+ }
+ }
+}
+
+
+static void theora_flush (video_decoder_t *this_gen) {
+ /*
+ * flush out any frames that are still stored in the decoder
+ */
+ theora_decoder_t *this = (theora_decoder_t *) this_gen;
+ this->skipframes=0;
+}
+
+static void theora_reset (video_decoder_t *this_gen) {
+ /*
+ * reset decoder after engine flush (prepare for new
+ * video data not related to recently decoded data)
+ */
+ theora_decoder_t *this = (theora_decoder_t *) this_gen;
+ this->skipframes=0;
+}
+
+static void theora_discontinuity (video_decoder_t *this_gen) {
+ /*
+ * inform decoder that a time reference discontinuity has happened.
+ * that is, it must forget any currently held pts value
+ */
+ theora_decoder_t *this = (theora_decoder_t *) this_gen;
+ this->skipframes=0;
+}
+
+static void theora_dispose (video_decoder_t *this_gen) {
+ /*
+ * close down, free all resources
+ */
+
+ theora_decoder_t *this = (theora_decoder_t *) this_gen;
+
+ lprintf ("dispose \n");
+
+ theora_clear (&this->t_state);
+ theora_comment_clear (&this->t_comment);
+ theora_info_clear (&this->t_info);
+ this->stream->video_out->close(this->stream->video_out, this->stream);
+ free (this->packet);
+ free (this);
+}
+
+static video_decoder_t *theora_open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ /*
+ * open a new instance of this plugin class
+ */
+
+ theora_decoder_t *this ;
+
+ this = (theora_decoder_t *) xine_xmalloc (sizeof (theora_decoder_t));
+
+ this->theora_decoder.decode_data = theora_decode_data;
+ this->theora_decoder.flush = theora_flush;
+ this->theora_decoder.reset = theora_reset;
+ this->theora_decoder.discontinuity = theora_discontinuity;
+ this->theora_decoder.dispose = theora_dispose;
+
+ this->stream = stream;
+ this->class = (theora_class_t *) class_gen;
+
+ this->op_max_size = 4096;
+ this->packet = malloc(this->op_max_size);
+
+ this->done = 0;
+
+ this->stream = stream;
+
+ this->initialized = 0;
+
+ theora_comment_init (&this->t_comment);
+ theora_info_init (&this->t_info);
+ (stream->video_out->open) (stream->video_out, stream);
+
+ return &this->theora_decoder;
+
+}
+
+/*
+ * theora plugin class
+ */
+void *theora_init_plugin (xine_t *xine, void *data) {
+ /*initialize our plugin*/
+ theora_class_t *this;
+
+ this = (theora_class_t *) xine_xmalloc (sizeof (theora_class_t));
+
+ this->decoder_class.open_plugin = theora_open_plugin;
+ this->decoder_class.identifier = "theora video";
+ this->decoder_class.description = N_("theora video decoder plugin");
+ this->decoder_class.dispose = default_video_decoder_class_dispose;
+
+ return this;
+}
+
+/*
+ * exported plugin catalog entry
+ */
+
+static const uint32_t supported_types[] = { BUF_VIDEO_THEORA, 0 };
+
+const decoder_info_t dec_info_theora = {
+ supported_types, /* supported types */
+ 5 /* priority */
+};
diff --git a/src/combined/xine_vorbis_decoder.c b/src/combined/xine_vorbis_decoder.c
new file mode 100644
index 000000000..ad3a07188
--- /dev/null
+++ b/src/combined/xine_vorbis_decoder.c
@@ -0,0 +1,366 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * (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/xine_internal.h>
+#include <xine/audio_out.h>
+#include <xine/buffer.h>
+
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+
+#define MAX_NUM_SAMPLES 4096
+#define INIT_BUFSIZE 8192
+
+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;
+
+ /* data accumulation stuff */
+ unsigned char *buf;
+ int bufsize;
+ int size;
+
+} 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 ) return;
+ this->size = 0;
+
+ /* clear block first, as it might contain allocated data */
+ vorbis_block_clear(&this->vb);
+ 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_check_bufsize (vorbis_decoder_t *this, int size) {
+ if (size > this->bufsize) {
+ this->bufsize = size + size / 2;
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("vorbis: increasing buffer to %d to avoid overflow.\n"),
+ this->bufsize);
+ this->buf = realloc(this->buf, this->bufsize);
+ }
+}
+
+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) );
+
+ /* data accumulation */
+ vorbis_check_bufsize(this, this->size + buf->size);
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+ this->size += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+ this->op.packet = this->buf;
+ this->op.bytes = this->size;
+
+ /* reset accumultaion buffer */
+ this->size = 0;
+
+ 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((char *)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 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] + 1.0f) * 32768.f;
+ val -= 32768;
+ /* might as well guard against clipping */
+ if(val>32767){
+ val=32767;
+ } else if(val<-32768){
+ val=-32768;
+ }
+ *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);
+ }
+ } else {
+ 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;
+
+ this->bufsize = INIT_BUFSIZE;
+ this->buf = xine_xmalloc(INIT_BUFSIZE);
+ this->size = 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
+ */
+void *vorbis_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.identifier = "vorbis";
+ this->decoder_class.description = N_("vorbis audio decoder plugin");
+ this->decoder_class.dispose = default_audio_decoder_class_dispose;
+
+ return this;
+}
+
+static const uint32_t audio_types[] = {
+ BUF_AUDIO_VORBIS, 0
+ };
+
+const decoder_info_t dec_info_vorbis = {
+ audio_types, /* supported types */
+ 5 /* priority */
+};