diff options
Diffstat (limited to 'src/combined')
26 files changed, 4190 insertions, 1368 deletions
diff --git a/src/combined/Makefile.am b/src/combined/Makefile.am index 6a43fed47..cfb33d5ce 100644 --- a/src/combined/Makefile.am +++ b/src/combined/Makefile.am @@ -1,24 +1,68 @@ +include $(top_srcdir)/misc/Makefile.quiet +SUBDIRS = ffmpeg + include $(top_builddir)/misc/Makefile.plugins include $(top_srcdir)/misc/Makefile.common -SUBDIRS = ffmpeg +AM_CFLAGS = $(DEFAULT_OCFLAGS) $(VISIBILITY_FLAG) +AM_LDFLAGS = $(xineplug_ldflags) -if HAVE_WAVPACK +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_LTLIBRARIES = \ + $(xineplug_wavpack) \ + $(xineplug_flac) \ + $(xineplug_nsf) -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_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 index 24cab7577..773353096 100644 --- a/src/combined/ffmpeg/Makefile.am +++ b/src/combined/ffmpeg/Makefile.am @@ -1,74 +1,47 @@ +include $(top_srcdir)/misc/Makefile.quiet include $(top_builddir)/misc/Makefile.plugins include $(top_srcdir)/misc/Makefile.common -DEFAULT_INCLUDES = -I. +AM_CFLAGS = $(DEFAULT_OCFLAGS) $(VISIBILITY_FLAG) +AM_CPPFLAGS = $(ZLIB_CPPFLAGS) +AM_LDFLAGS = $(xineplug_ldflags) -if HAVE_FFMPEG -ff_cppflags = $(FFMPEG_CFLAGS) $(FFMPEG_POSTPROC_CFLAGS) -link_ffmpeg = $(FFMPEG_LIBS) $(FFMPEG_UTIL_LIBS) $(FFMPEG_POSTPROC_LIBS) -else -ff_cppflags = -I$(top_builddir)/src/libffmpeg -I$(top_srcdir)/src/libffmpeg/libavcodec -I$(top_srcdir)/src/libffmpeg/libavutil -link_ffmpeg = \ - $(top_builddir)/src/libffmpeg/libavcodec/libavcodec.la \ - $(top_builddir)/src/libffmpeg/libavutil/libavutil.la \ - $(top_builddir)/src/libffmpeg/libavcodec/libpostproc/libpostprocess.la -endif +xineplug_LTLIBRARIES = xineplug_decode_ff.la ff_generated = \ avcodec_video.list avcodec_audio.list \ ff_video_list.h ff_audio_list.h BUILT_SOURCES = $(ff_generated) +DISTCLEANFILES = $(ff_generated) -# ffmpeg_config.h is generated by configure -DISTCLEANFILES = ffmpeg_config.h $(ff_generated) +EXTRA_DIST = xine_video.list xine_audio.list mkcodeclist.pl -# this must always be included, even if the current machine has no DXR3... -EXTRA_DIST = ffmpeg_encoder.c \ - xine_video.list xine_audio.list mkcodeclist.pl - -xineplug_LTLIBRARIES = xineplug_decode_ff.la xineplug_decode_dvaudio.la - -if HAVE_DXR3 -AM_CPPFLAGS = -I$(top_srcdir)/src/dxr3 $(X_CFLAGS) $(ff_cppflags) \ - $(ZLIB_CPPFLAGS) -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 -AM_CPPFLAGS = $(ff_cppflags) $(ZLIB_CPPFLAGS) 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 -xineplug_decode_ff_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) -xineplug_decode_ff_la_LDFLAGS = $(xineplug_ldflags) $(IMPURE_TEXT_LDFLAGS) -xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \ - $(link_ffmpeg) $(PTHREAD_LIBS) $(LTLIBINTL) - -xineplug_decode_dvaudio_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) -xineplug_decode_dvaudio_la_LDFLAGS = $(xineplug_ldflags) -xineplug_decode_dvaudio_la_SOURCES = ff_dvaudio_decoder.c -xineplug_decode_dvaudio_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) +nodist_xineplug_decode_ff_la_SOURCES = ffmpeg_config.h -$(top_srcdir)/src/libffmpeg/libavcodec/libavcodec.la: - make -C $(top_srcdir)/src/libffmpeg +xineplug_decode_ff_la_CFLAGS = $(AM_CFLAGS) $(FFMPEG_CFLAGS) $(FFMPEG_POSTPROC_CFLAGS) +xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \ + $(FFMPEG_LIBS) $(AVUTIL_LIBS) $(FFMPEG_POSTPROC_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) +xineplug_decode_ff_la_LDFLAGS = $(AM_LDFLAGS) $(IMPURE_TEXT_LDFLAGS) # Generation of ffmpeg->xine codec mapping lists (see xine_*.list). -AV_CPP = $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) +AV_CPP = $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AVUTIL_CFLAGS) # Extract some CODEC_ID_* from avcodec.h. Requires some sed mangling. avcodec_audio.list: AV_CODECS:=/CODEC_ID_PCM_S16LE/,/CODEC_ID_DVD_SUBTITLE/ avcodec_video.list: AV_CODECS:=/CODEC_ID_MPEG1VIDEO/,/CODEC_ID_PCM_S16LE/ avcodec_audio.list avcodec_video.list: - echo '#include "$(srcdir)/ffmpeg_decoder.h"' | $(AV_CPP) - |\ + $(AM_V_GEN)echo '#include "$(srcdir)/ffmpeg_decoder.h"' | $(AV_CPP) - |\ sed -e $(AV_CODECS)'! d; s/^[ \t]*//; s/[=,].*//; /^$$/ d' >$@ # Generate the mappings. These are #included where needed. ff_%_list.h: $(srcdir)/mkcodeclist.pl avcodec_%.list $(srcdir)/xine_%.list - $(PERL) $^ $@ + $(AM_V_GEN)$(PERL) $^ $@ ff_audio_decoder.c: ff_audio_list.h ff_video_decoder.c: ff_video_list.h diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index e4a9c16bf..a45d57c69 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -22,7 +22,6 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#include "../../libffmpeg/ffmpeg_config.h" #endif #include <stdlib.h> @@ -38,9 +37,9 @@ #define LOG */ -#include "xine_internal.h" -#include "buffer.h" -#include "xineutils.h" +#include <xine/xine_internal.h> +#include <xine/buffer.h> +#include <xine/xineutils.h> #include "bswap.h" #include "ffmpeg_decoder.h" @@ -653,18 +652,6 @@ static audio_decoder_t *ff_audio_open_plugin (audio_decoder_class_t *class_gen, return &this->audio_decoder; } -static char *ff_audio_get_identifier (audio_decoder_class_t *this) { - return "ffmpeg audio"; -} - -static char *ff_audio_get_description (audio_decoder_class_t *this) { - return "ffmpeg based audio decoder plugin"; -} - -static void ff_audio_dispose_class (audio_decoder_class_t *this) { - free (this); -} - void *init_audio_plugin (xine_t *xine, void *data) { ff_audio_class_t *this ; @@ -672,9 +659,9 @@ void *init_audio_plugin (xine_t *xine, void *data) { this = calloc(1, sizeof (ff_audio_class_t)); this->decoder_class.open_plugin = ff_audio_open_plugin; - this->decoder_class.get_identifier = ff_audio_get_identifier; - this->decoder_class.get_description = ff_audio_get_description; - this->decoder_class.dispose = ff_audio_dispose_class; + 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 ); diff --git a/src/combined/ffmpeg/ff_dvaudio_decoder.c b/src/combined/ffmpeg/ff_dvaudio_decoder.c deleted file mode 100644 index 4d78162df..000000000 --- a/src/combined/ffmpeg/ff_dvaudio_decoder.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * 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_internal.h" -#include "buffer.h" -#include "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 - -#ifdef HAVE_FFMPEG_AVUTIL_H -# include <avcodec.h> -#elif defined HAVE_FFMPEG -# include <libavcodec/avcodec.h> -#else -# include "../../libffmpeg/libavcodec/avcodec.h" -#endif - -#include "../../libffmpeg/libavcodec/dvdata.h" - -#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 = calloc(1, AUDIOBUFSIZE); - this->bufsize = AUDIOBUFSIZE; - this->size = 0; - this->decode_buffer = calloc(1, 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 = calloc(1, 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 char *dvaudio_get_identifier (audio_decoder_class_t *this) { - return "dv audio"; -} - -static char *dvaudio_get_description (audio_decoder_class_t *this) { - return "dv audio decoder plugin"; -} - -static void dvaudio_dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_dvaudio_plugin (xine_t *xine, void *data) { - - dvaudio_class_t *this ; - - this = calloc(1, sizeof (dvaudio_class_t)); - - this->decoder_class.open_plugin = dvaudio_open_plugin; - this->decoder_class.get_identifier = dvaudio_get_identifier; - this->decoder_class.get_description = dvaudio_get_description; - this->decoder_class.dispose = dvaudio_dispose_class; - - 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, 15, "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.h b/src/combined/ffmpeg/ff_mpeg_parser.h index 5797933df..c1ebc326f 100644 --- a/src/combined/ffmpeg/ff_mpeg_parser.h +++ b/src/combined/ffmpeg/ff_mpeg_parser.h @@ -23,7 +23,7 @@ #ifndef HAVE_MPEG_PARSER_H #define HAVE_MPEG_PARSER_H -#include "xine_internal.h" +#include <xine/xine_internal.h> #include "ffmpeg_decoder.h" #define BUFFER_SIZE (1194 * 1024) /* libmpeg2's buffer size */ diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index a1d729df4..c75848bee 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -22,7 +22,6 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#include "../../libffmpeg/ffmpeg_config.h" #endif #include <stdlib.h> @@ -38,10 +37,10 @@ /* #define LOG */ -#include "xine_internal.h" +#include <xine/xine_internal.h> #include "bswap.h" -#include "buffer.h" -#include "xineutils.h" +#include <xine/buffer.h> +#include <xine/xineutils.h> #include "ffmpeg_decoder.h" #include "ff_mpeg_parser.h" @@ -70,12 +69,6 @@ # define DEPRECATED_AVCODEC_THREAD_INIT 1 #endif -/* reordered_opaque appeared in libavcodec 51.68.0 */ -#define AVCODEC_HAS_REORDERED_OPAQUE -#if LIBAVCODEC_VERSION_INT < 0x334400 -# undef AVCODEC_HAS_REORDERED_OPAQUE -#endif - typedef struct ff_video_decoder_s ff_video_decoder_t; typedef struct ff_video_class_s { @@ -96,12 +89,10 @@ struct ff_video_decoder_s { xine_stream_t *stream; int64_t pts; -#ifdef AVCODEC_HAS_REORDERED_OPAQUE uint64_t pts_tag_mask; uint64_t pts_tag; int pts_tag_counter; int pts_tag_stable_counter; -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ int video_step; int reported_video_step; @@ -237,10 +228,8 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){ av_frame->type= FF_BUFFER_TYPE_USER; -#ifdef AVCODEC_HAS_REORDERED_OPAQUE /* take over pts for this frame to have it reordered */ av_frame->reordered_opaque = context->reordered_opaque; -#endif xine_list_push_back(this->dr1_frames, av_frame); @@ -1225,7 +1214,6 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu } } -#ifdef AVCODEC_HAS_REORDERED_OPAQUE static uint64_t ff_tag_pts(ff_video_decoder_t *this, uint64_t pts) { return pts | this->pts_tag; @@ -1271,7 +1259,6 @@ static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts) } } } -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { uint8_t *chunk_buf = this->buf; @@ -1300,7 +1287,6 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { this->size = 0; } -#ifdef AVCODEC_HAS_REORDERED_OPAQUE if (this->size == 0) { /* take over pts when we are about to buffer a frame */ this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts); @@ -1308,7 +1294,6 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { this->context->reordered_opaque = ff_tag_pts(this, this->pts); this->pts = 0; } -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ /* data accumulation */ if (buf->size > 0) { @@ -1375,10 +1360,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { &got_picture, &chunk_buf[offset], this->size); #endif -#ifdef AVCODEC_HAS_REORDERED_OPAQUE /* reset consumed pts value */ this->context->reordered_opaque = ff_tag_pts(this, 0); -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ lprintf("consumed size: %d, got_picture: %d\n", len, got_picture); if ((len <= 0) || (len > this->size)) { @@ -1396,12 +1379,10 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { memmove (this->buf, &chunk_buf[offset], this->size); chunk_buf = this->buf; -#ifdef AVCODEC_HAS_REORDERED_OPAQUE /* take over pts for next access unit */ this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts); this->context->reordered_opaque = ff_tag_pts(this, this->pts); this->pts = 0; -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ } } } @@ -1410,11 +1391,7 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { video_step_to_use = (this->video_step || !this->context->time_base.den) ? this->video_step : (int)(90000ll -#if LIBAVCODEC_VERSION_INT >= 0x341400 * this->context->ticks_per_frame -#elif LIBAVCODEC_VERSION_INT >= 0x340000 -# warning Building without avcodec ticks_per_frame support; you should upgrade your libavcodec and recompile -#endif * this->context->time_base.num / this->context->time_base.den); /* aspect ratio provided by ffmpeg, override previous setting */ @@ -1504,14 +1481,9 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { ff_convert_frame(this, img); } -#ifndef AVCODEC_HAS_REORDERED_OPAQUE - img->pts = this->pts; - this->pts = 0; -#else /* AVCODEC_HAS_REORDERED_OPAQUE */ img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque); ff_check_pts_tagging(this, this->av_frame->reordered_opaque); /* only check for valid frames */ this->av_frame->reordered_opaque = 0; -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ /* workaround for weird 120fps streams */ if( video_step_to_use == 750 ) { @@ -1554,13 +1526,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { this->output_format, VO_BOTH_FIELDS|this->frame_flags); /* set PTS to allow early syncing */ -#ifndef AVCODEC_HAS_REORDERED_OPAQUE - img->pts = this->pts; - this->pts = 0; -#else /* AVCODEC_HAS_REORDERED_OPAQUE */ img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque); this->av_frame->reordered_opaque = 0; -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ img->duration = video_step_to_use; @@ -1614,6 +1581,8 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { } } else { + if (this->decoder_init_mode && !this->is_mpeg12) + ff_handle_preview_buffer(this, buf); /* decode */ if (buf->pts) @@ -1646,12 +1615,10 @@ static void ff_reset (video_decoder_t *this_gen) { if (this->is_mpeg12) mpeg_parser_reset(this->mpeg_parser); -#ifdef AVCODEC_HAS_REORDERED_OPAQUE this->pts_tag_mask = 0; this->pts_tag = 0; this->pts_tag_counter = 0; this->pts_tag_stable_counter = 0; -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ } static void ff_discontinuity (video_decoder_t *this_gen) { @@ -1660,7 +1627,6 @@ static void ff_discontinuity (video_decoder_t *this_gen) { lprintf ("ff_discontinuity\n"); this->pts = 0; -#ifdef AVCODEC_HAS_REORDERED_OPAQUE /* * there is currently no way to reset all the pts which are stored in the decoder. * therefore, we add a unique tag (generated from pts_tag_counter) to pts (see @@ -1693,7 +1659,6 @@ static void ff_discontinuity (video_decoder_t *this_gen) { counter_mask <<= 1; } } -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ } static void ff_dispose (video_decoder_t *this_gen) { @@ -1799,18 +1764,6 @@ static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen, return &this->video_decoder; } -static char *ff_video_get_identifier (video_decoder_class_t *this) { - return "ffmpeg video"; -} - -static char *ff_video_get_description (video_decoder_class_t *this) { - return "ffmpeg based video decoder plugin"; -} - -static void ff_video_dispose_class (video_decoder_class_t *this) { - free (this); -} - void *init_video_plugin (xine_t *xine, void *data) { ff_video_class_t *this; @@ -1819,9 +1772,9 @@ void *init_video_plugin (xine_t *xine, void *data) { this = calloc(1, sizeof (ff_video_class_t)); this->decoder_class.open_plugin = ff_video_open_plugin; - this->decoder_class.get_identifier = ff_video_get_identifier; - this->decoder_class.get_description = ff_video_get_description; - this->decoder_class.dispose = ff_video_dispose_class; + 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 ); @@ -1870,12 +1823,12 @@ void *init_video_plugin (xine_t *xine, void *data) { return this; } -static uint32_t wmv8_video_types[] = { +static const uint32_t wmv8_video_types[] = { BUF_VIDEO_WMV8, 0 }; -static uint32_t wmv9_video_types[] = { +static const uint32_t wmv9_video_types[] = { BUF_VIDEO_WMV9, 0 }; diff --git a/src/combined/ffmpeg/ffmpeg_decoder.c b/src/combined/ffmpeg/ffmpeg_decoder.c index b50633053..4f9a0f7a4 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.c +++ b/src/combined/ffmpeg/ffmpeg_decoder.c @@ -22,10 +22,9 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#include "../../libffmpeg/ffmpeg_config.h" #endif -#include "xine_internal.h" +#include <xine/xine_internal.h> #include "ffmpeg_decoder.h" @@ -36,279 +35,6 @@ pthread_once_t once_control = PTHREAD_ONCE_INIT; pthread_mutex_t ffmpeg_lock; -#ifndef HAVE_FFMPEG - -#define REGISTER_ENCODER(X,x) \ - if(ENABLE_##X##_ENCODER) register_avcodec(&x##_encoder) -#define REGISTER_DECODER(X,x) \ - if(ENABLE_##X##_DECODER) register_avcodec(&x##_decoder) -#define REGISTER_ENCDEC(X,x) REGISTER_ENCODER(X,x); REGISTER_DECODER(X,x) - -#define REGISTER_PARSER(X,x) \ - if(ENABLE_##X##_PARSER) av_register_codec_parser(&x##_parser) - -/* If you do not call this function, then you can select exactly which - formats you want to support */ - -/** - * simple call to register all the codecs. - */ -void avcodec_register_all(void) -{ - static int inited = 0; - - if (inited != 0) - return; - inited = 1; - - /* video codecs */ - REGISTER_DECODER(AASC, aasc); - REGISTER_ENCDEC (ASV1, asv1); - REGISTER_ENCDEC (ASV2, asv2); - REGISTER_DECODER(AVS, avs); - REGISTER_DECODER(BMP, bmp); - REGISTER_DECODER(CAVS, cavs); - REGISTER_DECODER(CINEPAK, cinepak); - REGISTER_DECODER(CLJR, cljr); - REGISTER_DECODER(CSCD, cscd); - REGISTER_DECODER(CYUV, cyuv); - REGISTER_DECODER(DSICINVIDEO, dsicinvideo); - REGISTER_ENCDEC (DVVIDEO, dvvideo); - REGISTER_DECODER(EIGHTBPS, eightbps); - REGISTER_ENCDEC (FFV1, ffv1); - REGISTER_ENCDEC (FFVHUFF, ffvhuff); - REGISTER_DECODER(FLASHSV, flashsv); - REGISTER_DECODER(FLIC, flic); - REGISTER_ENCDEC (FLV, flv); - REGISTER_DECODER(FOURXM, fourxm); - REGISTER_DECODER(FRAPS, fraps); - REGISTER_ENCDEC (GIF, gif); - REGISTER_ENCDEC (H261, h261); - REGISTER_ENCDEC (H263, h263); - REGISTER_DECODER(H263I, h263i); - REGISTER_ENCODER(H263P, h263p); - REGISTER_DECODER(H264, h264); - REGISTER_ENCDEC (HUFFYUV, huffyuv); - REGISTER_DECODER(IDCIN, idcin); - REGISTER_DECODER(INDEO2, indeo2); - REGISTER_DECODER(INDEO3, indeo3); - REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video); - REGISTER_ENCODER(JPEGLS, jpegls); - REGISTER_DECODER(KMVC, kmvc); - REGISTER_ENCODER(LJPEG, ljpeg); - REGISTER_DECODER(LOCO, loco); - REGISTER_DECODER(MDEC, mdec); - REGISTER_ENCDEC (MJPEG, mjpeg); - REGISTER_DECODER(MJPEGB, mjpegb); - REGISTER_DECODER(MMVIDEO, mmvideo); -#ifdef HAVE_XVMC - REGISTER_DECODER(MPEG_XVMC, mpeg_xvmc); -#endif - REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video); - REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video); - REGISTER_ENCDEC (MPEG4, mpeg4); - REGISTER_DECODER(MPEGVIDEO, mpegvideo); - REGISTER_ENCDEC (MSMPEG4V1, msmpeg4v1); - REGISTER_ENCDEC (MSMPEG4V2, msmpeg4v2); - REGISTER_ENCDEC (MSMPEG4V3, msmpeg4v3); - REGISTER_DECODER(MSRLE, msrle); - REGISTER_DECODER(MSVIDEO1, msvideo1); - REGISTER_DECODER(MSZH, mszh); - REGISTER_DECODER(NUV, nuv); - REGISTER_ENCODER(PAM, pam); - REGISTER_ENCODER(PBM, pbm); - REGISTER_ENCODER(PGM, pgm); - REGISTER_ENCODER(PGMYUV, pgmyuv); -#ifdef CONFIG_ZLIB - REGISTER_ENCDEC (PNG, png); -#endif - REGISTER_ENCODER(PPM, ppm); - REGISTER_DECODER(QDRAW, qdraw); - REGISTER_DECODER(QPEG, qpeg); - REGISTER_DECODER(QTRLE, qtrle); - REGISTER_ENCDEC (RAWVIDEO, rawvideo); - REGISTER_DECODER(ROQ, roq); - REGISTER_DECODER(RPZA, rpza); - REGISTER_ENCDEC (RV10, rv10); - REGISTER_ENCDEC (RV20, rv20); - REGISTER_DECODER(SMACKER, smacker); - REGISTER_DECODER(SMC, smc); - REGISTER_ENCDEC (SNOW, snow); - REGISTER_DECODER(SP5X, sp5x); - REGISTER_ENCDEC (SVQ1, svq1); - REGISTER_DECODER(SVQ3, svq3); - REGISTER_DECODER(TARGA, targa); - REGISTER_DECODER(THEORA, theora); - REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo); - REGISTER_DECODER(TIFF, tiff); - REGISTER_DECODER(TRUEMOTION1, truemotion1); - REGISTER_DECODER(TRUEMOTION2, truemotion2); - REGISTER_DECODER(TSCC, tscc); - REGISTER_DECODER(ULTI, ulti); - REGISTER_DECODER(VC1, vc1); - REGISTER_DECODER(VCR1, vcr1); - REGISTER_DECODER(VMDVIDEO, vmdvideo); - REGISTER_DECODER(VMNC, vmnc); - REGISTER_DECODER(VP3, vp3); - REGISTER_DECODER(VP5, vp5); - REGISTER_DECODER(VP6, vp6); - REGISTER_DECODER(VP6F, vp6f); - REGISTER_DECODER(VQA, vqa); - REGISTER_ENCDEC (WMV1, wmv1); - REGISTER_ENCDEC (WMV2, wmv2); - REGISTER_DECODER(WMV3, wmv3); - REGISTER_DECODER(WNV1, wnv1); -#ifdef CONFIG_X264 - REGISTER_ENCODER(X264, x264); -#endif - REGISTER_DECODER(XAN_WC3, xan_wc3); - REGISTER_DECODER(XL, xl); -#ifdef CONFIG_XVID - REGISTER_ENCODER(XVID, xvid); -#endif - REGISTER_ENCDEC (ZLIB, zlib); -#ifdef CONFIG_ZLIB - REGISTER_ENCDEC (ZMBV, zmbv); -#endif - - /* audio codecs */ -#ifdef CONFIG_LIBFAAD - REGISTER_DECODER(AAC, aac); - REGISTER_DECODER(MPEG4AAC, mpeg4aac); -#endif -#ifdef CONFIG_LIBA52 - REGISTER_DECODER(AC3, ac3); -#endif - REGISTER_ENCODER(AC3, ac3); -#ifdef CODEC_ID_EAC3 - REGISTER_DECODER(EAC3, eac3); -#endif - REGISTER_DECODER(ALAC, alac); -#if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED) - REGISTER_ENCDEC (AMR_NB, amr_nb); -#endif -#ifdef CONFIG_AMR_WB - REGISTER_ENCDEC (AMR_WB, amr_wb); -#endif - REGISTER_DECODER(COOK, cook); - REGISTER_DECODER(DSICINAUDIO, dsicinaudio); -#ifdef CONFIG_LIBDTS - REGISTER_DECODER(DTS, dts); -#endif -#ifdef CONFIG_LIBFAAC - REGISTER_ENCODER(FAAC, faac); -#endif - REGISTER_ENCDEC (FLAC, flac); - REGISTER_DECODER(IMC, imc); -#ifdef CONFIG_LIBGSM - REGISTER_ENCDEC (LIBGSM, libgsm); -#endif - REGISTER_DECODER(MACE3, mace3); - REGISTER_DECODER(MACE6, mace6); - REGISTER_ENCDEC (MP2, mp2); - REGISTER_DECODER(MP3, mp3); - REGISTER_DECODER(MP3ADU, mp3adu); -#ifdef CONFIG_LIBMP3LAME - REGISTER_ENCODER(MP3LAME, mp3lame); -#endif - REGISTER_DECODER(MP3ON4, mp3on4); - REGISTER_DECODER(MPC7, mpc7); -#ifdef CONFIG_LIBVORBIS - if (!ENABLE_VORBIS_ENCODER) REGISTER_ENCODER(OGGVORBIS, oggvorbis); - if (!ENABLE_VORBIS_DECODER) REGISTER_DECODER(OGGVORBIS, oggvorbis); -#endif - REGISTER_DECODER(QDM2, qdm2); - REGISTER_DECODER(RA_144, ra_144); - REGISTER_DECODER(RA_288, ra_288); - REGISTER_DECODER(SHORTEN, shorten); - REGISTER_DECODER(SMACKAUD, smackaud); - REGISTER_ENCDEC (SONIC, sonic); - REGISTER_ENCODER(SONIC_LS, sonic_ls); - REGISTER_DECODER(TRUESPEECH, truespeech); - REGISTER_DECODER(TTA, tta); - REGISTER_DECODER(VMDAUDIO, vmdaudio); - REGISTER_ENCDEC (VORBIS, vorbis); - REGISTER_DECODER(WAVPACK, wavpack); - REGISTER_DECODER(WMAV1, wmav1); - REGISTER_DECODER(WMAV2, wmav2); - REGISTER_DECODER(WS_SND1, ws_snd1); - - /* pcm codecs */ - REGISTER_ENCDEC (PCM_ALAW, pcm_alaw); - REGISTER_ENCDEC (PCM_MULAW, pcm_mulaw); - REGISTER_ENCDEC (PCM_S8, pcm_s8); - REGISTER_ENCDEC (PCM_S16BE, pcm_s16be); - REGISTER_ENCDEC (PCM_S16LE, pcm_s16le); - REGISTER_ENCDEC (PCM_S24BE, pcm_s24be); - REGISTER_ENCDEC (PCM_S24DAUD, pcm_s24daud); - REGISTER_ENCDEC (PCM_S24LE, pcm_s24le); - REGISTER_ENCDEC (PCM_S32BE, pcm_s32be); - REGISTER_ENCDEC (PCM_S32LE, pcm_s32le); - REGISTER_ENCDEC (PCM_U8, pcm_u8); - REGISTER_ENCDEC (PCM_U16BE, pcm_u16be); - REGISTER_ENCDEC (PCM_U16LE, pcm_u16le); - REGISTER_ENCDEC (PCM_U24BE, pcm_u24be); - REGISTER_ENCDEC (PCM_U24LE, pcm_u24le); - REGISTER_ENCDEC (PCM_U32BE, pcm_u32be); - REGISTER_ENCDEC (PCM_U32LE, pcm_u32le); - - /* dpcm codecs */ - REGISTER_DECODER(INTERPLAY_DPCM, interplay_dpcm); - REGISTER_DECODER(ROQ_DPCM, roq_dpcm); - REGISTER_DECODER(SOL_DPCM, sol_dpcm); - REGISTER_DECODER(XAN_DPCM, xan_dpcm); - - /* adpcm codecs */ - REGISTER_ENCDEC (ADPCM_4XM, adpcm_4xm); - REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx); - REGISTER_ENCDEC (ADPCM_CT, adpcm_ct); - REGISTER_ENCDEC (ADPCM_EA, adpcm_ea); - REGISTER_ENCDEC (ADPCM_G726, adpcm_g726); - REGISTER_ENCDEC (ADPCM_IMA_DK3, adpcm_ima_dk3); - REGISTER_ENCDEC (ADPCM_IMA_DK4, adpcm_ima_dk4); - REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt); - REGISTER_ENCDEC (ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); - REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav); - REGISTER_ENCDEC (ADPCM_IMA_WS, adpcm_ima_ws); - REGISTER_ENCDEC (ADPCM_MS, adpcm_ms); - REGISTER_ENCDEC (ADPCM_SBPRO_2, adpcm_sbpro_2); - REGISTER_ENCDEC (ADPCM_SBPRO_3, adpcm_sbpro_3); - REGISTER_ENCDEC (ADPCM_SBPRO_4, adpcm_sbpro_4); - REGISTER_ENCDEC (ADPCM_SWF, adpcm_swf); - REGISTER_ENCDEC (ADPCM_XA, adpcm_xa); - REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha); - - /* subtitles */ - REGISTER_ENCDEC (DVBSUB, dvbsub); - REGISTER_ENCDEC (DVDSUB, dvdsub); - - /* parsers */ - REGISTER_PARSER (AAC, aac); - REGISTER_PARSER (AC3, ac3); - REGISTER_PARSER (CAVSVIDEO, cavsvideo); - REGISTER_PARSER (DVBSUB, dvbsub); - REGISTER_PARSER (DVDSUB, dvdsub); - REGISTER_PARSER (H261, h261); - REGISTER_PARSER (H263, h263); - REGISTER_PARSER (H264, h264); - REGISTER_PARSER (MJPEG, mjpeg); - REGISTER_PARSER (MPEG4VIDEO, mpeg4video); - REGISTER_PARSER (MPEGAUDIO, mpegaudio); - REGISTER_PARSER (MPEGVIDEO, mpegvideo); - REGISTER_PARSER (PNM, pnm); - - /* - av_register_bitstream_filter(&dump_extradata_bsf); - av_register_bitstream_filter(&remove_extradata_bsf); - av_register_bitstream_filter(&noise_bsf); - av_register_bitstream_filter(&mp3_header_compress_bsf); - av_register_bitstream_filter(&mp3_header_decompress_bsf); - av_register_bitstream_filter(&mjpega_dump_header_bsf); - */ -} - -#endif - void init_once_routine(void) { pthread_mutex_init(&ffmpeg_lock, NULL); avcodec_init(); @@ -321,9 +47,9 @@ void init_once_routine(void) { const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_VIDEO_DECODER | PLUGIN_MUST_PRELOAD, 18, "ffmpegvideo", XINE_VERSION_CODE, &dec_info_ffmpeg_video, init_video_plugin }, - { PLUGIN_VIDEO_DECODER, 18, "ffmpeg-wmv8", XINE_VERSION_CODE, &dec_info_ffmpeg_wmv8, init_video_plugin }, - { PLUGIN_VIDEO_DECODER, 18, "ffmpeg-wmv9", XINE_VERSION_CODE, &dec_info_ffmpeg_wmv9, init_video_plugin }, - { PLUGIN_AUDIO_DECODER, 15, "ffmpegaudio", XINE_VERSION_CODE, &dec_info_ffmpeg_audio, init_audio_plugin }, + { 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 index 0aeb71271..f679a5ce9 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.h +++ b/src/combined/ffmpeg/ffmpeg_decoder.h @@ -27,10 +27,8 @@ #ifdef HAVE_FFMPEG_AVUTIL_H # include <avcodec.h> -#elif defined HAVE_FFMPEG -# include <libavcodec/avcodec.h> #else -# include "../../libffmpeg/libavcodec/avcodec.h" +# include <libavcodec/avcodec.h> #endif #if LIBAVCODEC_VERSION_MAJOR > 51 diff --git a/src/combined/ffmpeg/ffmpeg_encoder.c b/src/combined/ffmpeg/ffmpeg_encoder.c deleted file mode 100644 index d41023675..000000000 --- a/src/combined/ffmpeg/ffmpeg_encoder.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * 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" - -#ifdef HAVE_FFMPEG_AVUTIL_H -# include <avcodec.h> -#elif defined HAVE_FFMPEG -# include <libavcodec/avcodec.h> -#else -# include "../../libffmpeg/libavcodec/avcodec.h" -#endif - -/* 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 = calloc(1, 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/ffmpeg/mkcodeclist.pl b/src/combined/ffmpeg/mkcodeclist.pl index b4a10921a..311d147af 100755 --- a/src/combined/ffmpeg/mkcodeclist.pl +++ b/src/combined/ffmpeg/mkcodeclist.pl @@ -38,9 +38,9 @@ while (defined ($line = <LIST>)) { $Type = $type; $Type =~ tr/a-z/A-Z/; } elsif (substr ($line, 0, 7) eq 'config=') { - # "#ifdef CONFIG_FOO_DECODER" mappings + # avcodec minimum version mappings ($a, $f, $t) = split (/=/, $line, 3); - $config{$f} = $t; + $config{$f} = $t if $t =~ /^\d+,\d+,\d+$/ } else { # codec details push @known, [split (/\s+/, $line, 3)]; @@ -63,6 +63,7 @@ my $w = ($out ne '-'); if ($w) { # Write the C source code for the codec lists open LIST, "> $out" or die $!; + print LIST "#ifndef AV_VERSION_INT\n# define AV_VERSION_INT(a,b,c) 0x7FFFFFFF\n#endif\n" or die $!; print LIST "static const ff_codec_t ff_${type}_lookup[] = {\n" or die $!; foreach $line (@known) { next if $line->[0] eq '!'; @@ -73,12 +74,12 @@ if ($w) { foreach $line (@known) { next if $line->[0] eq '!'; next unless defined $codecs{$line->[1]}; - $a = $line->[1]; + $a = ''; $a = $config{$a} if defined $config{$a}; if ($a eq '') { print LIST " BUF_${Type}_$line->[0],\n" or die $!; } else { - print LIST " #ifdef CONFIG_${a}_DECODER\n BUF_${Type}_$line->[0],\n #endif\n" or die $!; + print LIST " #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT($a)\n BUF_${Type}_$line->[0],\n #endif\n" or die $!; } } print LIST " 0,\n};\n" or die $!; diff --git a/src/combined/ffmpeg/xine_audio.list b/src/combined/ffmpeg/xine_audio.list index 0ebbfbda6..8a40c29cb 100644 --- a/src/combined/ffmpeg/xine_audio.list +++ b/src/combined/ffmpeg/xine_audio.list @@ -1,5 +1,4 @@ type=audio -config=MP3ADU= # xine-lib BUF_AUDIO_ ffmpeg CODEC_ID_ description or comment # ("!"=ignore) (quote any "s) diff --git a/src/combined/ffmpeg/xine_video.list b/src/combined/ffmpeg/xine_video.list index bd1238d6f..009f4dafd 100644 --- a/src/combined/ffmpeg/xine_video.list +++ b/src/combined/ffmpeg/xine_video.list @@ -1,7 +1,4 @@ type=video -config=VP6F=VP6 -config=FLV1=FLV -config=THEORA= # xine-lib BUF_VIDEO_ ffmpeg CODEC_ID_ description or comment # ("!"=ignore) (quote any "s) diff --git a/src/combined/decoder_flac.c b/src/combined/flac_decoder.c index fe1822797..1572fd2be 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; /* @@ -261,22 +253,19 @@ 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) { - const int bits = this->bits_per_sample; + const int bits = bits_per_sample; this->output_open = (this->stream->audio_out->open) ( this->stream->audio_out, this->stream, bits > 16 ? 16 : bits, - this->sample_rate, + sample_rate, mode); } this->buf_pos = 0; @@ -401,19 +390,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; @@ -421,15 +397,17 @@ init_plugin (xine_t *xine, void *data) { this = calloc(1, 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 }; @@ -440,7 +418,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 9c5f7de32..0685631c7 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: { - const 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 const char * -get_description (demux_class_t *this_gen) { - return "FLAC demux plugin"; -} - -static const char * -get_identifier (demux_class_t *this_gen) { - return "FLAC"; -} - -static const char * -get_extensions (demux_class_t *this_gen) { - return "flac"; -} - -static const 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..c4c19f48a --- /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 d9e09e34a..4376ecf7a 100644 --- a/src/combined/demux_flac.h +++ b/src/combined/nsf_combined.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003 the xine project + * Copyright (C) 2000-2001 the xine project * * This file is part of xine, a free video player. * @@ -18,9 +18,5 @@ * 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..36f7f2990 --- /dev/null +++ b/src/combined/nsf_decoder.c @@ -0,0 +1,251 @@ +/* + * 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/ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#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 = calloc(1, 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 *) calloc(1, 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 *) calloc(1, 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..2081d13b8 --- /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 = calloc(1, 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 = calloc(1, 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 5e4f47342..8fe241d27 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 3cfa78509..87358169b 100644 --- a/src/combined/combined_wavpack.h +++ b/src/combined/wavpack_combined.h @@ -20,8 +20,9 @@ * xine interface to libwavpack by Diego Pettenò <flameeyes@gmail.com> */ -#include "os_types.h" -#include "attributes.h" +#include <xine/os_types.h> +#include <xine/attributes.h> +#include "bswap.h" typedef struct { uint32_t idcode; /* This should always be the string "wvpk" */ @@ -38,11 +39,7 @@ typedef struct { uint32_t decoded_crc32; /* CRC32 of the decoded data */ } 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 21dc0dbd1..253180cf2 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; @@ -105,6 +105,8 @@ static int xine_buffer_set_pos_rel(void *const this_gen, const int32_t delta, default: return -1; } + + return -1; } static int xine_buffer_set_pos_abs(void *const this_gen, const uint32_t pos) { @@ -312,27 +314,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 = calloc(1, 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 94a23acdc..a4cec9e56 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 wvp"; -} - -static const char *get_mimetypes (demux_class_t *const this_gen) { - return "audio/x-wavpack: wv,wvp: WavPack audio;"; -} - -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 = calloc(1, 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: wv,wvp: WavPack audio;"; + this->demux_class.extensions = "wv wvp"; + 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..e297339df --- /dev/null +++ b/src/combined/xine_ogg_demuxer.c @@ -0,0 +1,2247 @@ +/* + * 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 *meta[XINE_STREAM_INFO_MAX]; + 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 *)calloc(1, 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; + const size_t op_size = sizeof(ogg_packet); + + while (done<todo) { + size_t 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; +} + + +#define OGG_META(TAG,APPEND) { #TAG"=", XINE_META_INFO_##TAG, APPEND } +#define OGG_META_L(TAG,APPEND,META) { #TAG"=", XINE_META_INFO_##META, APPEND } +static const struct ogg_meta { + char tag[16]; + int meta; + int append; +} metadata[] = { + OGG_META (ALBUM, 0), + OGG_META (ARTIST, 0), + OGG_META (PUBLISHER, 0), + OGG_META (COPYRIGHT, 0), + OGG_META (DISCNUMBER, 0), + OGG_META (LICENSE, 0), + OGG_META (TITLE, 0), + OGG_META_L (TRACKNUMBER, 0, TRACK_NUMBER), + OGG_META (COMPOSER, 1), + OGG_META (ARRANGER, 1), + OGG_META (LYRICIST, 1), + OGG_META (AUTHOR, 1), + OGG_META (CONDUCTOR, 1), + OGG_META (PERFORMER, 1), + OGG_META (ENSEMBLE, 1), + OGG_META (OPUS, 0), + OGG_META (PART, 0), + OGG_META (PARTNUMBER, 0), + OGG_META (GENRE, 1), + OGG_META_L (DATE, 1, YEAR), /* hmm... */ + OGG_META (LOCATION, 0), + OGG_META (COMMENT, 0), +}; + +#if 0 +/* ensure that those marked "append" are cleared */ +/* FIXME: is this useful? Should they be cleared on first write? */ +static void prepare_read_comments (demux_ogg_t *this) +{ + int i; + + for (i = 0; i < sizeof (metadata) / sizeof (struct ogg_meta); ++i) + if (metadata[i].append) { + free (this->meta[metadata[i].meta]); + this->meta[metadata[i].meta] = NULL; + } +} +#endif + +static int read_comments (demux_ogg_t *this, const char *comment) +{ + int i; + + for (i = 0; i < sizeof (metadata) / sizeof (struct ogg_meta); ++i) { + size_t ml = strlen (metadata[i].tag); + if (!strncasecmp (metadata[i].tag, comment, ml) && comment[ml]) { + if (metadata[i].append && this->meta[metadata[i].meta]) { + char *newstr; + if (asprintf (&newstr, "%s\n%s", this->meta[metadata[i].meta], comment + ml) >= 0) { + free (this->meta[metadata[i].meta]); + this->meta[metadata[i].meta] = newstr; + } + } + else { + free (this->meta[metadata[i].meta]); + this->meta[metadata[i].meta] = strdup (comment + ml); + } + _x_meta_info_set_utf8(this->stream, metadata[i].meta, this->meta[metadata[i].meta]); + return 1; + } + } + return 0; +} + +/* + * utility function to read a LANGUAGE= line from the user_comments, + * to label audio and spu streams + * utility function to read CHAPTER*=, TITLE= etc. from the user_comments, + * to name (parts of) the stream + */ +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=") ); + } + else + read_comments (this, comment); + } + } + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); +#endif +} + +/* + * utility function to read CHAPTER*= from the user_comments, + * to name parts of the stream + */ +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 (read_comments (this, comment)) + continue; + + 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 *)calloc(1, 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; + } + } + } + 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_ui_data_t data = { + .str = { 0, }, + .str_len = 0 + }; + xine_event_t uevent = { + .type = XINE_EVENT_UI_SET_TITLE, + .stream = this->stream, + .data = &data, + .data_length = sizeof(data) + }; + + this->chapter_info->current_chapter = chapter; + + if (chapter >= 0) { + if (this->meta[XINE_META_INFO_TITLE]) { + data.str_len = snprintf(data.str, sizeof(data.str), "%s / %s", this->meta[XINE_META_INFO_TITLE], this->chapter_info->entries[chapter].name); + } else { + strncpy(data.str, this->chapter_info->entries[chapter].name, sizeof(data.str)-1); + } + } else { + strncpy(data.str, this->meta[XINE_META_INFO_TITLE], sizeof(data.str)); + } + if ( data.str_len == 0 ) + data.str_len = strlen(data.str); + + _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, data.str); + lprintf("new TITLE: %s\n", data.str); + + 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; + const char *content_type = ""; + size_t content_type_length = 0; + + 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-Type" MIME header */ + const char *startline = &op->packet[28]; + const char *endline; + if ( strcmp(&op->packet[28], "Content-Type: ") == 0 && + (endline = strstr(startline, "\r\n")) ) { + content_type = startline + sizeof("Content-Type: "); + content_type_length = startline - endline; + } + + lprintf("Content-Type: %s (length:%td)\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) || !this->og.header || !this->og.body) { + 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; + } + + if (!this->og.header || !this->og.body) { + 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); + } + for (i = 0; i < XINE_STREAM_INFO_MAX; ++i) + free (this->meta[i]); + + 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; + int i; + + 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 = calloc(1, 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 + + for (i = 0; i < XINE_STREAM_INFO_MAX; ++i) + this->meta[i] = NULL; + this->chapter_info = 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; + int i; + + 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 = calloc(1, 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; + for (i = 0; i < XINE_STREAM_INFO_MAX; ++i) + this->meta[i] = NULL; + 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 = calloc(1, 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 = calloc(1, 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-ogm: ogx: Ogg Stream;" + "application/x-ogm-audio: oga: Ogg Audio;" + "application/x-ogm-video: ogv: Ogg Video;" + "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..acdf5e394 --- /dev/null +++ b/src/combined/xine_speex_decoder.c @@ -0,0 +1,404 @@ +/* + * 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++) { + size_t keylen = strlen(speex_comment_keys[i].key); + + if ( !strncasecmp (speex_comment_keys[i].key, c, + keylen) ) { + char meta_info[(len - keylen) + 1]; + + lprintf ("known metadata %d %d\n", + i, speex_comment_keys[i].xine_metainfo_index); + + strncpy(meta_info, &c[keylen], len-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; + unsigned 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 = (unsigned int)spx_header->mode; + if (modeID >= SPEEX_NB_MODES) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": invalid mode ID %u\n", modeID); + return; + } + + 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 *) calloc(1, 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 *) calloc(1, 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..fbea502ca --- /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 *) calloc(1, 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 *) calloc(1, 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..9864177d6 --- /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 *) calloc(1, 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 = calloc(1, 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 *) calloc(1, 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 */ +}; |