diff options
Diffstat (limited to 'src/combined')
23 files changed, 4352 insertions, 785 deletions
| diff --git a/src/combined/Makefile.am b/src/combined/Makefile.am index 03250ef67..92d49a3e5 100644 --- a/src/combined/Makefile.am +++ b/src/combined/Makefile.am @@ -1,23 +1,66 @@ +SUBDIRS = ffmpeg +  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 3c78fa9d3..3f8f6fa26 100644 --- a/src/combined/ffmpeg/Makefile.am +++ b/src/combined/ffmpeg/Makefile.am @@ -1,47 +1,60 @@  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) +if WITH_EXTERNAL_FFMPEG +AM_CPPFLAGS += $(FFMPEG_CFLAGS) $(FFMPEG_POSTPROC_CFLAGS)  link_ffmpeg = $(FFMPEG_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 +AM_CPPFLAGS += -I$(top_srcdir)/contrib/ffmpeg +link_ffmpeg = $(top_builddir)/contrib/ffmpeg/libavcodec/libavcodec.a \ +	$(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a \ +	$(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a + +$(top_builddir)/contrib/ffmpeg/libavcodec/libavcodec.a: +	$(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libavcodec/libavcodec.a + +$(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a: +	$(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libavutil/libavutil.a + +$(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a: +	$(MAKE) -C $(top_builddir)/contrib/ ffmpeg/libpostproc/libpostproc.a + +$(top_builddir)/contrib/ffmpeg/config.h: +	$(MAKE) -C $(top_builddir)/contrib/ ffmpeg/config.mak -# ffmpeg_config.h is generated by configure -DISTCLEANFILES = ffmpeg_config.h +ffmpeg_config.h: $(top_builddir)/contrib/ffmpeg/config.h +	cp $(top_builddir)/contrib/ffmpeg/config.h ffmpeg_config.h + +BUILT_SOURCES = ffmpeg_config.h +CLEANFILES    = $(BUILT_SOURCES) + +endif  # this must always be included, even if the current machine has no DXR3...  EXTRA_DIST = ffmpeg_encoder.c  xineplug_LTLIBRARIES = xineplug_decode_ff.la xineplug_decode_dvaudio.la -if HAVE_DXR3 -AM_CPPFLAGS = -I$(top_srcdir)/src/dxr3 $(X_CFLAGS) $(ff_cppflags) \ -              $(ZLIB_CPPFLAGS) +if ENABLE_DXR3 +AM_CFLAGS   += $(X_CFLAGS) +AM_CPPFLAGS += -I$(top_srcdir)/src/dxr3  xineplug_decode_ff_la_SOURCES = ffmpeg_decoder.c ff_audio_decoder.c ff_video_decoder.c \                                  ffmpeg_encoder.c ff_mpeg_parser.c ffmpeg_decoder.h \  				ff_mpeg_parser.h  else -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) +nodist_xineplug_decode_ff_la_SOURCES = ffmpeg_config.h +  xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \  	$(link_ffmpeg) $(PTHREAD_LIBS) $(LTLIBINTL) +xineplug_decode_ff_la_LDFLAGS = $(AM_LDFLAGS) $(IMPURE_TEXT_LDFLAGS) -xineplug_decode_dvaudio_la_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) - -$(top_srcdir)/src/libffmpeg/libavcodec/libavcodec.la: -	make -C $(top_srcdir)/src/libffmpeg +xineplug_decode_dvaudio_la_SOURCES  = ff_dvaudio_decoder.c +xineplug_decode_dvaudio_la_LIBADD   = $(XINE_LIB) $(LTLIBINTL) +xineplug_decode_dvaudio_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/contrib/ffmpeg -I$(top_srcdir)/contrib/ffmpeg/libavutil diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 042900867..2b42cfb33 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -22,7 +22,9 @@  #ifdef HAVE_CONFIG_H  #include "config.h" -#include "../../libffmpeg/ffmpeg_config.h" +# ifndef HAVE_FFMPEG +#  include "ffmpeg_config.h" +# endif  #endif  #include <stdlib.h> @@ -38,9 +40,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" @@ -470,18 +472,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 ; @@ -489,115 +479,115 @@ void *init_audio_plugin (xine_t *xine, void *data) {    this = (ff_audio_class_t *) xine_xmalloc (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 );    return this;  } -static uint32_t supported_audio_types[] = {  -  #ifdef CONFIG_WMAV1_DECODER +static const uint32_t supported_audio_types[] = {  +#if defined(HAVE_FFMPEG) || CONFIG_WMAV1_DECODER    BUF_AUDIO_WMAV1, -  #endif -  #ifdef CONFIG_WMAV2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WMAV2_DECODER    BUF_AUDIO_WMAV2, -  #endif -  #ifdef CONFIG_RA_144_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_RA_144_DECODER    BUF_AUDIO_14_4, -  #endif -  #ifdef CONFIG_RA_288_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_RA_288_DECODER    BUF_AUDIO_28_8, -  #endif -  #ifdef CONFIG_MP3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MP3_DECODER    BUF_AUDIO_MPEG, -  #endif -  #ifdef CONFIG_ADPCM_MS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_MS_DECODER    BUF_AUDIO_MSADPCM, -  #endif -  #ifdef CONFIG_ADPCM_IMA_QT_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_QT_DECODER    BUF_AUDIO_QTIMAADPCM, -  #endif -  #ifdef CONFIG_ADPCM_IMA_WAV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_WAV_DECODER    BUF_AUDIO_MSIMAADPCM, -  #endif -  #ifdef CONFIG_ADPCM_IMA_DK3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_DK3_DECODER    BUF_AUDIO_DK3ADPCM, -  #endif -  #ifdef CONFIG_ADPCM_IMA_DK4_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_DK4_DECODER    BUF_AUDIO_DK4ADPCM, -  #endif -  #ifdef CONFIG_ADPCM_IMA_WS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_WS_DECODER    BUF_AUDIO_VQA_IMA, -  #endif -  #ifdef CONFIG_ADPCM_IMA_SMJPEG_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_IMA_SMJPEG_DECODER    BUF_AUDIO_SMJPEG_IMA, -  #endif -  #ifdef CONFIG_ADPCM_XA_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_XA_DECODER    BUF_AUDIO_XA_ADPCM, -  #endif -  #ifdef CONFIG_ADPCM_4XM_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_4XM_DECODER    BUF_AUDIO_4X_ADPCM, -  #endif -  #ifdef CONFIG_ADPCM_EA_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_EA_DECODER    BUF_AUDIO_EA_ADPCM, -  #endif -  #ifdef CONFIG_PCM_MULAW_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_PCM_MULAW_DECODER    BUF_AUDIO_MULAW, -  #endif -  #ifdef CONFIG_PCM_ALAW_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_PCM_ALAW_DECODER    BUF_AUDIO_ALAW, -  #endif -  #ifdef CONFIG_ROQ_DPCM_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ROQ_DPCM_DECODER    BUF_AUDIO_ROQ, -  #endif -  #ifdef CONFIG_INTERPLAY_DPCM_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_INTERPLAY_DPCM_DECODER    BUF_AUDIO_INTERPLAY, -  #endif -  #ifdef CONFIG_MACE3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MACE3_DECODER    BUF_AUDIO_MAC3, -  #endif -  #ifdef CONFIG_MACE6_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MACE6_DECODER    BUF_AUDIO_MAC6, -  #endif -  #ifdef CONFIG_XAN_DPCM_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_XAN_DPCM_DECODER    BUF_AUDIO_XAN_DPCM, -  #endif -  #ifdef CONFIG_VMDAUDIO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VMDAUDIO_DECODER    BUF_AUDIO_VMD, -  #endif -  #ifdef CONFIG_FLAC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_FLAC_DECODER    BUF_AUDIO_FLAC, -  #endif -  #ifdef CONFIG_SHORTEN_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SHORTEN_DECODER    BUF_AUDIO_SHORTEN, -  #endif -  #ifdef CONFIG_ALAC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ALAC_DECODER    BUF_AUDIO_ALAC, -  #endif -  #ifdef CONFIG_QDM2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_QDM2_DECODER    BUF_AUDIO_QDESIGN2, -  #endif -  #ifdef CONFIG_COOK_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_COOK_DECODER    BUF_AUDIO_COOK, -  #endif -  #ifdef CONFIG_TRUESPEECH_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_TRUESPEECH_DECODER    BUF_AUDIO_TRUESPEECH, -  #endif -  #ifdef CONFIG_TTA_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_TTA_DECODER    BUF_AUDIO_TTA, -  #endif -  #ifdef CONFIG_SMACKAUDIO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SMACKAUDIO_DECODER    BUF_AUDIO_SMACKER, -  #endif -  #ifdef CONFIG_ADPCM_SWF_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ADPCM_SWF_DECODER    BUF_AUDIO_FLVADPCM, -  #endif -  #ifdef CONFIG_WAVPACK_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WAVPACK_DECODER    BUF_AUDIO_WAVPACK, -  #endif +#endif    0  }; diff --git a/src/combined/ffmpeg/ff_dvaudio_decoder.c b/src/combined/ffmpeg/ff_dvaudio_decoder.c index 4704c1a2a..ef70d117b 100644 --- a/src/combined/ffmpeg/ff_dvaudio_decoder.c +++ b/src/combined/ffmpeg/ff_dvaudio_decoder.c @@ -36,9 +36,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>  #ifdef _MSC_VER  /* ffmpeg has own definitions of those types */ @@ -54,13 +54,15 @@  #ifdef HAVE_FFMPEG_AVUTIL_H  #  include <avcodec.h> -#elif defined HAVE_FFMPEG -#  include <libavcodec/avcodec.h> +#  include <rational.h> +#  define FFMPEG_AVCODEC_H +#  define FFMPEG_RATIONAL_H +#  define av_unused  #else -#  include "../../libffmpeg/libavcodec/avcodec.h" +#  include <libavcodec/avcodec.h>  #endif -#include "../../libffmpeg/libavcodec/dvdata.h" +#include <libavcodec/dvdata.h> /* This is not installed by FFmpeg, its usage has to be cleared up */  #ifdef _MSC_VER  #  undef malloc @@ -95,7 +97,6 @@ typedef struct dvaudio_decoder_s {  } 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 @@ -385,18 +386,6 @@ static audio_decoder_t *dvaudio_open_plugin (audio_decoder_class_t *class_gen, x    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 ; @@ -404,9 +393,9 @@ static void *init_dvaudio_plugin (xine_t *xine, void *data) {    this = (dvaudio_class_t *) xine_xmalloc (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; +  this->decoder_class.identifier      = "dv audio"; +  this->decoder_class.description     = N_("dv audio decoder plugin"); +  this->decoder_class.dispose         = default_audio_decoder_class_dispose;    return this;  } @@ -427,6 +416,6 @@ static const decoder_info_t dec_info_dvaudio = {  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_AUDIO_DECODER, 16, "dvaudio", XINE_VERSION_CODE, &dec_info_dvaudio, init_dvaudio_plugin },    { PLUGIN_NONE, 0, "", 0, NULL, NULL }  }; diff --git a/src/combined/ffmpeg/ff_mpeg_parser.h b/src/combined/ffmpeg/ff_mpeg_parser.h index ea43a6ce4..504e746f9 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 02282990b..10b326d45 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -22,7 +22,9 @@  #ifdef HAVE_CONFIG_H  #include "config.h" -#include "../../libffmpeg/ffmpeg_config.h" +# ifndef HAVE_FFMPEG +#  include "ffmpeg_config.h" +# endif  #endif  #include <stdlib.h> @@ -38,10 +40,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" @@ -1584,18 +1586,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; @@ -1604,9 +1594,9 @@ void *init_video_plugin (xine_t *xine, void *data) {    this = (ff_video_class_t *) xine_xmalloc (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 ); @@ -1655,240 +1645,240 @@ void *init_video_plugin (xine_t *xine, void *data) {    return this;  } -static uint32_t supported_video_types[] = {  -  #ifdef CONFIG_MSMPEG4V1_DECODER +static const uint32_t supported_video_types[] = {  +#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V1_DECODER    BUF_VIDEO_MSMPEG4_V1, -  #endif -  #ifdef CONFIG_MSMPEG4V2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V2_DECODER    BUF_VIDEO_MSMPEG4_V2, -  #endif -  #ifdef CONFIG_MSMPEG4V3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MSMPEG4V3_DECODER    BUF_VIDEO_MSMPEG4_V3, -  #endif -  #ifdef CONFIG_WMV1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WMV1_DECODER    BUF_VIDEO_WMV7, -  #endif -  #ifdef CONFIG_WMV2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WMV2_DECODER    BUF_VIDEO_WMV8, -  #endif -  #ifdef CONFIG_WMV3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WMV3_DECODER    BUF_VIDEO_WMV9, -  #endif -  #ifdef CONFIG_VC1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VC1_DECODER    BUF_VIDEO_VC1, -  #endif -  #ifdef CONFIG_MPEG4_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER    BUF_VIDEO_MPEG4, -  #endif -  #ifdef CONFIG_MPEG4_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER    BUF_VIDEO_XVID, -  #endif -  #ifdef CONFIG_MPEG4_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER    BUF_VIDEO_DIVX5, -  #endif -  #ifdef CONFIG_MPEG4_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MPEG4_DECODER    BUF_VIDEO_3IVX, -  #endif -  #ifdef CONFIG_MJPEG_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MJPEG_DECODER    BUF_VIDEO_JPEG, -  #endif -  #ifdef CONFIG_MJPEG_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MJPEG_DECODER    BUF_VIDEO_MJPEG, -  #endif -  #ifdef CONFIG_MJPEGB_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MJPEGB_DECODER    BUF_VIDEO_MJPEG_B, -  #endif -  #ifdef CONFIG_H263I_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_H263I_DECODER    BUF_VIDEO_I263, -  #endif -  #ifdef CONFIG_H263_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_H263_DECODER    BUF_VIDEO_H263, -  #endif -  #ifdef CONFIG_RV10_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_RV10_DECODER    BUF_VIDEO_RV10, -  #endif -  #ifdef CONFIG_RV20_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_RV20_DECODER    BUF_VIDEO_RV20, -  #endif -  #ifdef CONFIG_INDEO3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_INDEO3_DECODER    BUF_VIDEO_IV31, -  #endif -  #ifdef CONFIG_INDEO3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_INDEO3_DECODER    BUF_VIDEO_IV32, -  #endif -  #ifdef CONFIG_SVQ1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SVQ1_DECODER    BUF_VIDEO_SORENSON_V1, -  #endif -  #ifdef CONFIG_SVQ3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SVQ3_DECODER    BUF_VIDEO_SORENSON_V3, -  #endif -  #ifdef CONFIG_DVVIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_DVVIDEO_DECODER    BUF_VIDEO_DV, -  #endif -  #ifdef CONFIG_HUFFYUV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_HUFFYUV_DECODER    BUF_VIDEO_HUFFYUV, -  #endif -  #ifdef CONFIG_VP3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VP3_DECODER    BUF_VIDEO_VP31, -  #endif -  #ifdef CONFIG_VP5_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VP5_DECODER    BUF_VIDEO_VP5, -  #endif -  #ifdef CONFIG_VP6_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VP6_DECODER    BUF_VIDEO_VP6,    BUF_VIDEO_VP6F, -  #endif -  #ifdef CONFIG_4XM_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_4XM_DECODER    BUF_VIDEO_4XM, -  #endif -  #ifdef CONFIG_CINEPAK_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_CINEPAK_DECODER    BUF_VIDEO_CINEPAK, -  #endif -  #ifdef CONFIG_MSVIDEO1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MSVIDEO1_DECODER    BUF_VIDEO_MSVC, -  #endif -  #ifdef CONFIG_MSRLE_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MSRLE_DECODER    BUF_VIDEO_MSRLE, -  #endif -  #ifdef CONFIG_RPZA_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_RPZA_DECODER    BUF_VIDEO_RPZA, -  #endif -  #ifdef CONFIG_CYUV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_CYUV_DECODER    BUF_VIDEO_CYUV, -  #endif -  #ifdef CONFIG_ROQ_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ROQ_DECODER    BUF_VIDEO_ROQ, -  #endif -  #ifdef CONFIG_IDCIN_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_IDCIN_DECODER    BUF_VIDEO_IDCIN, -  #endif -  #ifdef CONFIG_XAN_WC3_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_XAN_WC3_DECODER    BUF_VIDEO_WC3, -  #endif -  #ifdef CONFIG_WS_VQA_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WS_VQA_DECODER    BUF_VIDEO_VQA, -  #endif -  #ifdef CONFIG_INTERPLAY_VIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_INTERPLAY_VIDEO_DECODER    BUF_VIDEO_INTERPLAY, -  #endif -  #ifdef CONFIG_FLIC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_FLIC_DECODER    BUF_VIDEO_FLI, -  #endif -  #ifdef CONFIG_8BPS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_8BPS_DECODER    BUF_VIDEO_8BPS, -  #endif -  #ifdef CONFIG_SMC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SMC_DECODER    BUF_VIDEO_SMC, -  #endif -  #ifdef CONFIG_TRUEMOTION1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_TRUEMOTION1_DECODER    BUF_VIDEO_DUCKTM1, -  #endif -  #ifdef CONFIG_TRUEMOTION2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_TRUEMOTION2_DECODER    BUF_VIDEO_DUCKTM2, -  #endif -  #ifdef CONFIG_VMDVIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VMDVIDEO_DECODER    BUF_VIDEO_VMD, -  #endif -  #ifdef CONFIG_ZLIB_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ZLIB_DECODER    BUF_VIDEO_ZLIB, -  #endif -  #ifdef CONFIG_MSZH_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MSZH_DECODER    BUF_VIDEO_MSZH, -  #endif -  #ifdef CONFIG_ASV1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ASV1_DECODER    BUF_VIDEO_ASV1, -  #endif -  #ifdef CONFIG_ASV2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ASV2_DECODER    BUF_VIDEO_ASV2, -  #endif -  #ifdef CONFIG_VCR1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VCR1_DECODER    BUF_VIDEO_ATIVCR1, -  #endif -  #ifdef CONFIG_FLV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_FLV_DECODER    BUF_VIDEO_FLV1, -  #endif -  #ifdef CONFIG_QTRLE_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_QTRLE_DECODER    BUF_VIDEO_QTRLE, -  #endif -  #ifdef CONFIG_H264_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_H264_DECODER    BUF_VIDEO_H264, -  #endif -  #ifdef CONFIG_H261_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_H261_DECODER    BUF_VIDEO_H261, -  #endif -  #ifdef CONFIG_AASC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_AASC_DECODER    BUF_VIDEO_AASC, -  #endif -  #ifdef CONFIG_LOCO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_LOCO_DECODER    BUF_VIDEO_LOCO, -  #endif -  #ifdef CONFIG_QDRAW_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_QDRAW_DECODER    BUF_VIDEO_QDRW, -  #endif -  #ifdef CONFIG_QPEG_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_QPEG_DECODER    BUF_VIDEO_QPEG, -  #endif -  #ifdef CONFIG_TSCC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_TSCC_DECODER    BUF_VIDEO_TSCC, -  #endif -  #ifdef CONFIG_ULTI_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ULTI_DECODER    BUF_VIDEO_ULTI, -  #endif -  #ifdef CONFIG_WNV1_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_WNV1_DECODER    BUF_VIDEO_WNV1, -  #endif -  #ifdef CONFIG_VIXL_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VIXL_DECODER    BUF_VIDEO_XL, -  #endif -  #ifdef CONFIG_INDEO2_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_INDEO2_DECODER    BUF_VIDEO_RT21, -  #endif -  #ifdef CONFIG_FRAPS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_FRAPS_DECODER    BUF_VIDEO_FPS1, -  #endif -  #ifdef CONFIG_MPEG1VIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MPEG1VIDEO_DECODER    BUF_VIDEO_MPEG, -  #endif -  #ifdef CONFIG_CSCD_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_CSCD_DECODER    BUF_VIDEO_CSCD, -  #endif -  #ifdef CONFIG_AVS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_AVS_DECODER    BUF_VIDEO_AVS, -  #endif -  #ifdef CONFIG_MMVIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_MMVIDEO_DECODER    BUF_VIDEO_ALGMM, -  #endif -  #ifdef CONFIG_ZMBV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_ZMBV_DECODER    BUF_VIDEO_ZMBV, -  #endif -  #ifdef CONFIG_SMACKVIDEO_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_SMACKVIDEO_DECODER    BUF_VIDEO_SMACKER, -  #endif -  #ifdef CONFIG_NUV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_NUV_DECODER    BUF_VIDEO_NUV, -  #endif -  #ifdef CONFIG_KMVC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_KMVC_DECODER    BUF_VIDEO_KMVC, -  #endif -  #ifdef CONFIG_FLASHSV_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_FLASHSV_DECODER    BUF_VIDEO_FLASHSV, -  #endif -  #ifdef CONFIG_CAVS_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_CAVS_DECODER    BUF_VIDEO_CAVS, -  #endif -  #ifdef CONFIG_VMNC_DECODER +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VMNC_DECODER    BUF_VIDEO_VMNC, -  #endif +#endif    BUF_VIDEO_THEORA_RAW,    0   }; -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 776e07df9..8a8a79270 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,276 +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); -    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(); @@ -318,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 f47421253..6de9e8772 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  typedef struct ff_codec_s { diff --git a/src/combined/ffmpeg/ffmpeg_encoder.c b/src/combined/ffmpeg/ffmpeg_encoder.c index 2d1be10a3..c1e3d2823 100644 --- a/src/combined/ffmpeg/ffmpeg_encoder.c +++ b/src/combined/ffmpeg/ffmpeg_encoder.c @@ -40,10 +40,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  /* buffer size for encoded mpeg1 stream; will hold one intra frame  diff --git a/src/combined/decoder_flac.c b/src/combined/flac_decoder.c index 2230056cd..43bad327e 100644 --- a/src/combined/decoder_flac.c +++ b/src/combined/flac_decoder.c @@ -44,11 +44,9 @@  #define LOG  */ -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" - -#include "demux_flac.h" +#include <xine/xine_internal.h> +#include <xine/audio_out.h> +#include <xine/buffer.h>  typedef struct {    audio_decoder_class_t   decoder_class; @@ -59,23 +57,17 @@ typedef struct flac_decoder_s {    int64_t           pts; -  int               output_sampling_rate; -  int               output_open; -  int               output_mode; -    xine_stream_t    *stream;    FLAC__StreamDecoder *flac_decoder; -  int sample_rate; -  int bits_per_sample; -  int channels; -    unsigned char *buf;    int            buf_size;    int            buf_pos;    int            min_size; +  int            output_open; +  } flac_decoder_t;  /* @@ -249,21 +241,18 @@ flac_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)       */      if (buf->decoder_flags & BUF_FLAG_STDHEADER)      { -        int mode = AO_CAP_MODE_MONO; - -        this->sample_rate     = buf->decoder_info[1]; -        this->bits_per_sample = buf->decoder_info[2]; -        this->channels        = buf->decoder_info[3]; - -	mode = _x_ao_channels2mode(this->channels); +        const int sample_rate     = buf->decoder_info[1]; +        const int bits_per_sample = buf->decoder_info[2]; +        const int channels        = buf->decoder_info[3]; +        const int mode            = _x_ao_channels2mode(channels);          if (!this->output_open)          {              this->output_open = (this->stream->audio_out->open) (                                              this->stream->audio_out,                                              this->stream, -                                            this->bits_per_sample, -                                            this->sample_rate, +                                            bits_per_sample, +                                            sample_rate,                                              mode); @@ -390,19 +379,6 @@ open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {  /*   * flac plugin class   */ - -static char *get_identifier (audio_decoder_class_t *this) { -  return "flacdec"; -} - -static char *get_description (audio_decoder_class_t *this) { -  return "flac audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { -  free (this); -} -  static void *  init_plugin (xine_t *xine, void *data) {      flac_class_t *this; @@ -410,15 +386,17 @@ init_plugin (xine_t *xine, void *data) {      this = (flac_class_t *) xine_xmalloc (sizeof (flac_class_t));      this->decoder_class.open_plugin     = open_plugin; -    this->decoder_class.get_identifier  = get_identifier; -    this->decoder_class.get_description = get_description; -    this->decoder_class.dispose         = dispose_class; +    this->decoder_class.identifier      = "flacdec"; +    this->decoder_class.description     = N_("flac audio decoder plugin"); +    this->decoder_class.dispose         = default_audio_decoder_class_dispose;      return this;  } -static uint32_t audio_types[] = {  +void *demux_flac_init_class (xine_t *xine, void *data); + +static const uint32_t audio_types[] = {     BUF_AUDIO_FLAC, 0   }; @@ -429,7 +407,7 @@ static const decoder_info_t dec_info_audio = {  const plugin_info_t xine_plugin_info[] EXPORTED = {    /* type, API, "name", version, special_info, init_function */   -  { PLUGIN_DEMUX, 26, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, -  { PLUGIN_AUDIO_DECODER, 15, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, +  { PLUGIN_DEMUX, 27, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, +  { PLUGIN_AUDIO_DECODER, 16, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin },    { PLUGIN_NONE, 0, "", 0, NULL, NULL }  }; diff --git a/src/combined/demux_flac.c b/src/combined/flac_demuxer.c index fdc7ab7ea..22ee2319b 100644 --- a/src/combined/demux_flac.c +++ b/src/combined/flac_demuxer.c @@ -51,11 +51,9 @@  #define LOG  */ -#include "xine_internal.h" -#include "xineutils.h" -#include "../demuxers/demux.h" - -#include "demux_flac.h" +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/demux.h>  #ifndef LEGACY_FLAC  # define FLAC__SeekableStreamDecoder FLAC__StreamDecoder @@ -582,20 +580,7 @@ open_plugin (demux_class_t *class_gen,              return NULL;          }          break; -        case METHOD_BY_EXTENSION: { -            char *ending, *mrl; -     -            mrl = input->get_mrl (input); -     -            ending = strrchr (mrl, '.'); - -            if (!ending || (strlen (ending) < 5)) -                return NULL; - -            if (strncasecmp (ending, ".flac", 5)) -                return NULL; -        } -        break; +        case METHOD_BY_MRL:          case METHOD_EXPLICIT:          break;          default: @@ -714,37 +699,6 @@ open_plugin (demux_class_t *class_gen,  /* FLAC Demuxer class */ - -static char * -get_description (demux_class_t *this_gen) { -    return "FLAC demux plugin"; -} -  -static char * -get_identifier (demux_class_t *this_gen) { -    return "FLAC"; -} - -static char * -get_extensions (demux_class_t *this_gen) { -    return "flac"; -} - -static char * -get_mimetypes (demux_class_t *this_gen) { -    return "audio/x-flac: flac: FLAC Audio;" -	"audio/flac: flac: FLAC Audio;"; -} - -static void  -class_dispose (demux_class_t *this_gen) { -    demux_flac_class_t *this = (demux_flac_class_t *) this_gen; - -    lprintf("class_dispose\n"); - -    free (this); -} -  void *  demux_flac_init_class (xine_t *xine, void *data) { @@ -757,11 +711,12 @@ demux_flac_init_class (xine_t *xine, void *data) {      this->xine   = xine;      this->demux_class.open_plugin     = open_plugin; -    this->demux_class.get_description = get_description; -    this->demux_class.get_identifier  = get_identifier; -    this->demux_class.get_mimetypes   = get_mimetypes; -    this->demux_class.get_extensions  = get_extensions; -    this->demux_class.dispose         = class_dispose; +    this->demux_class.description     = N_("FLAC demux plugin"); +    this->demux_class.identifier      = "FLAC"; +    this->demux_class.mimetypes       = "application/x-flac: flac: FLAC Audio;" +                                        "application/flac: flac: FLAC Audio;"; +    this->demux_class.extensions      = "flac"; +    this->demux_class.dispose         = default_demux_class_dispose;      return this;  } diff --git a/src/combined/nsf_combined.c b/src/combined/nsf_combined.c new file mode 100644 index 000000000..0364e2db2 --- /dev/null +++ b/src/combined/nsf_combined.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +#include <xine/xine_internal.h> +#include "nsf_combined.h" + +static const demuxer_info_t demux_info_nsf = { +  10                       /* priority */ +}; + +static const uint32_t audio_types[] = {  +  BUF_AUDIO_NSF, +  0 +}; + +static const decoder_info_t decoder_info_nsf = { +  audio_types,         /* supported types */ +  5                    /* priority        */ +}; + +const plugin_info_t xine_plugin_info[] EXPORTED = { +  { PLUGIN_DEMUX, 27, "nsfdemux", XINE_VERSION_CODE, &demux_info_nsf, demux_nsf_init_plugin }, +  { PLUGIN_AUDIO_DECODER, 16, "nsfdec", XINE_VERSION_CODE, &decoder_info_nsf, decoder_nsf_init_plugin }, +  { PLUGIN_NONE, 0, NULL, 0, NULL, NULL } +}; diff --git a/src/combined/demux_flac.h b/src/combined/nsf_combined.h index a48c73260..4376ecf7a 100644 --- a/src/combined/demux_flac.h +++ b/src/combined/nsf_combined.h @@ -1,26 +1,22 @@ -/*  - * Copyright (C) 2000-2003 the xine project - *  +/* + * Copyright (C) 2000-2001 the xine project + *   * This file is part of xine, a free video player. - *  + *   * xine is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License, or   * (at your option) any later version. - *  + *   * xine is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details. - *  + *   * You should have received a copy of the GNU General Public License   * along with this program; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA   */ -#ifndef HAVE_DEMUX_FLAC_H -#define HAVE_DEMUX_FLAC_H - -void *demux_flac_init_class (xine_t *xine, void *data); - -#endif +void *decoder_nsf_init_plugin (xine_t *xine, void *data); +void *demux_nsf_init_plugin (xine_t *xine, void *data); diff --git a/src/combined/nsf_decoder.c b/src/combined/nsf_decoder.c new file mode 100644 index 000000000..cb3b6e7b0 --- /dev/null +++ b/src/combined/nsf_decoder.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * NSF Audio "Decoder" using the Nosefart NSF engine by Matt Conte + *   http://www.baisoku.org/ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <xine/xine_internal.h> +#include <xine/audio_out.h> +#include <xine/buffer.h> +#include <xine/xineutils.h> +#include "bswap.h" + +/* Nosefart includes */ +#include "types.h" +#include "nsf.h" + +#include "nsf_combined.h" + +typedef struct { +  audio_decoder_class_t   decoder_class; +} nsf_class_t; + +typedef struct nsf_decoder_s { +  audio_decoder_t  audio_decoder; + +  xine_stream_t    *stream; + +  int              sample_rate;       /* audio sample rate */ +  int              bits_per_sample;   /* bits/sample, usually 8 or 16 */ +  int              channels;          /* 1 or 2, usually */ + +  int              output_open;       /* flag to indicate audio is ready */ + +  int              nsf_size; +  unsigned char   *nsf_file; +  int              nsf_index; +  int              song_number; + +  /* nsf-specific variables */ +  int64_t           last_pts; +  unsigned int      iteration; + +  nsf_t            *nsf; +} nsf_decoder_t; + +/************************************************************************** + * xine audio plugin functions + *************************************************************************/ + +static void nsf_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + +  nsf_decoder_t *this = (nsf_decoder_t *) this_gen; +  audio_buffer_t *audio_buffer; + +  if (buf->decoder_flags & BUF_FLAG_HEADER) { + +    /* When the engine sends a BUF_FLAG_HEADER flag, it is time to initialize +     * the decoder. The buffer element type has 4 decoder_info fields, +     * 0..3. Field 1 is the sample rate. Field 2 is the bits/sample. Field +     * 3 is the number of channels. */ +    this->sample_rate = buf->decoder_info[1]; +    this->bits_per_sample = buf->decoder_info[2]; +    this->channels = buf->decoder_info[3]; + +    /* take this opportunity to initialize stream/meta information */ +    _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, +      "NES Music (Nosefart)"); + +    this->song_number = buf->content[4]; +    /* allocate a buffer for the file */ +    this->nsf_size = _X_BE_32(&buf->content[0]); +    this->nsf_file = xine_xmalloc(this->nsf_size); +    this->nsf_index = 0; + +    /* peform any other required initialization */ +    this->last_pts = -1; +    this->iteration = 0; + +    return; +  } + +  /* accumulate chunks from the NSF file until whole file is received */ +  if (this->nsf_index < this->nsf_size) { +    xine_fast_memcpy(&this->nsf_file[this->nsf_index], buf->content, +      buf->size); +    this->nsf_index += buf->size; + +    if (this->nsf_index == this->nsf_size) { +      /* file has been received, proceed to initialize engine */ +      nsf_init(); +      this->nsf = nsf_load(NULL, this->nsf_file, this->nsf_size); +      if (!this->nsf) { +        xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "nsf: could not initialize NSF\n"); +        /* make the decoder return on every subsequent buffer */ +        this->nsf_index = 0; +	return; +      } +      this->nsf->current_song = this->song_number; +      nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate, +        this->bits_per_sample, this->channels); +    } +    return; +  } + +  /* if the audio output is not open yet, open the audio output */ +  if (!this->output_open) { +    this->output_open = (this->stream->audio_out->open) ( +      this->stream->audio_out, +      this->stream, +      this->bits_per_sample, +      this->sample_rate, +      _x_ao_channels2mode(this->channels)); +  } + +  /* if the audio still isn't open, do not go any further with the decode */ +  if (!this->output_open) +    return; + +  /* check if a song change was requested */ +  if (buf->decoder_info[1]) { +    this->nsf->current_song = buf->decoder_info[1]; +    nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate, +      this->bits_per_sample, this->channels); +  } + +  /* time to decode a frame */ +  if (this->last_pts != -1) { + +    /* process a frame */ +    nsf_frame(this->nsf); + +    /* get an audio buffer */ +    audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); +    if (audio_buffer->mem_size == 0) { +       xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "nsf: Help! Allocated audio buffer with nothing in it!\n"); +       return; +    } + +    apu_process(audio_buffer->mem, this->sample_rate / this->nsf->playback_rate); +    audio_buffer->vpts = buf->pts; +    audio_buffer->num_frames = this->sample_rate / this->nsf->playback_rate; +    this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); +  } +  this->last_pts = buf->pts; +} + +/* This function resets the state of the audio decoder. This usually + * entails resetting the data accumulation buffer. */ +static void nsf_reset (audio_decoder_t *this_gen) { + +  nsf_decoder_t *this = (nsf_decoder_t *) this_gen; + +  this->last_pts = -1; +} + +/* This function resets the last pts value of the audio decoder. */ +static void nsf_discontinuity (audio_decoder_t *this_gen) { + +  nsf_decoder_t *this = (nsf_decoder_t *) this_gen; + +  this->last_pts = -1; +} + +/* This function closes the audio output and frees the private audio decoder + * structure. */ +static void nsf_dispose (audio_decoder_t *this_gen) { + +  nsf_decoder_t *this = (nsf_decoder_t *) this_gen; + +  /* close the audio output */ +  if (this->output_open) +    this->stream->audio_out->close (this->stream->audio_out, this->stream); +  this->output_open = 0; + +  /* free anything that was allocated during operation */ +  nsf_free(&this->nsf); +  free(this->nsf_file); +  free(this); +} + +/* This function allocates, initializes, and returns a private audio + * decoder structure. */ +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { + +  nsf_decoder_t *this ; + +  this = (nsf_decoder_t *) xine_xmalloc (sizeof (nsf_decoder_t)); + +  /* connect the member functions */ +  this->audio_decoder.decode_data         = nsf_decode_data; +  this->audio_decoder.reset               = nsf_reset; +  this->audio_decoder.discontinuity       = nsf_discontinuity; +  this->audio_decoder.dispose             = nsf_dispose; + +  /* connect the stream */ +  this->stream = stream; + +  /* audio output is not open at the start */ +  this->output_open = 0; + +  /* initialize the basic audio parameters */ +  this->channels = 0; +  this->sample_rate = 0; +  this->bits_per_sample = 0; + +  /* return the newly-initialized audio decoder */ +  return &this->audio_decoder; +} + +/* This function allocates a private audio decoder class and initializes  + * the class's member functions. */ +void *decoder_nsf_init_plugin (xine_t *xine, void *data) { + +  nsf_class_t *this ; + +  this = (nsf_class_t *) xine_xmalloc (sizeof (nsf_class_t)); + +  this->decoder_class.open_plugin     = open_plugin; +  this->decoder_class.identifier      = "NSF"; +  this->decoder_class.description     = N_("NES Music audio decoder plugin"); +  this->decoder_class.dispose         = default_audio_decoder_class_dispose; + +  return this; +} diff --git a/src/combined/nsf_demuxer.c b/src/combined/nsf_demuxer.c new file mode 100644 index 000000000..451e6e938 --- /dev/null +++ b/src/combined/nsf_demuxer.c @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +/* + * NSF File "Demuxer" by Mike Melanson (melanson@pcisys.net) + * This is really just a loader for NES Music File Format (extension NSF) + * which loads an entire NSF file and passes it over to the NSF audio + * decoder.  + * + * After the file is sent over, the demuxer controls the playback by + * sending empty buffers with incrementing pts values. + * + * For more information regarding the NSF format, visit: + *   http://www.tripoint.org/kevtris/nes/nsfspec.txt + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +/********** logging **********/ +#define LOG_MODULE "demux_nsf" +/* #define LOG_VERBOSE */ +/* #define LOG */ + +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/compat.h> +#include <xine/demux.h> +#include "bswap.h" + +#include "nsf_combined.h" + +#define NSF_HEADER_SIZE 0x80 +#define NSF_SAMPLERATE 44100 +#define NSF_BITS 8 +#define NSF_CHANNELS 1 +#define NSF_REFRESH_RATE 60 +#define NSF_PTS_INC (90000 / NSF_REFRESH_RATE) + +typedef struct { +  demux_plugin_t       demux_plugin; + +  xine_stream_t       *stream; +  fifo_buffer_t       *video_fifo; +  fifo_buffer_t       *audio_fifo; +  input_plugin_t      *input; +  int                  status; + +  int                  total_songs; +  int                  current_song; +  int                  new_song;  /* indicates song change */ + +  char                *title; +  char                *artist; +  char                *copyright; + +  off_t                filesize; + +  int64_t              current_pts; +  int                  file_sent; +} demux_nsf_t; + +typedef struct { +  demux_class_t     demux_class; +} demux_nsf_class_t; + +/* returns 1 if the NSF file was opened successfully, 0 otherwise */ +static int open_nsf_file(demux_nsf_t *this) { +  unsigned char header[NSF_HEADER_SIZE]; + +  this->input->seek(this->input, 0, SEEK_SET); +  if (this->input->read(this->input, header, NSF_HEADER_SIZE) != +    NSF_HEADER_SIZE) +    return 0; + +  /* check for the signature */ +  if ( memcmp(header, "NESM\x1A", 5) != 0 ) +    return 0; + +  this->total_songs = header[6]; +  this->current_song = header[7]; +  this->title = strndup((char*)&header[0x0E], 0x20); +  this->artist = strndup((char*)&header[0x2E], 0x20); +  this->copyright = strndup((char*)&header[0x4E], 0x20); + +  this->filesize = this->input->get_length(this->input); + +  return 1; +} + +static int demux_nsf_send_chunk(demux_plugin_t *this_gen) { +  demux_nsf_t *this = (demux_nsf_t *) this_gen; +  buf_element_t *buf; +  int bytes_read; +  char title[100]; + +  /* send chunks of the file to the decoder until file is completely +   * loaded; then send control buffers */ +  if (!this->file_sent) { +    buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); +    buf->type = BUF_AUDIO_NSF; +    bytes_read = this->input->read(this->input, buf->content, buf->max_size); + +    if (bytes_read == 0) { +      /* the file has been completely loaded, free the buffer and start +       * sending control buffers */ +      buf->free_buffer(buf); +      this->file_sent = 1; + +    } else { + +      /* keep loading the file */ +      if (bytes_read < buf->max_size) +        buf->size = bytes_read; +      else +        buf->size = buf->max_size; + +      buf->extra_info->input_normpos = 0; +      buf->extra_info->input_time = 0; +      buf->pts = 0; + +      this->audio_fifo->put (this->audio_fifo, buf); +    } +  } + +  /* this is not an 'else' because control might fall through from above */ +  if (this->file_sent) { +    /* send a control buffer */ +    buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + +    if (this->new_song) { + +      buf->decoder_info[1] = this->current_song; +      this->new_song = 0; +      sprintf(title, "%s, song %d/%d", +        this->title, this->current_song, this->total_songs); + +      _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title); + +      _x_demux_control_newpts(this->stream, this->current_pts, 0); + +    } else +      buf->decoder_info[1] = 0; + +    buf->type = BUF_AUDIO_NSF; +    if(this->total_songs)  +      buf->extra_info->input_normpos = (this->current_song - 1) * 65535 / this->total_songs; +    buf->extra_info->input_time = this->current_pts / 90; +    buf->pts = this->current_pts; +    buf->size = 0; +    this->audio_fifo->put (this->audio_fifo, buf); + +    this->current_pts += NSF_PTS_INC; +  } + +  return this->status; +} + +static void demux_nsf_send_headers(demux_plugin_t *this_gen) { +  demux_nsf_t *this = (demux_nsf_t *) this_gen; +  buf_element_t *buf; +  char copyright[100]; + +  this->video_fifo = this->stream->video_fifo; +  this->audio_fifo = this->stream->audio_fifo; + +  this->status = DEMUX_OK; + +  /* load stream information */ +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 0); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, +    NSF_CHANNELS); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, +    NSF_SAMPLERATE); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, +    NSF_BITS); + +  _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title); +  _x_meta_info_set(this->stream, XINE_META_INFO_ARTIST, this->artist); +  sprintf(copyright, "(C) %s", this->copyright); +  _x_meta_info_set(this->stream, XINE_META_INFO_COMMENT, copyright); + +  /* send start buffers */ +  _x_demux_control_start(this->stream); + +  /* send init info to the audio decoder */ +  if (this->audio_fifo) { +    buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); +    buf->type = BUF_AUDIO_NSF; +    buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; +    buf->decoder_info[0] = 5; +    buf->decoder_info[1] = NSF_SAMPLERATE; +    buf->decoder_info[2] = NSF_BITS; +    buf->decoder_info[3] = NSF_CHANNELS; + +    /* send the NSF filesize in the body, big endian format */ +    buf->content[0] = (this->filesize >> 24) & 0xFF; +    buf->content[1] = (this->filesize >> 16) & 0xFF; +    buf->content[2] = (this->filesize >>  8) & 0xFF; +    buf->content[3] = (this->filesize >>  0) & 0xFF; +    /* send the requested song */ +    buf->content[4] = this->current_song + 5; + +    this->audio_fifo->put (this->audio_fifo, buf); +  } +} + +static int demux_nsf_seek (demux_plugin_t *this_gen, +                           off_t start_pos, int start_time, int playing) { + +  demux_nsf_t *this = (demux_nsf_t *) this_gen; +  start_pos = (off_t) ( (double) start_pos / 65535 * +              this->total_songs ); + +  /* if thread is not running, initialize demuxer */ +  if( !playing ) { + +    /* send new pts */ +    _x_demux_control_newpts(this->stream, 0, 0); + +    this->status = DEMUX_OK; + +    /* reposition stream at the start for loading */ +    this->input->seek(this->input, 0, SEEK_SET); + +    this->file_sent = 0; +    this->current_pts = 0; +    this->new_song = 1; +  } else { +    this->current_song = start_pos + 1; +    this->new_song = 1; +    this->current_pts = 0; +    _x_demux_flush_engine(this->stream); +  } + +  return this->status; +} + +static void demux_nsf_dispose (demux_plugin_t *this_gen) { +  demux_nsf_t *this = (demux_nsf_t *) this_gen; + +  free(this->title); +  free(this->artist); +  free(this->copyright); +  free(this); +} + +static int demux_nsf_get_status (demux_plugin_t *this_gen) { +  demux_nsf_t *this = (demux_nsf_t *) this_gen; + +  return this->status; +} + +/* return the approximate length in miliseconds */ +static int demux_nsf_get_stream_length (demux_plugin_t *this_gen) { +  return 0; +} + +static uint32_t demux_nsf_get_capabilities(demux_plugin_t *this_gen) { +  return DEMUX_CAP_NOCAP; +} + +static int demux_nsf_get_optional_data(demux_plugin_t *this_gen, +                                       void *data, int data_type) { +  return DEMUX_OPTIONAL_UNSUPPORTED; +} + +static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, +                                    input_plugin_t *input) { + +  demux_nsf_t   *this; + +  if (!INPUT_IS_SEEKABLE(input)) { +    xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "input not seekable, can not handle!\n"); +    return NULL; +  } + +  this         = xine_xmalloc (sizeof (demux_nsf_t)); +  this->stream = stream; +  this->input  = input; + +  this->demux_plugin.send_headers      = demux_nsf_send_headers; +  this->demux_plugin.send_chunk        = demux_nsf_send_chunk; +  this->demux_plugin.seek              = demux_nsf_seek; +  this->demux_plugin.dispose           = demux_nsf_dispose; +  this->demux_plugin.get_status        = demux_nsf_get_status; +  this->demux_plugin.get_stream_length = demux_nsf_get_stream_length; +  this->demux_plugin.get_capabilities  = demux_nsf_get_capabilities; +  this->demux_plugin.get_optional_data = demux_nsf_get_optional_data; +  this->demux_plugin.demux_class       = class_gen; + +  this->status = DEMUX_FINISHED; + +  switch (stream->content_detection_method) { + +  case METHOD_BY_MRL: +  case METHOD_BY_CONTENT: +  case METHOD_EXPLICIT: + +    if (!open_nsf_file(this)) { +      free (this); +      return NULL; +    } + +  break; + +  default: +    free (this); +    return NULL; +  } + +  return &this->demux_plugin; +} + +void *demux_nsf_init_plugin (xine_t *xine, void *data) { +  demux_nsf_class_t     *this; + +  this = xine_xmalloc (sizeof (demux_nsf_class_t)); + +  this->demux_class.open_plugin     = open_plugin; +  this->demux_class.description     = N_("NES Music file demux plugin"); +  this->demux_class.identifier      = "NSF"; +  this->demux_class.mimetypes       = NULL; +  this->demux_class.extensions      = "nsf"; +  this->demux_class.dispose         = default_demux_class_dispose; + +  return this; +} diff --git a/src/combined/combined_wavpack.c b/src/combined/wavpack_combined.c index 98bbe5b57..ca54635e7 100644 --- a/src/combined/combined_wavpack.c +++ b/src/combined/wavpack_combined.c @@ -20,14 +20,14 @@   * xine interface to libwavpack by Diego Pettenò <flameeyes@gmail.com>   */ -#include "xine_internal.h" -#include "combined_wavpack.h" +#include <xine/xine_internal.h> +#include "wavpack_combined.h"  static const demuxer_info_t demux_info_wv = {    0			/* priority */  }; -static uint32_t audio_types[] = {  +static const uint32_t audio_types[] = {     BUF_AUDIO_WAVPACK, 0   }; @@ -38,7 +38,7 @@ static const decoder_info_t decoder_info_wv = {  const plugin_info_t xine_plugin_info[] EXPORTED = {    /* type, API, "name", version, special_info, init_function */ -  { PLUGIN_DEMUX, 26, "wavpack", XINE_VERSION_CODE, &demux_info_wv, demux_wv_init_plugin }, -  { PLUGIN_AUDIO_DECODER, 15, "wavpackdec", XINE_VERSION_CODE, &decoder_info_wv, decoder_wavpack_init_plugin }, +  { PLUGIN_DEMUX, 27, "wavpack", XINE_VERSION_CODE, &demux_info_wv, demux_wv_init_plugin }, +  { PLUGIN_AUDIO_DECODER, 16, "wavpackdec", XINE_VERSION_CODE, &decoder_info_wv, decoder_wavpack_init_plugin },    { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }  }; diff --git a/src/combined/combined_wavpack.h b/src/combined/wavpack_combined.h index 61a504a4f..42b0bfd51 100644 --- a/src/combined/combined_wavpack.h +++ b/src/combined/wavpack_combined.h @@ -20,7 +20,8 @@   * xine interface to libwavpack by Diego Pettenò <flameeyes@gmail.com>   */ -#include "os_types.h" +#include <xine/os_types.h> +#include "bswap.h"  typedef struct {    uint32_t idcode;        /* This should always be the string "wvpk" */ @@ -35,13 +36,9 @@ typedef struct {    uint32_t samples_count; /* Count of samples in the current frame */    uint32_t flags;         /* Misc flags */    uint32_t decoded_crc32; /* CRC32 of the decoded data */ -} __attribute__((packed)) wvheader_t; +} XINE_PACKED wvheader_t; -#ifdef WORDS_BIGENDIAN -static const uint32_t wvpk_signature = ('k' + ('p' << 8) + ('v' << 16) + ('w' << 24)); -#else -static const uint32_t wvpk_signature = ('w' + ('v' << 8) + ('p' << 16) + ('k' << 24)); -#endif +static const uint32_t wvpk_signature = ME_FOURCC('w', 'v', 'p', 'k');  void *demux_wv_init_plugin (xine_t *const xine, void *const data);  void *decoder_wavpack_init_plugin (xine_t *xine, void *data); diff --git a/src/combined/decoder_wavpack.c b/src/combined/wavpack_decoder.c index f8a301c9f..80a14e678 100644 --- a/src/combined/decoder_wavpack.c +++ b/src/combined/wavpack_decoder.c @@ -27,12 +27,12 @@  #define LOG_MODULE "decode_wavpack"  #define LOG_VERBOSE -#include "xine_internal.h" -#include "attributes.h" +#include <xine/xine_internal.h> +#include <xine/attributes.h>  #include "bswap.h"  #include <wavpack/wavpack.h> -#include "combined_wavpack.h" +#include "wavpack_combined.h"  typedef struct {    audio_decoder_class_t   decoder_class; @@ -102,6 +102,8 @@ static int xine_buffer_set_pos_rel(void *const this_gen, const int32_t delta,      return 0;    } + +  return -1;  }  static int xine_buffer_set_pos_abs(void *const this_gen, const uint32_t pos) { @@ -309,27 +311,15 @@ static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, xine_stre   * wavpack plugin class   */ -static char *get_identifier (audio_decoder_class_t *this) { -  return "wavpackdec"; -} - -static char *get_description (audio_decoder_class_t *this) { -  return "wavpack audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { -  free (this); -} -  void *decoder_wavpack_init_plugin (xine_t *xine, void *data) {      wavpack_class_t *this;      this = (wavpack_class_t *) xine_xmalloc (sizeof (wavpack_class_t));      this->decoder_class.open_plugin     = open_plugin; -    this->decoder_class.get_identifier  = get_identifier; -    this->decoder_class.get_description = get_description; -    this->decoder_class.dispose         = dispose_class; +    this->decoder_class.identifier      = "wavpackdec"; +    this->decoder_class.description     = N_("wavpack audio decoder plugin"); +    this->decoder_class.dispose         = default_audio_decoder_class_dispose;      return this;  } diff --git a/src/combined/demux_wavpack.c b/src/combined/wavpack_demuxer.c index 754052199..e32c17e4e 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 = xine_xmalloc (sizeof (demux_wv_class_t));    this->demux_class.open_plugin     = open_plugin; -  this->demux_class.get_description = get_description; -  this->demux_class.get_identifier  = get_identifier; -  this->demux_class.get_mimetypes   = get_mimetypes; -  this->demux_class.get_extensions  = get_extensions; -  this->demux_class.dispose         = class_dispose; +  this->demux_class.description     = N_("Wavpack demux plugin"); +  this->demux_class.identifier      = "Wavpack"; +  this->demux_class.mimetypes       = "audio/x-wavpack: 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..52788612f --- /dev/null +++ b/src/combined/xine_ogg_demuxer.c @@ -0,0 +1,2159 @@ +/* + * Copyright (C) 2000-2004 the xine project + *  + * This file is part of xine, a free video player. + *  + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *  + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + */ + +/* + * demultiplexer for ogg streams + */ +/* 2003.02.09 (dilb) update of the handling for audio/video infos for strongarm cpus. */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <inttypes.h> + +#include <ogg/ogg.h> + +#ifdef HAVE_VORBIS +#include <vorbis/codec.h> +#endif + +#ifdef HAVE_SPEEX +#include <speex/speex.h> +#include <speex/speex_header.h> +#include <speex/speex_stereo.h> +#include <speex/speex_callbacks.h> +#endif + +#ifdef HAVE_THEORA +#include <theora/theora.h> +#endif + +#define LOG_MODULE "demux_ogg" +#define LOG_VERBOSE + +/* +#define LOG +*/ + +#define DEBUG_PACKETS 0 +#define DEBUG_PREVIEWS 0 +#define DEBUG_PTS 0 +#define DEBUG_VIDEO_PACKETS 0 + +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/demux.h> +#include "bswap.h" +#include "flacutils.h" + +#define CHUNKSIZE                8500 +#define PACKET_TYPE_HEADER       0x01 +#define PACKET_TYPE_COMMENT      0x03 +#define PACKET_TYPE_CODEBOOK     0x05 +#define PACKET_TYPE_BITS	 0x07 +#define PACKET_LEN_BITS01        0xc0 +#define PACKET_LEN_BITS2         0x02 +#define PACKET_IS_SYNCPOINT      0x08 + +#define MAX_STREAMS              32 + +#define PTS_AUDIO                0 +#define PTS_VIDEO                1 + +#define WRAP_THRESHOLD           900000 + +#define SUB_BUFSIZE 1024 + +typedef struct chapter_entry_s { +  int64_t           start_pts; +  char              *name; +} chapter_entry_t; + +typedef struct chapter_info_s { +  int                current_chapter; +  int                max_chapter; +  chapter_entry_t   *entries; +} chapter_info_t; + +typedef struct stream_info_s { +  ogg_stream_state      oss; +  uint32_t              buf_types; +  int                   headers; +  int64_t               header_granulepos; +  int64_t               factor; +  int64_t               quotient; +  int                   resync; +  char                  *language; +  /* CMML, Ogg Skeleton stream information */ +  int                   granuleshift; +  /* Annodex v2 stream information */ +  int                   hide_first_header; +  int                   delivered_bos; +  int                   delivered_eos; +} stream_info_t; + +typedef struct demux_ogg_s { +  demux_plugin_t        demux_plugin; + +  xine_stream_t        *stream; +  fifo_buffer_t        *audio_fifo; +  fifo_buffer_t        *video_fifo; +  input_plugin_t       *input; +  int                   status; + +  int                   frame_duration; + +#ifdef HAVE_THEORA +  theora_info           t_info; +  theora_comment        t_comment; +#endif + +  ogg_sync_state        oy; +  ogg_page              og; + +  int64_t               start_pts; +  int64_t               last_pts[2]; + +  int                   time_length; + +  int                   num_streams; +  stream_info_t        *si[MAX_STREAMS];   /* stream info */ + +  int                   num_audio_streams; +  int                   num_video_streams; +  int                   unhandled_video_streams; +  int                   num_spu_streams; + +  off_t                 avg_bitrate; + +  char                 *title; +  chapter_info_t       *chapter_info; +  xine_event_queue_t   *event_queue; + +  uint8_t               send_newpts:1; +  uint8_t               buf_flag_seek:1; +  uint8_t               keyframe_needed:1; +  uint8_t               ignore_keyframes:1; +} demux_ogg_t ; + +typedef struct { +  demux_class_t     demux_class; +} demux_ogg_class_t; + +typedef struct { +  demux_class_t     demux_class; +} demux_anx_class_t; + + +#ifdef HAVE_THEORA +static int intlog(int num) { +  int ret=0; + +  while(num>0){ +    num=num/2; +    ret=ret+1; +  } +  return(ret); +} +#endif + +static int get_stream (demux_ogg_t *this, int serno) { +  /*finds the stream_num, which belongs to a ogg serno*/ +  int i; + +  for (i = 0; i<this->num_streams; i++) { +    if (this->si[i]->oss.serialno == serno) { +      return i; +    } +  } +  return -1; +} + +static int new_stream_info (demux_ogg_t *this, const int cur_serno) { +  int stream_num; + +  this->si[this->num_streams] = (stream_info_t *)xine_xmalloc(sizeof(stream_info_t)); +  ogg_stream_init(&this->si[this->num_streams]->oss, cur_serno); +  stream_num = this->num_streams; +  this->si[stream_num]->buf_types = 0; +  this->si[stream_num]->header_granulepos = -1; +  this->si[stream_num]->headers = 0; +  this->num_streams++; + +  return stream_num; +} + +static int64_t get_pts (demux_ogg_t *this, int stream_num , int64_t granulepos ) { +  /*calculates an pts from an granulepos*/ +  if (granulepos<0) { +    if ( this->si[stream_num]->header_granulepos>=0 ) { +      /*return the smallest valid pts*/ +      return 1; +    } else +      return 0; +  } else if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA || +	     (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { +    int64_t iframe, pframe; +    int granuleshift; +    granuleshift = this->si[stream_num]->granuleshift; +    iframe = granulepos >> granuleshift; +    pframe = granulepos - (iframe << granuleshift); +    if (this->si[stream_num]->quotient) +      return 1+((iframe+pframe) * this->si[stream_num]->factor / this->si[stream_num]->quotient); +    else +      return 0; +  } else if (this->si[stream_num]->quotient) +    return 1+(granulepos * this->si[stream_num]->factor / this->si[stream_num]->quotient); +  else +    return 0; +} + +static int read_ogg_packet (demux_ogg_t *this) { +  char *buffer; +  long bytes; +  long total = 0; +  while (ogg_sync_pageout(&this->oy,&this->og)!=1) { +    buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); +    bytes  = this->input->read(this->input, buffer, CHUNKSIZE); +    if (bytes == 0) { +      if (total == 0) { +        lprintf("read_ogg_packet read nothing\n"); +        return 0; +      } +      break; +    } +    ogg_sync_wrote(&this->oy, bytes); +    total += bytes; +  } +  return 1; +} + +static void get_stream_length (demux_ogg_t *this) { +  /*determine the streamlenght and set this->time_length accordingly. +    ATTENTION:current_pos and oggbuffers will be destroyed by this function, +    there will be no way to continue playback uninterrupted. + +    You have to seek afterwards, because after get_stream_length, the +    current_position is at the end of the file */ + +  off_t filelength; +  int done=0; +  int stream_num; + +  this->time_length=-1; + +  if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { +    filelength=this->input->get_length(this->input); + +    if (filelength!=-1) { +      if (filelength>70000) { +        this->demux_plugin.seek(&this->demux_plugin, +				(off_t) ( (double)(filelength-65536)/filelength*65535), 0, 0); +      } +      done=0; +      while (!done) { +        if (!read_ogg_packet (this)) { +          if (this->time_length) { +            _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, +                               ((int64_t) 8000*filelength)/this->time_length); +            /*this is a fine place to compute avg_bitrate*/ +            this->avg_bitrate= 8000*filelength/this->time_length; +          } +          return; +        } +        stream_num=get_stream(this, ogg_page_serialno (&this->og) ); +        if (stream_num!=-1) { +          if (this->time_length < (get_pts(this, stream_num, ogg_page_granulepos(&this->og) / 90))) +            this->time_length = get_pts(this, stream_num, ogg_page_granulepos(&this->og)) / 90; +        } +      } +    } +  } +} + +#ifdef HAVE_THEORA +static void send_ogg_packet (demux_ogg_t *this, +                               fifo_buffer_t *fifo, +                               ogg_packet *op, +                               int64_t pts, +                               uint32_t decoder_flags, +                               int stream_num) { + +  buf_element_t *buf; + +  int done=0,todo=op->bytes; +  int op_size = sizeof(ogg_packet); + +  while (done<todo) { +    int offset=0; +    buf = fifo->buffer_pool_alloc (fifo); +    buf->decoder_flags = decoder_flags; +    if (done==0) { +      memcpy (buf->content, op, op_size); +      offset=op_size; +      buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_START; +    } + +    if (done+buf->max_size-offset < todo) { +      memcpy (buf->content+offset, op->packet+done, buf->max_size-offset); +      buf->size = buf->max_size; +      done=done+buf->max_size-offset; +    } else { +      memcpy (buf->content+offset , op->packet+done, todo-done); +      buf->size = todo-done+offset; +      done=todo; +      buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_END; +    } + +    buf->pts = pts; +    if( this->input->get_length (this->input) ) +      buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) *  +                                       65535 / this->input->get_length (this->input) ); +    buf->extra_info->input_time = buf->pts / 90 ; +    buf->type       = this->si[stream_num]->buf_types; + +    fifo->put (fifo, buf); +  } +} +#endif + +/* redefine abs as macro to handle 64-bit diffs. +   i guess llabs may not be available everywhere */ +#define abs(x) ( ((x)<0) ? -(x) : (x) ) + +static void check_newpts (demux_ogg_t *this, int64_t pts, int video, int preview) { +  int64_t diff; + +  llprintf(DEBUG_PTS, "new pts %" PRId64 " found in stream\n",pts); + +  diff = pts - this->last_pts[video]; + +  if (!preview && (pts>=0) && +      (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { + +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, +             "diff=%" PRId64 " (pts=%" PRId64 ", last_pts=%" PRId64 ")\n", diff, pts, this->last_pts[video]); + +    if (this->buf_flag_seek) { +      _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); +      this->buf_flag_seek = 0; +    } else { +      _x_demux_control_newpts(this->stream, pts, 0); +    } +    this->send_newpts = 0; +    this->last_pts[1-video] = 0; +  } + +  if (!preview && (pts>=0) ) +    this->last_pts[video] = pts; + +  /* use pts for bitrate measurement */ + +  /*compute avg_bitrate if time_length isn't set*/ +  if ((pts>180000) && !(this->time_length)) { +    this->avg_bitrate = this->input->get_current_pos (this->input) * 8 * 90000/ pts; + +    if (this->avg_bitrate<1) +      this->avg_bitrate = 1; + +  } +} + +static void ogg_handle_event (demux_ogg_t *this) { +  xine_event_t *event; + +  while ((event = xine_event_get(this->event_queue))) { +    switch(event->type) { +    case XINE_EVENT_INPUT_NEXT: +      { +        if (this->chapter_info) { +          int c_chap = this->chapter_info->current_chapter; +          if (c_chap+1 < this->chapter_info->max_chapter) { +            int start_time = this->chapter_info->entries[c_chap+1].start_pts / 90; +            this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); +          } +        } +      } +      break; +    case XINE_EVENT_INPUT_PREVIOUS: +      { +        if (this->chapter_info) { +          int c_chap = this->chapter_info->current_chapter; +          if (c_chap >= 1) { +            int start_time = this->chapter_info->entries[c_chap-1].start_pts / 90; +            this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); +          } +        } +      } +      break; +    } +    xine_event_free(event); +  } +  return; +} + +/* + * utility function to read a LANGUAGE= line from the user_comments, + * to label audio and spu streams + */ +static void read_language_comment (demux_ogg_t *this, ogg_packet *op, int stream_num) { +#ifdef HAVE_VORBIS +  char           **ptr; +  char           *comment; +  vorbis_comment vc; +  vorbis_info    vi; + +  vorbis_comment_init(&vc); +  vorbis_info_init(&vi); + +  /* this is necessary to make libvorbis accept this vorbis_info*/ +  vi.rate=1; + +  if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { +    ptr=vc.user_comments; +    while(*ptr) { +      comment=*ptr; +      if ( !strncasecmp ("LANGUAGE=", comment, 9) ) { +        this->si[stream_num]->language = strdup (comment + strlen ("LANGUAGE=") ); +      } +      ++ptr; +    } +  } +  vorbis_comment_clear(&vc); +  vorbis_info_clear(&vi); +#endif +} + +/* + * utility function to read CHAPTER*= and TITLE= from the user_comments, + * to name parts of the videostream + */ +static void read_chapter_comment (demux_ogg_t *this, ogg_packet *op) { +#ifdef HAVE_VORBIS +  char           **ptr; +  char           *comment; +  vorbis_comment vc; +  vorbis_info    vi; + +  vorbis_comment_init(&vc); +  vorbis_info_init(&vi); + +  /* this is necessary to make libvorbis accept this vorbis_info*/ +  vi.rate=1; + +  if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { +    char *chapter_time = 0; +    char *chapter_name = 0; +    int   chapter_no = 0; +    ptr=vc.user_comments; +    while(*ptr) { +      comment=*ptr; +      if ( !strncasecmp ("TITLE=", comment,6) ) { +        this->title = strdup (comment + strlen ("TITLE=") ); +        _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title); +      } +      if ( !chapter_time && strlen(comment) == 22 && +          !strncasecmp ("CHAPTER" , comment, 7) && +          isdigit(*(comment+7)) && isdigit(*(comment+8)) && +          (*(comment+9) == '=')) { + +        chapter_time = strdup(comment+10); +        chapter_no   = strtol(comment+7, NULL, 10); +      } +      if ( !chapter_name && !strncasecmp("CHAPTER", comment, 7) && +          isdigit(*(comment+7)) && isdigit(*(comment+8)) && +          !strncasecmp ("NAME=", comment+9, 5)) { + +        if (strtol(comment+7,NULL,10) == chapter_no) { +          chapter_name = strdup(comment+14); +        } +      } +      if (chapter_time && chapter_name && chapter_no){ +        int hour, min, sec, msec; + +        lprintf("create chapter entry: no=%d name=%s time=%s\n", chapter_no, chapter_name, chapter_time); +        hour= strtol(chapter_time, NULL, 10); +        min = strtol(chapter_time+3, NULL, 10); +        sec = strtol(chapter_time+6, NULL, 10); +        msec = strtol(chapter_time+9, NULL, 10); +        lprintf("time: %d %d %d %d\n", hour, min,sec,msec); + +        if (!this->chapter_info) { +          this->chapter_info = (chapter_info_t *)xine_xmalloc(sizeof(chapter_info_t)); +          this->chapter_info->current_chapter = -1; +        } +        this->chapter_info->max_chapter = chapter_no; +        this->chapter_info->entries = realloc( this->chapter_info->entries, chapter_no*sizeof(chapter_entry_t)); +        this->chapter_info->entries[chapter_no-1].name = chapter_name; +        this->chapter_info->entries[chapter_no-1].start_pts = (msec + (1000.0 * sec) + (60000.0 * min) + (3600000.0 * hour))*90; + +        free (chapter_time); +        chapter_no = 0; +        chapter_time = chapter_name = 0; +      } +      ++ptr; +    } +  } +  vorbis_comment_clear(&vc); +  vorbis_info_clear(&vi); +#endif +} + +/* + * update the display of the title, if needed + */ +static void update_chapter_display (demux_ogg_t *this, int stream_num, ogg_packet *op) { +  int chapter = 0; +  int64_t pts = get_pts(this, stream_num, op->granulepos ); + +  while (chapter < this->chapter_info->max_chapter && +    this->chapter_info->entries[chapter].start_pts < pts) { +    chapter++; +  } +  chapter--; + +  if (chapter != this->chapter_info->current_chapter){ +    xine_event_t uevent; +    xine_ui_data_t data; +    int title_len; +    char *title; + +    this->chapter_info->current_chapter = chapter; +    if (chapter >= 0) { +      char t_title[256]; + +      if (this->title) { +        snprintf(t_title, sizeof (t_title), "%s / %s", this->title, this->chapter_info->entries[chapter].name); +      } else { +        snprintf(t_title, sizeof (t_title), "%s", this->chapter_info->entries[chapter].name); +      } +      title = t_title; +    } else { +      title = this->title; +    } +    _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title); +    lprintf("new TITLE: %s\n", title); + +    uevent.type = XINE_EVENT_UI_SET_TITLE; +    uevent.stream = this->stream; +    uevent.data = &data; +    uevent.data_length = sizeof(data); +    title_len = strlen(title) + 1; +    memcpy(data.str, title, title_len); +    data.str_len = title_len; +    xine_event_send(this->stream, &uevent); +  } +} + +/* + * utility function to pack one ogg_packet into a xine + * buffer, fill out all needed fields + * and send it to the right fifo + */ + +static void send_ogg_buf (demux_ogg_t *this, +                          ogg_packet  *op, +                          int          stream_num, +                          uint32_t     decoder_flags) { + +  int hdrlen; +  int normpos = 0; + +  if( this->input->get_length (this->input) ) +    normpos = (int)( (double) this->input->get_current_pos (this->input) *  +                              65535 / this->input->get_length (this->input) ); + +   +  hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; +  hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; + +  /* for Annodex files: the first packet after the AnxData info packet needs +   * to have its BOS flag set: we set it here */ +  if (!this->si[stream_num]->delivered_bos) { +    op->b_o_s = 1; +    this->si[stream_num]->delivered_bos = 1; +  } + +  if ( this->audio_fifo +       && (this->si[stream_num]->buf_types & 0xFF000000) == BUF_AUDIO_BASE) { +    uint8_t *data; +    int size; +    int64_t pts; + +    if (op->packet[0] == PACKET_TYPE_COMMENT ) { +      read_language_comment(this, op, stream_num); +    } + +    if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_SPEEX || +        (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_FLAC || +        (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_VORBIS) { +      data = op->packet; +      size = op->bytes; +    } else { +      data = op->packet+1+hdrlen; +      size = op->bytes-1-hdrlen; +    } +    llprintf(DEBUG_PACKETS, "audio data size %d\n", size); + +    if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { +      pts = get_pts(this, stream_num, op->granulepos ); +      check_newpts( this, pts, PTS_AUDIO, decoder_flags ); +    } else +      pts = 0; + +    llprintf(DEBUG_PACKETS, +             "audiostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", +             stream_num, +             op->granulepos, +             this->si[stream_num]->header_granulepos, +             pts); + +    _x_demux_send_data(this->audio_fifo, data, size, +		       pts, this->si[stream_num]->buf_types, decoder_flags, +		       normpos, +		       pts / 90, this->time_length, 0); + +#ifdef HAVE_THEORA +  } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_VIDEO_THEORA) { + +    int64_t pts; +    theora_info t_info; +    theora_comment t_comment; + +    theora_info_init (&t_info); +    theora_comment_init (&t_comment); + +    /*Lets see if this is an Header*/ +    if ((theora_decode_header(&t_info, &t_comment, op))>=0) { +      decoder_flags=decoder_flags|BUF_FLAG_HEADER; +      lprintf ("found an header\n"); +    } + +    if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { +      pts = get_pts(this, stream_num, op->granulepos ); +      check_newpts( this, pts, PTS_VIDEO, decoder_flags ); +    } else +      pts = 0; + +    llprintf(DEBUG_PACKETS, +             "theorastream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", +             stream_num, +             op->granulepos, +             this->si[stream_num]->header_granulepos, +             pts); + +    send_ogg_packet (this, this->video_fifo, op, pts, decoder_flags, stream_num); + +    theora_comment_clear (&t_comment); +    theora_info_clear (&t_info); +#endif + +  } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { + +    uint8_t *data; +    int size; +    int64_t pts; + +    llprintf(DEBUG_VIDEO_PACKETS, +             "video buffer, type=%08x\n", this->si[stream_num]->buf_types); + +    if (op->packet[0] == PACKET_TYPE_COMMENT ) { +      read_chapter_comment(this, op); +    }else{ +      data = op->packet+1+hdrlen; +      size = op->bytes-1-hdrlen; + +      if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { +        pts = get_pts(this, stream_num, op->granulepos ); +        check_newpts( this, pts, PTS_VIDEO, decoder_flags ); +      } else +        pts = 0; +       +      llprintf(DEBUG_VIDEO_PACKETS, +               "videostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", +               stream_num, +               op->granulepos, +               this->si[stream_num]->header_granulepos, +               pts); + +      _x_demux_send_data(this->video_fifo, data, size, +                         pts, this->si[stream_num]->buf_types, decoder_flags, +                         normpos, +                         pts / 90, this->time_length, 0); + +      if (this->chapter_info && op->granulepos != -1) { +        update_chapter_display(this, stream_num, op); +      } +    } +  } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { +    buf_element_t *buf; +    uint32_t *val; +    char *str; + +    buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + +    buf->type = this->si[stream_num]->buf_types; + +    buf->pts = get_pts (this, stream_num, op->granulepos); + +    val = (uint32_t * )buf->content; +    str = (char *)val; + +    memcpy(str, op->packet, op->bytes); +    str[op->bytes] = '\0'; + +    buf->size = 12 + op->bytes + 1; + +    lprintf ("CMML stream %d (bytes=%ld): PTS %"PRId64": %s\n", +             stream_num, op->bytes, buf->pts, str); + +    this->video_fifo->put (this->video_fifo, buf); +  } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { + +    buf_element_t *buf; +    int i; +    char *subtitle,*str; +    int lenbytes; +    int start,end; +    uint32_t *val; + +    for (i = 0, lenbytes = 0; i < hdrlen; i++) { +      lenbytes = lenbytes << 8; +      lenbytes += *((unsigned char *) op->packet + hdrlen - i); +    } + +    if (op->packet[0] == PACKET_TYPE_HEADER ) { +      lprintf ("Textstream-header-packet\n"); +    } else if (op->packet[0] == PACKET_TYPE_COMMENT ) { +      lprintf ("Textstream-comment-packet\n"); +      read_language_comment(this, op, stream_num); +    } else { +      subtitle = (char *)&op->packet[hdrlen + 1]; + +      if ((strlen(subtitle) > 1) || (*subtitle != ' ')) { +        start = op->granulepos; +        end = start+lenbytes; +        lprintf ("subtitlestream %d: %d -> %d :%s\n",stream_num,start,end,subtitle); +        buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + +        buf->type = this->si[stream_num]->buf_types; +        buf->pts = 0; + +        val = (uint32_t * )buf->content; +        *val++ = start; +        *val++ = end; +        str = (char *)val; + +        memcpy (str, subtitle, 1+strlen(subtitle)); + +        this->video_fifo->put (this->video_fifo, buf); +      } +    } +  } else { +    lprintf("unknown stream type %x\n", this->si[stream_num]->buf_types); +  } +} + +static void decode_vorbis_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +#ifdef HAVE_VORBIS +  vorbis_info       vi; +  vorbis_comment    vc; + +  this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS +    +this->num_audio_streams++; + +  this->si[stream_num]->headers = 3; + +  vorbis_info_init(&vi); +  vorbis_comment_init(&vc); +  if (vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { + +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, vi.bitrate_nominal); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, vi.rate); + +    this->si[stream_num]->factor = 90000; +    this->si[stream_num]->quotient = vi.rate; + +    if (vi.bitrate_nominal<1) +      this->avg_bitrate += 100000; /* assume 100 kbit */ +    else +      this->avg_bitrate += vi.bitrate_nominal; + +  } else { +    this->si[stream_num]->factor = 900; +    this->si[stream_num]->quotient = 441; + +    this->si[stream_num]->headers = 0; +    xine_log (this->stream->xine, XINE_LOG_MSG, +              _("ogg: vorbis audio track indicated but no vorbis stream header found.\n")); +  } +  vorbis_comment_clear(&vc); +  vorbis_info_clear(&vi); +#endif +} + +static void decode_speex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +#ifdef HAVE_SPEEX +  void *st; +  SpeexMode *mode; +  SpeexHeader *header; + +  this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX +    +this->num_audio_streams++; + +  this->si[stream_num]->headers = 1; + +  header = speex_packet_to_header (op->packet, op->bytes); + +  if (header) { +    int bitrate; +    mode = (SpeexMode *) speex_mode_list[header->mode]; + +    st = speex_decoder_init (mode); + +    speex_decoder_ctl (st, SPEEX_GET_BITRATE, &bitrate); + +    if (bitrate <= 1) +      bitrate = 16000; /* assume 16 kbit */ + +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); + +    this->si[stream_num]->factor = 90000; +    this->si[stream_num]->quotient = header->rate; + +    this->avg_bitrate += bitrate; + +    lprintf ("detected Speex stream,\trate %d\tbitrate %d\n", header->rate, bitrate); + +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, header->rate); +    this->si[stream_num]->headers += header->extra_headers; +  } +#else +  xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Speex stream detected, unable to play\n"); + +  this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif +} + +static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +  buf_element_t    *buf; +  xine_bmiheader    bih; +  int               channel; + +  int16_t          locbits_per_sample; +  uint32_t         locsubtype; +  int32_t          locsize, locdefault_len, locbuffersize, locwidth, locheight; +  int64_t          loctime_unit, locsamples_per_unit; + +  /* read fourcc with machine endianness */ +  locsubtype = *((uint32_t *)&op->packet[9]); + +  /* everything else little endian */ +  locsize = _X_LE_32(&op->packet[13]); +  loctime_unit = _X_LE_64(&op->packet[17]); +  locsamples_per_unit = _X_LE_64(&op->packet[25]); +  locdefault_len = _X_LE_32(&op->packet[33]); +  locbuffersize = _X_LE_32(&op->packet[37]); +  locbits_per_sample = _X_LE_16(&op->packet[41]); +  locwidth = _X_LE_32(&op->packet[45]); +  locheight = _X_LE_32(&op->packet[49]); + +  lprintf ("direct show filter created stream detected, hexdump:\n"); +#ifdef LOG +  xine_hexdump (op->packet, op->bytes); +#endif + +  channel = this->num_video_streams++; + +  this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (locsubtype); +  if( !this->si[stream_num]->buf_types ) +  { +    this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; +    _x_report_video_fourcc (this->stream->xine, LOG_MODULE, locsubtype); +  } +  this->si[stream_num]->buf_types |= channel; +  this->si[stream_num]->headers = 0; /* header is sent below */ + +  lprintf ("subtype          %.4s\n", (char*)&locsubtype); +  lprintf ("time_unit        %" PRId64 "\n", loctime_unit); +  lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); +  lprintf ("default_len      %d\n", locdefault_len); +  lprintf ("buffersize       %d\n", locbuffersize); +  lprintf ("bits_per_sample  %d\n", locbits_per_sample); +  lprintf ("width            %d\n", locwidth); +  lprintf ("height           %d\n", locheight); +  lprintf ("buf_type         %08x\n",this->si[stream_num]->buf_types); + +  bih.biSize=sizeof(xine_bmiheader); +  bih.biWidth = locwidth; +  bih.biHeight= locheight; +  bih.biPlanes= 0; +  memcpy(&bih.biCompression, &locsubtype, 4); +  bih.biBitCount= 0; +  bih.biSizeImage=locwidth*locheight; +  bih.biXPelsPerMeter=1; +  bih.biYPelsPerMeter=1; +  bih.biClrUsed=0; +  bih.biClrImportant=0; + +  buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); +  buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| +                       BUF_FLAG_FRAME_END; +  this->frame_duration = loctime_unit * 9 / 1000; +  this->si[stream_num]->factor = loctime_unit * 9; +  this->si[stream_num]->quotient = 1000; +  buf->decoder_info[0] = this->frame_duration; +  memcpy (buf->content, &bih, sizeof (xine_bmiheader)); +  buf->size = sizeof (xine_bmiheader); +  buf->type = this->si[stream_num]->buf_types; + +  /* video metadata */ +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, locsubtype); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, locwidth); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, locheight); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + +  this->avg_bitrate += 500000; /* FIXME */ + +  this->video_fifo->put (this->video_fifo, buf); +} + +static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + +  if (this->audio_fifo) { +    buf_element_t    *buf; +    int               codec; +    char              str[5]; +    int               channel; + +    int16_t          locbits_per_sample, locchannels, locblockalign; +    int32_t          locsize, locdefault_len, locbuffersize, locavgbytespersec; +    int64_t          loctime_unit, locsamples_per_unit; + +    locsize = _X_LE_32(&op->packet[13]); +    loctime_unit = _X_LE_64(&op->packet[17]); +    locsamples_per_unit = _X_LE_64(&op->packet[25]); +    locdefault_len = _X_LE_32(&op->packet[33]); +    locbuffersize = _X_LE_32(&op->packet[37]); +    locbits_per_sample = _X_LE_16(&op->packet[41]); +    locchannels = _X_LE_16(&op->packet[45]); +    locblockalign = _X_LE_16(&op->packet[47]); +    locavgbytespersec= _X_LE_32(&op->packet[49]); + +    lprintf ("direct show filter created audio stream detected, hexdump:\n"); +#ifdef LOG +    xine_hexdump (op->packet, op->bytes); +#endif + +    memcpy(str, &op->packet[9], 4); +    str[4] = 0; +    codec = strtoul(str, NULL, 16); + +    channel= this->num_audio_streams++; + +    this->si[stream_num]->buf_types = _x_formattag_to_buf_audio(codec); +    if( this->si[stream_num]->buf_types ) { +      this->si[stream_num]->buf_types |= channel; +    } else { +      this->si[stream_num]->buf_types = BUF_AUDIO_UNKNOWN; +      _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, codec); +      /*break;*/ +    } + +    lprintf ("subtype          0x%x\n", codec); +    lprintf ("time_unit        %" PRId64 "\n", loctime_unit); +    lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); +    lprintf ("default_len      %d\n", locdefault_len); +    lprintf ("buffersize       %d\n", locbuffersize); +    lprintf ("bits_per_sample  %d\n", locbits_per_sample); +    lprintf ("channels         %d\n", locchannels); +    lprintf ("blockalign       %d\n", locblockalign); +    lprintf ("avgbytespersec   %d\n", locavgbytespersec); +    lprintf ("buf_type         %08x\n",this->si[stream_num]->buf_types); + +    buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); +    buf->type = this->si[stream_num]->buf_types; +    buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; +    buf->decoder_info[0] = 0; +    buf->decoder_info[1] = locsamples_per_unit; +    buf->decoder_info[2] = locbits_per_sample; +    buf->decoder_info[3] = locchannels; +    this->audio_fifo->put (this->audio_fifo, buf); + +    this->si[stream_num]->headers = 0; /* header already sent */ +    this->si[stream_num]->factor = 90000; +    this->si[stream_num]->quotient = locsamples_per_unit; + +    this->avg_bitrate += locavgbytespersec*8; + +    /* audio metadata */ +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, codec); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, locchannels); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, locbits_per_sample); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, locsamples_per_unit); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, locavgbytespersec * 8); + +  } else /* no audio_fifo there */ +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +} + +static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + +  lprintf ("older Direct Show filter-generated stream header detected. Hexdump:\n"); +#ifdef LOG +  xine_hexdump (op->packet, op->bytes); +#endif + +  this->si[stream_num]->headers = 0; /* header is sent below */ + +  if ( (_X_LE_32(&op->packet[96]) == 0x05589f80) && (op->bytes >= 184)) { + +    buf_element_t    *buf; +    xine_bmiheader    bih; +    int               channel; +    uint32_t          fcc; + +    lprintf ("seems to be a video stream.\n"); + +    channel = this->num_video_streams++; +    fcc = *(uint32_t*)(op->packet+68); +    lprintf ("fourcc %08x\n", fcc); + +    this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (fcc); +    if( !this->si[stream_num]->buf_types ) +    { +      this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; +      _x_report_video_fourcc (this->stream->xine, LOG_MODULE, fcc); +    } +    this->si[stream_num]->buf_types |= channel; + +    bih.biSize          = sizeof(xine_bmiheader); +    bih.biWidth         = _X_LE_32(&op->packet[176]); +    bih.biHeight        = _X_LE_32(&op->packet[180]); +    bih.biPlanes        = 0; +    memcpy (&bih.biCompression, op->packet+68, 4); +    bih.biBitCount      = _X_LE_16(&op->packet[182]); +    if (!bih.biBitCount) +      bih.biBitCount = 24; /* FIXME ? */ +    bih.biSizeImage     = (bih.biBitCount>>3)*bih.biWidth*bih.biHeight; +    bih.biXPelsPerMeter = 1; +    bih.biYPelsPerMeter = 1; +    bih.biClrUsed       = 0; +    bih.biClrImportant  = 0; + +    buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); +    buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| +                         BUF_FLAG_FRAME_END; +    this->frame_duration = (*(int64_t*)(op->packet+164)) * 9 / 1000; +    this->si[stream_num]->factor = (*(int64_t*)(op->packet+164)) * 9; +    this->si[stream_num]->quotient = 1000; + +    buf->decoder_info[0] = this->frame_duration; +    memcpy (buf->content, &bih, sizeof (xine_bmiheader)); +    buf->size = sizeof (xine_bmiheader); +    buf->type = this->si[stream_num]->buf_types; +    this->video_fifo->put (this->video_fifo, buf); + +    lprintf ("subtype          %.4s\n", (char*)&fcc); +    lprintf ("buf_type         %08x\n", this->si[stream_num]->buf_types); +    lprintf ("video size       %d x %d\n", bih.biWidth, bih.biHeight); +    lprintf ("frame duration   %d\n", this->frame_duration); + +    /* video metadata */ +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, bih.biWidth); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, bih.biHeight); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + +    this->avg_bitrate += 500000; /* FIXME */ + +    this->ignore_keyframes = 1; + +  } else if (_X_LE_32(&op->packet[96]) == 0x05589F81) { + +#if 0 +    /* FIXME: no test streams */ + +    buf_element_t    *buf; +    int               codec; +    char              str[5]; +    int               channel; +    int               extra_size; + +    extra_size         = *(int16_t*)(op->packet+140); +    format             = *(int16_t*)(op->packet+124); +    channels           = *(int16_t*)(op->packet+126); +    samplerate         = *(int32_t*)(op->packet+128); +    nAvgBytesPerSec    = *(int32_t*)(op->packet+132); +    nBlockAlign        = *(int16_t*)(op->packet+136); +    wBitsPerSample     = *(int16_t*)(op->packet+138); +    samplesize         = (sh_a->wf->wBitsPerSample+7)/8; +    cbSize             = extra_size; +    if(extra_size > 0) +      memcpy(wf+sizeof(WAVEFORMATEX),op->packet+142,extra_size); +#endif + +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "FIXME, old audio format not handled\n"); + +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + +  } else { +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, +              "old header detected but stream type is unknown\n"); +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +  } +} + +static void decode_text_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +  int channel=0; +  uint32_t *val; +  buf_element_t *buf; + +  lprintf ("textstream detected.\n"); +  this->si[stream_num]->headers = 2; +  channel = this->num_spu_streams++; +  this->si[stream_num]->buf_types = BUF_SPU_OGM | channel; + +  /*send an empty spu to inform the video_decoder, that there is a stream*/ +  buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); +  buf->type = this->si[stream_num]->buf_types; +  buf->pts = 0; +  val = (uint32_t * )buf->content; +  *val++=0; +  *val++=0; +  *val++=0; +  this->video_fifo->put (this->video_fifo, buf); +} + +static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + +#ifdef HAVE_THEORA +  xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, +            "demux_ogg: Theorastreamsupport is highly alpha at the moment\n"); + +  if (theora_decode_header(&this->t_info, &this->t_comment, op) >= 0) { + +    this->num_video_streams++; + +    this->si[stream_num]->factor = (int64_t) 90000 * (int64_t) this->t_info.fps_denominator; + +    if (!this->t_info.fps_numerator) { +      this->t_info.fps_numerator = 1;   /* FIXME: default value ? */ +    } +    this->si[stream_num]->quotient = this->t_info.fps_numerator; + +    this->frame_duration = ((int64_t) 90000*this->t_info.fps_denominator); +    this->frame_duration /= this->t_info.fps_numerator; + +    this->si[stream_num]->granuleshift = intlog(this->t_info.keyframe_frequency_force-1); + +    this->si[stream_num]->headers=3; +    this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; + +    _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->t_info.frame_width); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->t_info.frame_height); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + +    /*currently aspect_nominator and -denumerator are 0?*/ +    if (this->t_info.aspect_denominator) { +      int64_t ratio = ((int64_t) this->t_info.aspect_numerator * 10000); + +      ratio /= this->t_info.aspect_denominator; +      _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, ratio); +    } + +    lprintf ("decoded theora header \n"); +    lprintf ("frameduration %d\n",this->frame_duration); +    lprintf ("w:%d h:%d \n",this->t_info.frame_width,this->t_info.frame_height); +    lprintf ("an:%d ad:%d \n",this->t_info.aspect_numerator,this->t_info.aspect_denominator); +  } else { +    /*Rejected stream*/ +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, +             "A theora header was rejected by libtheora\n"); +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +    this->si[stream_num]->headers = 0; /* FIXME: don't know */ +  } +#else +  this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; +  this->num_video_streams++; +  this->unhandled_video_streams++; +  _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); +#endif +} + +static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +  xine_flac_metadata_header header; +  xine_flac_streaminfo_block streaminfo = {}; +  buf_element_t *buf; +  xine_waveformatex wave; + +  /* Packet type */ +  _x_assert(op->packet[0] == 0x7F); + +  /* OggFLAC signature */ +  _x_assert(_X_BE_32(&op->packet[1]) == ME_FOURCC('F', 'L', 'A', 'C')); + +  /* Version: supported only 1.0 */ +  _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0); + +  /* Header count */ +  this->si[stream_num]->headers = 0/*_X_BE_16(&op->packet[7]) +1*/; + +  /* fLaC signature */ +  _x_assert(_X_BE_32(&op->packet[9]) == ME_FOURCC('f', 'L', 'a', 'C')); + +  _x_parse_flac_metadata_header(&op->packet[13], &header); + +  switch ( header.blocktype ) { +  case FLAC_BLOCKTYPE_STREAMINFO: +    _x_assert(header.length == FLAC_STREAMINFO_SIZE); +    _x_parse_flac_streaminfo_block(&op->packet[17], &streaminfo); + +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, streaminfo.samplerate); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, streaminfo.channels); +    _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, streaminfo.bits_per_sample); + +    break; +  } + +  this->si[stream_num]->buf_types = BUF_AUDIO_FLAC +    +this->num_audio_streams++; + +  this->si[stream_num]->factor = 90000; + +  buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + +  buf->type = BUF_AUDIO_FLAC; +  buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + +  buf->decoder_info[0] = 0; +  buf->decoder_info[1] = streaminfo.samplerate; +  buf->decoder_info[2] = streaminfo.bits_per_sample; +  buf->decoder_info[3] = streaminfo.channels; +  buf->size = sizeof(xine_waveformatex) + FLAC_STREAMINFO_SIZE; +  memcpy(buf->content+sizeof(xine_waveformatex), &op->packet[17], FLAC_STREAMINFO_SIZE); +  xine_hexdump(&op->packet[17], FLAC_STREAMINFO_SIZE); +  wave.cbSize = FLAC_STREAMINFO_SIZE; +  memcpy(buf->content, &wave, sizeof(xine_waveformatex)); + +  this->audio_fifo->put(this->audio_fifo, buf); + +  /* Skip the Ogg framing info */ +  op->bytes -= 9; +  op->packet += 9; +} + +static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +  lprintf ("Annodex stream detected\n"); +  this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +  this->si[stream_num]->headers = 1; +  this->si[stream_num]->header_granulepos = op->granulepos; +  _x_meta_info_set(this->stream, XINE_META_INFO_SYSTEMLAYER, "Annodex"); +} + +static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +  int64_t granule_rate_n, granule_rate_d; +  uint32_t secondary_headers; +  char content_type[1024]; +  int content_type_length; + +  lprintf("AnxData stream detected\n"); + +  /* read granule rate */ +  granule_rate_n = _X_LE_64(&op->packet[8]); +  granule_rate_d = _X_LE_64(&op->packet[16]); +  secondary_headers = _X_LE_32(&op->packet[24]); + +  lprintf("granule_rate %" PRId64 "/%" PRId64 ", %d secondary headers\n", +      granule_rate_n, granule_rate_d, secondary_headers); + +  /* read "Content-Tyoe" MIME header */ +  sscanf(&op->packet[28], "Content-Type: %1023s\r\n", content_type); +  content_type_length = strlen(content_type); + +  lprintf("Content-Type: %s (length:%d)\n", content_type, content_type_length); + +  /* how many header packets in the AnxData stream? */ +  this->si[stream_num]->headers = secondary_headers + 1; +  this->si[stream_num]->hide_first_header = 1; + +  /* set factor and quotient */ +  this->si[stream_num]->factor = (int64_t) 90000 * granule_rate_d; +  this->si[stream_num]->quotient = granule_rate_n; + +  lprintf("factor: %" PRId64 ", quotient: %" PRId64 "\n", +          this->si[stream_num]->factor, this->si[stream_num]->quotient); + +  /* what type of stream are we dealing with? */ +  if (!strncmp(content_type, "audio/x-vorbis", content_type_length)) { +#ifdef HAVE_VORBIS +    this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS; +#else +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif +    this->num_audio_streams++; +  } else if (!strncmp(content_type, "audio/x-speex", content_type_length)) { +    this->num_audio_streams++; +#ifdef HAVE_SPEEX +    this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX; +#else +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif +  } else if (!strncmp(content_type, "video/x-theora", content_type_length)) { +    this->num_video_streams++; +#ifdef HAVE_THEORA +    this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; +#else +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif +  } else if (!strncmp(content_type, "text/x-cmml", content_type_length)) { +    unsigned int channel = this->num_spu_streams++; +    this->si[stream_num]->headers = 0; +    this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; +    this->si[stream_num]->granuleshift = 0; +  } else { +    this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +  } +   +} + +static void decode_cmml_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +    unsigned int channel = this->num_spu_streams++; +    this->si[stream_num]->headers = 0; +    this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; + +    this->si[stream_num]->factor = 90000 * _X_LE_64(&op->packet[20]); +    this->si[stream_num]->quotient = _X_LE_64(&op->packet[12]); +    this->si[stream_num]->granuleshift = (int)op->packet[28]; +} + +/* + * interpret stream start packages, send headers + */ +static void send_header (demux_ogg_t *this) { + +  int          stream_num = -1; +  int          cur_serno; +  int          done = 0; +  ogg_packet   op; +  xine_event_t ui_event; + +  lprintf ("detecting stream types...\n"); + +  this->ignore_keyframes = 0; + +  while (!done) { +    if (!read_ogg_packet(this)) { +      return; +    } +    /* now we've got at least one new page */ + +    cur_serno = ogg_page_serialno (&this->og); + +    if (ogg_page_bos(&this->og)) { +      lprintf ("beginning of stream\n"); +      lprintf ("serial number %d\n", cur_serno); + +      if( this->num_streams == MAX_STREAMS ) { +        xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); +        this->status = DEMUX_FINISHED; +        return; +      } +      stream_num = new_stream_info(this, cur_serno); + +    } else { +      stream_num = get_stream(this, cur_serno); +      if (stream_num == -1) { +        xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: stream with no beginning!\n"); +        this->status = DEMUX_FINISHED; +        return; +      } +    } + +    ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); + +    while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { + +      if (!this->si[stream_num]->buf_types) { + +        /* detect buftype */ +        if (!memcmp (&op.packet[1], "vorbis", 6)) { +          decode_vorbis_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[0], "Speex", 5)) { +          decode_speex_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[1], "video", 5)) { +          decode_video_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[1], "audio", 5)) { +          decode_audio_header(this, stream_num, &op); +        } else if (op.bytes >= 142 +                   && !memcmp (&op.packet[1], "Direct Show Samples embedded in Ogg", 35) ) { +          decode_dshow_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[1], "text", 4)) { +          decode_text_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[1], "theora", 6)) { +          decode_theora_header(this, stream_num, &op); +	} else if (!memcmp (&op.packet[1], "FLAC", 4)) { +	  decode_flac_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[0], "Annodex", 7)) { +          decode_annodex_header(this, stream_num, &op); +        } else if (!memcmp (&op.packet[0], "AnxData", 7)) { +          decode_anxdata_header(this, stream_num, &op); +	} else if (!memcmp (&op.packet[0], "CMML", 4)) { +	  decode_cmml_header(this, stream_num, &op); +        } else { +          xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, +                  "demux_ogg: unknown stream type (signature >%.8s<). hex dump of bos packet follows:\n", +                  op.packet); +          if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) +            xine_hexdump (op.packet, op.bytes); + +          this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +        } +      } + +      /* send preview buffer */ +      if (this->si[stream_num]->headers > 0 || +          op.packet[0] == PACKET_TYPE_COMMENT) { +        if (this->si[stream_num]->hide_first_header) +          this->si[stream_num]->hide_first_header = 0; +        else { +          lprintf ("sending preview buffer of stream type %08x\n", +              this->si[stream_num]->buf_types); + +          send_ogg_buf (this, &op, stream_num, BUF_FLAG_HEADER); +          this->si[stream_num]->headers --; +        } +      } + +      /* are we finished ? */ +      if (!ogg_page_bos(&this->og)) { +        int i; +        done = 1; + +        for (i=0; i<this->num_streams; i++) { +          if (this->si[i]->headers > 0) +            done = 0; + +          llprintf(DEBUG_PREVIEWS, +                   "%d preview buffers left to send from stream %d\n", +                   this->si[i]->headers, i); +        } +      } +    } +  } + +  ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED; +  ui_event.data_length = 0; +  xine_event_send(this->stream, &ui_event); + +  /*get the streamlength*/ +  get_stream_length (this); + +} + +static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { +  demux_ogg_t *this = (demux_ogg_t *) this_gen; + +  int stream_num; +  int cur_serno; + +  ogg_packet op; + +  ogg_handle_event(this); + +  llprintf(DEBUG_PACKETS, "send package...\n"); + +  if (!read_ogg_packet(this)) { +    this->status = DEMUX_FINISHED; +    lprintf ("EOF\n"); +    return this->status; +  } + +  /* now we've got one new page */ + +  cur_serno = ogg_page_serialno (&this->og); +  stream_num = get_stream(this, cur_serno); +  if (stream_num < 0) { +    lprintf ("error: unknown stream, serialnumber %d\n", cur_serno); + +    if (!ogg_page_bos(&this->og)) { +      lprintf ("help, stream with no beginning!\n"); +    } +    lprintf ("adding late stream with serial number %d (all content will be discarded)\n", cur_serno); + +    if( this->num_streams == MAX_STREAMS ) { +      xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); +      this->status = DEMUX_FINISHED; +      return this->status; +    } +    stream_num = new_stream_info(this, cur_serno); +  } + +  ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); + +  if (ogg_page_bos(&this->og)) { +    lprintf ("beginning of stream: serial number %d - discard\n", +             ogg_page_serialno (&this->og)); +    while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) ; +    return this->status; +  } + +  /*while keyframeseeking only process videostream*/ +    if (!this->ignore_keyframes && this->keyframe_needed +      && ((this->si[stream_num]->buf_types & 0xFF000000) != BUF_VIDEO_BASE)) +    return this->status; + +  while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { +    /* printf("demux_ogg: packet: %.8s\n", op.packet); */ +    /* printf("demux_ogg:   got a packet\n"); */ + +    if ((*op.packet & PACKET_TYPE_HEADER) && +        (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX) && (this->si[stream_num]->buf_types!=BUF_AUDIO_FLAC)) { +      if (op.granulepos != -1) { +        this->si[stream_num]->header_granulepos = op.granulepos; +        lprintf ("header with granulepos, remembering granulepos\n"); +      } else { +        lprintf ("header => discard\n"); +      } +      continue; +    } + +    /*discard granulepos-less packets and to early audiopackets*/ +    if (this->si[stream_num]->resync) { +      if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { +        /*never drop subtitles*/ +        this->si[stream_num]->resync=0; +      } else if ((op.granulepos == -1) && (this->si[stream_num]->header_granulepos == -1)) { +        continue; +      } else { + +        /*dump too early packets*/ +        if ((get_pts(this,stream_num,op.granulepos)-this->start_pts) > -90000) +          this->si[stream_num]->resync=0; +        else +          continue; +      } +    } + +    if (!this->ignore_keyframes && this->keyframe_needed) { +      lprintf ("keyframe needed... buf_type=%08x\n", this->si[stream_num]->buf_types); +      if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA) { +#ifdef HAVE_THEORA + +        int keyframe_granule_shift; +        int64_t pframe=-1,iframe=-1; + +	keyframe_granule_shift = this->si[stream_num]->granuleshift; + +        if(op.granulepos>=0){ +          iframe=op.granulepos>>keyframe_granule_shift; +          pframe=op.granulepos-(iframe<<keyframe_granule_shift); +          xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, +                   "seeking keyframe i %" PRId64 " p %" PRId64 "\n", iframe, pframe); +          if (pframe!=0) +            continue; +        } else +          continue; +        this->keyframe_needed = 0; +        this->start_pts=get_pts(this,stream_num,op.granulepos); +#endif +      } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { + +      /*calculate the current pts*/ +      if (op.granulepos!=-1) { +        this->start_pts=get_pts(this, stream_num, op.granulepos); +      } else if (this->start_pts!=-1) +        this->start_pts=this->start_pts+this->frame_duration; + +      /*seek the keyframe*/ +      if ((*op.packet == PACKET_IS_SYNCPOINT) && (this->start_pts!=-1)) +        this->keyframe_needed = 0; +      else +        continue; + +      } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) continue; +    } +    send_ogg_buf (this, &op, stream_num, 0); + +    /*delete used header_granulepos*/ +    if (op.granulepos == -1) +      this->si[stream_num]->header_granulepos = -1; + +  } +  if (ogg_page_eos(&this->og)) { +    int i; +    int finished_streams = 0; +   +    lprintf("end of stream, serialnumber %d\n", cur_serno); +    this->si[stream_num]->delivered_eos = 1; +   +    /* check if all logical streams are finished */ +    for (i = 0; i < this->num_streams; i++) { +      finished_streams += this->si[i]->delivered_eos; +    } + +    /* if all streams are finished, perhaps a chained stream follows */ +    if (finished_streams == this->num_streams) { +      /* delete current logical streams */ +      for (i = 0; i < this->num_streams; i++) { +        ogg_stream_clear(&this->si[i]->oss); +        if (this->si[i]->language) { +          free (this->si[i]->language); +        } +        free (this->si[i]); +      } +      this->num_streams       = 0; +      this->num_audio_streams = 0; +      this->num_video_streams = 0; +      this->unhandled_video_streams = 0; +      this->num_spu_streams   = 0; +      this->avg_bitrate       = 1; +       +      /* try to read a chained stream */ +      this->send_newpts = 1; +      this->last_pts[0] = 0; +      this->last_pts[1] = 0; +       +      /* send control buffer to avoid buffer leak */ +      _x_demux_control_end(this->stream, 0); +      _x_demux_control_start(this->stream); +      send_header(this); +    } +  } + +  return this->status; +} + +static void demux_ogg_dispose (demux_plugin_t *this_gen) { +  demux_ogg_t *this = (demux_ogg_t *) this_gen; +  int i; + +  for (i=0; i<this->num_streams; i++) { +    ogg_stream_clear(&this->si[i]->oss); + +    if (this->si[i]->language) { +      free (this->si[i]->language); +    } +    free(this->si[i]); +  } + +  ogg_sync_clear(&this->oy); + +#ifdef HAVE_THEORA +  theora_comment_clear (&this->t_comment); +  theora_info_clear (&this->t_info); +#endif + +  if (this->chapter_info){ +    free (this->chapter_info->entries); +    free (this->chapter_info); +  } +  if (this->title){ +    free (this->title); +  } +  if (this->event_queue) +    xine_event_dispose_queue (this->event_queue); + +  free (this); +} + +static int demux_ogg_get_status (demux_plugin_t *this_gen) { +  demux_ogg_t *this = (demux_ogg_t *) this_gen; + +  return this->status; +} + +static void demux_ogg_send_headers (demux_plugin_t *this_gen) { +  demux_ogg_t *this = (demux_ogg_t *) this_gen; + +  this->video_fifo  = this->stream->video_fifo; +  this->audio_fifo  = this->stream->audio_fifo; + +  this->status = DEMUX_OK; + +  /* +   * send start buffers +   */ + +  this->last_pts[0]   = 0; +  this->last_pts[1]   = 0; + +  /* +   * initialize ogg engine +   */ +  ogg_sync_init(&this->oy); + +  this->num_streams       = 0; +  this->num_audio_streams = 0; +  this->num_video_streams = 0; +  this->num_spu_streams   = 0; +  this->avg_bitrate       = 1; + +  this->input->seek (this->input, 0, SEEK_SET); + +  if (this->status == DEMUX_OK) { +    _x_demux_control_start(this->stream); +    send_header (this); +    lprintf ("headers sent, avg bitrate is %" PRId64 "\n", this->avg_bitrate); +  } + +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, +                       this->num_video_streams > 0); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, +		     this->num_video_streams > this->unhandled_video_streams); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, +                       this->num_audio_streams > 0); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL, +                       this->num_spu_streams); +} + +static int demux_ogg_seek (demux_plugin_t *this_gen, +			   off_t start_pos, int start_time, int playing) { + +  demux_ogg_t *this = (demux_ogg_t *) this_gen; +  int i; +  start_time /= 1000; +  start_pos = (off_t) ( (double) start_pos / 65535 * +              this->input->get_length (this->input) ); +  /* +   * seek to start position +   */ + +  if (INPUT_IS_SEEKABLE(this->input)) { + +    this->keyframe_needed = (this->num_video_streams>0); + +    if ( (!start_pos) && (start_time)) { +      if (this->time_length != -1) { +	/*do the seek via time*/ +	int current_time=-1; +	off_t current_pos; +	current_pos=this->input->get_current_pos(this->input); + +	/*try to find out the current time*/ +	if (this->last_pts[PTS_VIDEO]) { +	  current_time=this->last_pts[PTS_VIDEO]/90000; +	} else if (this->last_pts[PTS_AUDIO]) { +	  current_time=this->last_pts[PTS_AUDIO]/90000; +	} + +	/*fixme, the file could grow, do something +	 about this->time_length using get_lenght to verify, that the stream +	hasn` changed its length, otherwise no seek to "new" data is possible*/ + +	lprintf ("seek to time %d called\n",start_time); +	lprintf ("current time is %d\n",current_time);  + +	if (current_time > start_time) { +	  /*seek between beginning and current_pos*/ + +	  /*fixme - sometimes we seek backwards and during +	    keyframeseeking, we undo the seek*/ + +	  start_pos = start_time * current_pos +	  / current_time ; +	} else { +	  /*seek between current_pos and end*/ +	  start_pos = current_pos + +	    ((start_time - current_time) * +	     ( this->input->get_length(this->input) - current_pos ) / +	     ( (this->time_length / 1000) - current_time) +	    ); +	} + +	lprintf ("current_pos is %" PRId64 "\n",current_pos); +	lprintf ("new_pos is %" PRId64 "\n",start_pos);  + +      } else { +	/*seek using avg_bitrate*/ +	start_pos = start_time * this->avg_bitrate/8; +      } + +      lprintf ("seeking to %d seconds => %" PRId64 " bytes\n", +	      start_time, start_pos); + +    } + +    ogg_sync_reset(&this->oy); + +    for (i=0; i<this->num_streams; i++) { +      this->si[i]->header_granulepos = -1; +      ogg_stream_reset(&this->si[i]->oss); +    } + +    /*some strange streams have no syncpoint flag set at the beginning*/	  +    if (start_pos == 0)	  +      this->keyframe_needed = 0;	  + +    lprintf ("seek to %" PRId64 " called\n",start_pos); + +    this->input->seek (this->input, start_pos, SEEK_SET); + +  } + +  /* fixme - this would be a nice position to do the following tasks +     1. adjust an ogg videostream to a keyframe +     2. compare the keyframe_pts with start_time. if the difference is to +        high (e.g. larger than max keyframe_intervall, do a new seek or  +	continue reading +     3. adjust the audiostreams in such a way, that the +        difference is not to high. + +     In short words, do all the cleanups necessary to continue playback +     without further actions +  */ +   +  this->send_newpts     = 1; +  this->status          = DEMUX_OK; +   +  if( !playing ) { +     +    this->buf_flag_seek     = 0; + +  } else { +    if (start_pos!=0) { +      this->buf_flag_seek = 1; +      /*each stream has to continue with a packet that has an +       granulepos*/ +      for (i=0; i<this->num_streams; i++) { +	this->si[i]->resync = 1; +      } + +      this->start_pts=-1; +    } + +    _x_demux_flush_engine(this->stream); +  } +   +  return this->status; +} + +static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) { + +  demux_ogg_t *this = (demux_ogg_t *) this_gen;  + +  if (this->time_length==-1){ +    if (this->avg_bitrate) { +      return (int)((int64_t)1000 * this->input->get_length (this->input) * 8 / +		   this->avg_bitrate); +    } else { +      return 0; +    } +  } else { +    return this->time_length; +  } +} + +static uint32_t demux_ogg_get_capabilities(demux_plugin_t *this_gen) { +  demux_ogg_t *this = (demux_ogg_t *) this_gen;  +  int cap_chapter = 0; + +  if (this->chapter_info) +    cap_chapter = DEMUX_CAP_CHAPTERS; + +  return DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG | cap_chapter; +} + +static int format_lang_string (demux_ogg_t * this, uint32_t buf_mask, uint32_t buf_type, int channel, char *str) { +  int stream_num; + +  for (stream_num=0; stream_num<this->num_streams; stream_num++) { +    if ((this->si[stream_num]->buf_types & buf_mask) == buf_type) { +      if (this->si[stream_num]->language) { +        if (snprintf (str, XINE_LANG_MAX, "%s", this->si[stream_num]->language) >= XINE_LANG_MAX) +          /* the string got truncated */ +          str[XINE_LANG_MAX - 2] = str[XINE_LANG_MAX - 3] = str[XINE_LANG_MAX - 4] = '.'; +        /* TODO: provide long version in XINE_META_INFO_FULL_LANG */ +      } else { +        snprintf(str, XINE_LANG_MAX, "channel %d",channel); +      } +      return DEMUX_OPTIONAL_SUCCESS; +    } +  } +  return DEMUX_OPTIONAL_UNSUPPORTED; +} + +static int demux_ogg_get_optional_data(demux_plugin_t *this_gen, +					void *data, int data_type) { +   +  demux_ogg_t *this = (demux_ogg_t *) this_gen;  + +  char *str=(char *) data; +  int channel = *((int *)data); + +  switch (data_type) { +  case DEMUX_OPTIONAL_DATA_SPULANG: +    lprintf ("DEMUX_OPTIONAL_DATA_SPULANG channel = %d\n",channel); +    if (channel==-1) { +      strcpy( str, "none"); +      return DEMUX_OPTIONAL_SUCCESS; +    } else if ((channel>=0) && (channel<this->num_streams)) { +      return format_lang_string (this, 0xFFFFFFFF, BUF_SPU_OGM+channel, channel, str); +    } +    return DEMUX_OPTIONAL_UNSUPPORTED; +  case DEMUX_OPTIONAL_DATA_AUDIOLANG: +    lprintf ("DEMUX_OPTIONAL_DATA_AUDIOLANG channel = %d\n",channel); +    if (channel==-1) { +      return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE, channel, str); +    } else if ((channel>=0) && (channel<this->num_streams)) { +      return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE+channel, channel, str); +    } +    return DEMUX_OPTIONAL_UNSUPPORTED; +  default: +    return DEMUX_OPTIONAL_UNSUPPORTED; +  } +} + +static int detect_ogg_content (int detection_method, demux_class_t *class_gen, +                               input_plugin_t *input) { + +  switch (detection_method) { + +    case METHOD_BY_CONTENT: { +      uint32_t header; + +      if (_x_demux_read_header(input, &header, 4) != 4) +        return 0; + +      return !!( header == ME_FOURCC('O', 'g', 'g', 'S') ); +    } + +    case METHOD_BY_MRL: +    case METHOD_EXPLICIT: +      return 1; + +    default: +      return 0; +  } +} + +static int detect_anx_content (int detection_method, demux_class_t *class_gen, +    input_plugin_t *input) { + +  if (detect_ogg_content(detection_method, class_gen, input) == 0) +    return 0; + +  switch (detection_method) { + +#define ANNODEX_SIGNATURE_SEARCH 128 + +    case METHOD_BY_CONTENT: { +      uint8_t buf[ANNODEX_SIGNATURE_SEARCH]; + +      if (_x_demux_read_header(input, buf, ANNODEX_SIGNATURE_SEARCH) != +          ANNODEX_SIGNATURE_SEARCH) +        return 0; + +      /* scan for 'Annodex' signature in the first 64 bytes */ +      return !!memmem(buf, ANNODEX_SIGNATURE_SEARCH, +		      "Annodex", sizeof("Annodex")-1); +    } + +#undef ANNODEX_SIGNATURE_SEARCH + +    case METHOD_BY_MRL: +    case METHOD_EXPLICIT: +      return 1; + +    default: +      return 0; +  } +} + +static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, +				        xine_stream_t *stream,  +				        input_plugin_t *input) { + +  demux_ogg_t *this; + +  if (detect_anx_content(stream->content_detection_method, class_gen, input) == 0) +    return NULL; + +  /* +   * if we reach this point, the input has been accepted. +   */ + +  this         = xine_xmalloc (sizeof (demux_ogg_t)); +  memset (this, 0, sizeof(demux_ogg_t)); +  this->stream = stream; +  this->input  = input; + +  /* the Annodex demuxer currently calls into exactly the same functions as +   * the Ogg demuxer, which seems to make this function a bit redundant, but +   * this design leaves us a bit more room to change an Annodex demuxer's +   * behaviour in the future if necessary */ +  this->demux_plugin.send_headers      = demux_ogg_send_headers; +  this->demux_plugin.send_chunk        = demux_ogg_send_chunk; +  this->demux_plugin.seek              = demux_ogg_seek; +  this->demux_plugin.dispose           = demux_ogg_dispose; +  this->demux_plugin.get_status        = demux_ogg_get_status; +  this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; +  this->demux_plugin.get_capabilities  = demux_ogg_get_capabilities; +  this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; +  this->demux_plugin.demux_class       = class_gen; +   +  this->status = DEMUX_FINISHED; + +#ifdef HAVE_THEORA +  theora_info_init (&this->t_info); +  theora_comment_init (&this->t_comment); +#endif   + +  this->chapter_info = 0; +  this->title = 0; +  this->event_queue = xine_event_new_queue (this->stream); + +  return &this->demux_plugin; +} + +static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, +				        xine_stream_t *stream,  +				        input_plugin_t *input) { + +  demux_ogg_t *this; + +  if (detect_ogg_content(stream->content_detection_method, class_gen, input) == 0) +    return NULL; + +  /* +   * if we reach this point, the input has been accepted. +   */ + +  this         = xine_xmalloc (sizeof (demux_ogg_t)); +  memset (this, 0, sizeof(demux_ogg_t)); +  this->stream = stream; +  this->input  = input; + +  this->demux_plugin.send_headers      = demux_ogg_send_headers; +  this->demux_plugin.send_chunk        = demux_ogg_send_chunk; +  this->demux_plugin.seek              = demux_ogg_seek; +  this->demux_plugin.dispose           = demux_ogg_dispose; +  this->demux_plugin.get_status        = demux_ogg_get_status; +  this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; +  this->demux_plugin.get_capabilities  = demux_ogg_get_capabilities; +  this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; +  this->demux_plugin.demux_class       = class_gen; +   +  this->status = DEMUX_FINISHED; + +#ifdef HAVE_THEORA +  theora_info_init (&this->t_info); +  theora_comment_init (&this->t_comment); +#endif   + +  this->chapter_info = 0; +  this->title = 0; +  this->event_queue = xine_event_new_queue (this->stream); + +  return &this->demux_plugin; +} + +/* + * Annodex demuxer class + */ +static void *anx_init_class (xine_t *xine, void *data) { +  demux_anx_class_t     *this; + +  this = xine_xmalloc (sizeof (demux_anx_class_t)); + +  this->demux_class.open_plugin     = anx_open_plugin; +  this->demux_class.description     = N_("Annodex demux plugin"); +  this->demux_class.identifier      = "Annodex"; +  this->demux_class.mimetypes       =  +    "application/annodex: anx: Annodex media;" +    "application/x-annodex: anx: Annodex media;" +    "audio/annodex: axa: Annodex audio;" +    "audio/x-annodex: axa: Annodex audio;" +    "video/annodex: axv: Annodex video;" +    "video/x-annodex: axv: Annodex video;"; +  this->demux_class.extensions      = "anx axa axv"; +  this->demux_class.dispose         = default_demux_class_dispose; + +  return this; +} + +/* + * ogg demuxer class + */ +static void *ogg_init_class (xine_t *xine, void *data) { +  demux_ogg_class_t     *this; + +  this = xine_xmalloc (sizeof (demux_ogg_class_t)); + +  this->demux_class.open_plugin     = ogg_open_plugin; +  this->demux_class.description     = N_("OGG demux plugin"); +  this->demux_class.identifier      = "OGG"; +  this->demux_class.mimetypes       = +    "application/ogg: ogx: Ogg Stream;" +    "application/x-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..5116f70e2 --- /dev/null +++ b/src/combined/xine_speex_decoder.c @@ -0,0 +1,403 @@ +/*  + * Copyright (C) 2000-2003 the xine project + *  + * This file is part of xine, a free video player. + *  + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *  + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * (ogg/)speex audio decoder plugin (libspeex wrapper) for xine + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#define LOG_MODULE "speex_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ +#define LOG_BUFFERS 0 + +#include <xine/xine_internal.h> +#include <xine/audio_out.h> +#include <xine/buffer.h> + +#include <ogg/ogg.h> + +#include <speex/speex.h> +#include <speex/speex_header.h> +#include <speex/speex_callbacks.h> +#include <speex/speex_stereo.h> + +#define MAX_FRAME_SIZE 2000 + +typedef struct { +  audio_decoder_class_t   decoder_class; +} speex_class_t; + +typedef struct speex_decoder_s { +  audio_decoder_t   audio_decoder; + +  int64_t           pts; + +  int               output_sampling_rate; +  int               output_open; +  int               output_mode; + +  /* speex stuff */ +  void             *st; +  int               frame_size; +  int               rate; +  int               nframes; +  int               channels; +  SpeexBits         bits; +  SpeexStereoState  stereo; +  int               expect_metadata; + +  int               header_count; + +  xine_stream_t    *stream; + +} speex_decoder_t; + + +static void speex_reset (audio_decoder_t *this_gen) { + +  speex_decoder_t *this = (speex_decoder_t *) this_gen; + +  speex_bits_init (&this->bits); +} + +static void speex_discontinuity (audio_decoder_t *this_gen) { + +  speex_decoder_t *this = (speex_decoder_t *) this_gen; + +  this->pts=0; +} + +/* Known speex comment keys from ogg123 sources*/ +static const struct { +  char key[16];         /* includes the '=' for programming convenience */ +  int   xine_metainfo_index; +} speex_comment_keys[] = { +  {"ARTIST=", XINE_META_INFO_ARTIST}, +  {"ALBUM=", XINE_META_INFO_ALBUM}, +  {"TITLE=", XINE_META_INFO_TITLE}, +  {"GENRE=", XINE_META_INFO_GENRE}, +  {"DESCRIPTION=", XINE_META_INFO_COMMENT}, +  {"DATE=", XINE_META_INFO_YEAR} +}; + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ +                           ((buf[base+2]<<16)&0xff0000)| \ +                           ((buf[base+1]<<8)&0xff00)| \ +                            (buf[base]&0xff)) + +static +void read_metadata (speex_decoder_t *this, char * comments, int length) +{ +  char * c = comments; +  int len, i, nb_fields; +  char * end; + +  _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "speex"); + +  if (length < 8) { +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); +    return; +  } + +  end = c+length; +  len = readint (c, 0); +  c += 4; + +  if (c+len > end) { +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); +    return; +  } + +#ifdef LOG +  /* Encoder */ +  printf ("libspeex: "); +  fwrite (c, 1, len, stdout); +  printf ("\n"); +#endif + +  c += len; + +  if (c+4 > end) { +    xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); +    return; +  } + +  nb_fields = readint (c, 0); +  c += 4; + +  for (i = 0; i < nb_fields; i++) { +    if (c+4 > end) { +      xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); +      return; +    } + +    len = readint (c, 0); +    c += 4; +    if (c+len > end) { +      xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); +      return; +    } + +#ifdef LOG +    printf ("libspeex: "); +    fwrite (c, 1, len, stdout); +    printf ("\n"); +#endif + +    for (i = 0; i < (sizeof(speex_comment_keys)/sizeof(speex_comment_keys[0])); i++) { +      if ( !strncasecmp (speex_comment_keys[i].key, c, +			 strlen(speex_comment_keys[i].key)) ) { +	int keylen = strlen(speex_comment_keys[i].key); +	char meta_info[(len - keylen) + 1]; +	 +	lprintf ("known metadata %d %d\n", +		 i, speex_comment_keys[i].xine_metainfo_index); +	 +	snprintf(meta_info, (len - keylen), "%s", c + keylen); +	_x_meta_info_set_utf8(this->stream, speex_comment_keys[i].xine_metainfo_index, meta_info); +      } +    } + +    c += len; +  } +} + +static void speex_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + +  speex_decoder_t *this = (speex_decoder_t *) this_gen; +  char *const buf_content = (char*)buf->content; + +  llprintf (LOG_BUFFERS, "decode buf=%8p content=%8p flags=%08x\n", +	    buf, buf->content, buf->decoder_flags); + +  if ( (buf->decoder_flags & BUF_FLAG_HEADER) && +       !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { +    lprintf ("preview buffer, %d headers to go\n", this->header_count); + +    if (this->header_count) { + +      if (!this->st) { +	SpeexMode * spx_mode; +	SpeexHeader * spx_header; +	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 *) xine_xmalloc (sizeof (speex_decoder_t)); + +  this->audio_decoder.decode_data         = speex_decode_data; +  this->audio_decoder.reset               = speex_reset; +  this->audio_decoder.discontinuity       = speex_discontinuity; +  this->audio_decoder.dispose             = speex_dispose; +  this->stream                            = stream; + +  this->output_open     = 0; +  this->header_count    = 1; +  this->expect_metadata = 0; + +  this->st = NULL; + +  this->channels = 1; + +  memcpy (&this->stereo, &init_stereo, sizeof (SpeexStereoState)); + +  return (audio_decoder_t *) this; +} + +/* + * speex plugin class + */ + +void *speex_init_plugin (xine_t *xine, void *data) { + +  speex_class_t *this; +   +  this = (speex_class_t *) xine_xmalloc (sizeof (speex_class_t)); + +  this->decoder_class.open_plugin     = open_plugin; +  this->decoder_class.identifier      = "speex"; +  this->decoder_class.description     = N_("Speex audio decoder plugin"); +  this->decoder_class.dispose         = default_audio_decoder_class_dispose; + +  return this; +} + +static const uint32_t audio_types[] = {  +  BUF_AUDIO_SPEEX, 0 + }; + +const decoder_info_t dec_info_speex = { +  audio_types,         /* supported types */ +  5                    /* priority        */ +}; diff --git a/src/combined/xine_theora_decoder.c b/src/combined/xine_theora_decoder.c new file mode 100644 index 000000000..96d4ca8f0 --- /dev/null +++ b/src/combined/xine_theora_decoder.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2001-2003 the xine project + *  + * This file is part of xine, a free video player. + *  + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *  + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * xine decoder plugin using libtheora + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <pthread.h> +#include <math.h> +#include <assert.h> +#include <theora/theora.h> + +#define LOG_MODULE "theora_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include <xine/xine_internal.h> +#include <xine/video_out.h> +#include <xine/buffer.h> +#include <xine/metronom.h> +#include <xine/xineutils.h> + +typedef struct theora_class_s { +  video_decoder_class_t   decoder_class; +} theora_class_t; + +typedef struct theora_decoder_s { +  video_decoder_t    theora_decoder; +  theora_class_t     *class; +  theora_info        t_info; +  theora_comment     t_comment; +  theora_state       t_state; +  ogg_packet         op; +  yuv_buffer         yuv; +  xine_stream_t*     stream; +  int                reject; +  int                op_max_size; +  unsigned char*     packet; +  int                done; +  int                width, height; +  double             ratio; +  int                offset_x, offset_y; +  int                frame_duration; +  int                skipframes; +  int                hp_read; +  int                initialized; +} theora_decoder_t; + +static void readin_op (theora_decoder_t *this, unsigned char* src, int size) { +  if ( this->done+size > this->op_max_size) { +    while (this->op_max_size < this->done+size) +      this->op_max_size=this->op_max_size*2; +    this->packet=realloc(this->packet, this->op_max_size); +    this->op.packet=this->packet; +  } +  xine_fast_memcpy ( this->packet+this->done, src, size); +  this->done=this->done+size; +} + +static void yuv2frame(yuv_buffer *yuv, vo_frame_t *frame, int offset_x, int offset_y) { +  int i; +  int crop_offset; + +  /* fixme - direct rendering (exchaning pointers) may be possible. +   * frame->base[0] = yuv->y could work if one could change the +   * pitches[0,1,2] values, and rely on the drawing routine using +   * the new pitches. With cropping and offsets, it's a bit trickier, +   * but it would still be possible. +   * Attempts at doing this have yielded nothing but SIGSEVs so far. +   */ + +  /* Copy yuv data onto the frame. Cropping and offset as specified +   * by the frame_width, frame_height, offset_x and offset_y fields +   * in the theora header is carried out. +   */ + +  crop_offset=offset_x+yuv->y_stride*offset_y; +  for(i=0;i<frame->height;i++) +    xine_fast_memcpy(frame->base[0]+frame->pitches[0]*i,  +		     yuv->y+crop_offset+yuv->y_stride*i,  +		     frame->width); + +  crop_offset=(offset_x/2)+(yuv->uv_stride)*(offset_y/2); +  for(i=0;i<frame->height/2;i++){ +    xine_fast_memcpy(frame->base[1]+frame->pitches[1]*i,  +		     yuv->u+crop_offset+yuv->uv_stride*i,  +		     frame->width/2); +    xine_fast_memcpy(frame->base[2]+frame->pitches[2]*i,  +		     yuv->v+crop_offset+yuv->uv_stride*i,  +		     frame->width/2); + +  } +} + +static int collect_data (theora_decoder_t *this, buf_element_t *buf ) { +  /* Assembles an ogg_packet which was sent with send_ogg_packet over xinebuffers */ +  /* this->done, this->rejected, this->op and this->decoder->flags are needed*/ + +  if (buf->decoder_flags & BUF_FLAG_FRAME_START) { +    this->done=0;  /*start from the beginnig*/ +    this->reject=0;/*new packet - new try*/  + +    /*copy the ogg_packet struct and the sum, correct the adress of the packet*/ +    xine_fast_memcpy (&this->op, buf->content, sizeof(ogg_packet)); +    this->op.packet=this->packet; + +    readin_op (this, buf->content + sizeof(ogg_packet), buf->size - sizeof(ogg_packet) ); +    /*read the rest of the data*/ + +  } else { +    if (this->done==0 || this->reject) { +      /*we are starting to collect an packet without the beginnig +	reject the rest*/ +      printf ("libtheora: rejecting packet\n"); +      this->reject=1; +      return 0; +    } +    readin_op (this, buf->content, buf->size ); +  } +   +  if ((buf->decoder_flags & BUF_FLAG_FRAME_END) && !this->reject) { +    if ( this->done != this->op.bytes ) { +      printf ("libtheora: A packet changed its size during transfer - rejected\n"); +      printf ("           size %d    should be %ld\n", this->done , this->op.bytes); +      this->op.bytes=this->done; +    } +    return 1; +  } +  return 0; +} + +static void theora_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { +  /* +   * decode data from buf and feed decoded frames to  +   * video output  +   */ +  theora_decoder_t *this = (theora_decoder_t *) this_gen; +  vo_frame_t *frame; +  yuv_buffer yuv; +  int ret; + +  if (!collect_data(this, buf)) return; +  /*return, until a entire packets is collected*/ + +  if ( (buf->decoder_flags & BUF_FLAG_HEADER) && +       !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { +    /*get the first 3 packets and decode the header during preview*/ + +    if (this->hp_read==0) { +      /*decode first hp*/ +      if (theora_decode_header(&this->t_info, &this->t_comment, &this->op)>=0) { +	this->hp_read++; +	return; +      } +    } + +    if (this->hp_read==1) { +      /*decode three header packets*/ +      if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { +	printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); +      } else { +	this->hp_read++; +	return; +      } +    } + +    if (this->hp_read==2) { +      if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { +	printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); +      } +      /*headers are now decoded. initialize the decoder*/ +      theora_decode_init (&this->t_state, &this->t_info); +       +      lprintf("theora stream is Theora %dx%d %.02f fps video.\n" +	      "           frame content is %dx%d with offset (%d,%d).\n" +	      "           pixel aspect is %d:%d.\n", +	      this->t_info.width,this->t_info.height, +	      (double)this->t_info.fps_numerator/this->t_info.fps_denominator, +	      this->t_info.frame_width, this->t_info.frame_height, +	      this->t_info.offset_x, this->t_info.offset_y, +	      this->t_info.aspect_numerator, this->t_info.aspect_denominator); + +      this->frame_duration=((int64_t)90000*this->t_info.fps_denominator)/this->t_info.fps_numerator; +      this->width=this->t_info.frame_width; +      this->height=this->t_info.frame_height; +      if (this->t_info.aspect_numerator==0 || this->t_info.aspect_denominator==0) +	/* 0-values are undefined, so don't do any scaling.  */ +	this->ratio=(double)this->width/(double)this->height; +      else +	/* Yes, this video needs to be scaled.  */ +	this->ratio=(double)(this->width*this->t_info.aspect_numerator) / +	  (double)(this->height*this->t_info.aspect_denominator); +      this->offset_x=this->t_info.offset_x; +      this->offset_y=this->t_info.offset_y; +      this->initialized=1; +      this->hp_read++; +    } + +  } else if (buf->decoder_flags & BUF_FLAG_HEADER) { +    /*ignore headerpackets*/ + +    return; + +  } else { +    /*decode videodata*/ + +    if (!this->initialized) { +      printf ("libtheora: cannot decode stream without header\n"); +      return; +    } + +    ret=theora_decode_packetin( &this->t_state, &this->op); + +    if ( ret!=0) { +      xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "libtheora:Received an bad packet\n"); +    } else if (!this->skipframes) { + +      theora_decode_YUVout(&this->t_state,&yuv); + +      /*fixme - aspectratio from theora is not considered*/ +      frame = this->stream->video_out->get_frame( this->stream->video_out, +						  this->width, this->height, +						  this->ratio, +						  XINE_IMGFMT_YV12, +						  VO_BOTH_FIELDS); +      yuv2frame(&yuv, frame, this->offset_x, this->offset_y); + +      frame->pts = buf->pts; +      frame->duration=this->frame_duration; +      this->skipframes=frame->draw(frame, this->stream); +      frame->free(frame); +    } else { +      this->skipframes=this->skipframes-1; +    } +  } +} + + +static void theora_flush (video_decoder_t *this_gen) { +  /* +   * flush out any frames that are still stored in the decoder +   */ +  theora_decoder_t *this = (theora_decoder_t *) this_gen; +  this->skipframes=0; +} + +static void theora_reset (video_decoder_t *this_gen) { +  /* +   * reset decoder after engine flush (prepare for new +   * video data not related to recently decoded data) +   */ +  theora_decoder_t *this = (theora_decoder_t *) this_gen; +  this->skipframes=0; +} + +static void theora_discontinuity (video_decoder_t *this_gen) { +  /* +   * inform decoder that a time reference discontinuity has happened. +   * that is, it must forget any currently held pts value +   */ +  theora_decoder_t *this = (theora_decoder_t *) this_gen; +  this->skipframes=0; +} + +static void theora_dispose (video_decoder_t *this_gen) { +  /* +   * close down, free all resources +   */ + +  theora_decoder_t *this = (theora_decoder_t *) this_gen; + +  lprintf ("dispose \n"); + +  theora_clear (&this->t_state); +  theora_comment_clear (&this->t_comment); +  theora_info_clear (&this->t_info); +  this->stream->video_out->close(this->stream->video_out, this->stream); +  free (this->packet); +  free (this); +} + +static video_decoder_t *theora_open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) { + +  /* +   * open a new instance of this plugin class +   */ + +  theora_decoder_t  *this ; + +  this = (theora_decoder_t *) xine_xmalloc (sizeof (theora_decoder_t)); + +  this->theora_decoder.decode_data   = theora_decode_data; +  this->theora_decoder.flush         = theora_flush; +  this->theora_decoder.reset         = theora_reset; +  this->theora_decoder.discontinuity = theora_discontinuity; +  this->theora_decoder.dispose       = theora_dispose; + +  this->stream                       = stream; +  this->class                        = (theora_class_t *) class_gen; + +  this->op_max_size                  = 4096; +  this->packet                       = malloc(this->op_max_size); + +  this->done                         = 0; + +  this->stream                       = stream; + +  this->initialized                  = 0; + +  theora_comment_init (&this->t_comment); +  theora_info_init (&this->t_info); +  (stream->video_out->open) (stream->video_out, stream); + +  return &this->theora_decoder; + +} + +/* + * theora plugin class + */ +void *theora_init_plugin (xine_t *xine, void *data) { +  /*initialize our plugin*/ +  theora_class_t *this; +   +  this = (theora_class_t *) xine_xmalloc (sizeof (theora_class_t)); + +  this->decoder_class.open_plugin     = theora_open_plugin; +  this->decoder_class.identifier      = "theora video"; +  this->decoder_class.description     = N_("theora video decoder plugin"); +  this->decoder_class.dispose         = default_video_decoder_class_dispose; + +  return this; +} + +/* + * exported plugin catalog entry + */ + +static const uint32_t supported_types[] = { BUF_VIDEO_THEORA, 0 }; + +const decoder_info_t dec_info_theora = { +  supported_types,   /* supported types */ +  5                        /* priority        */ +}; diff --git a/src/combined/xine_vorbis_decoder.c b/src/combined/xine_vorbis_decoder.c new file mode 100644 index 000000000..ad3a07188 --- /dev/null +++ b/src/combined/xine_vorbis_decoder.c @@ -0,0 +1,366 @@ +/*  + * Copyright (C) 2000-2003 the xine project + *  + * This file is part of xine, a free video player. + *  + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *  + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * (ogg/)vorbis audio decoder plugin (libvorbis wrapper) for xine + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#define LOG_MODULE "vorbis_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include <xine/xine_internal.h> +#include <xine/audio_out.h> +#include <xine/buffer.h> + +#include <ogg/ogg.h> +#include <vorbis/codec.h> + +#define MAX_NUM_SAMPLES 4096 +#define INIT_BUFSIZE    8192 + +typedef struct { +  audio_decoder_class_t   decoder_class; +} vorbis_class_t; + +typedef struct vorbis_decoder_s { +  audio_decoder_t   audio_decoder; + +  int64_t           pts; + +  int               output_sampling_rate; +  int               output_open; +  int               output_mode; + +  ogg_packet        op; /* we must use this struct to sent data to libvorbis */ + +  /* vorbis stuff */ +  vorbis_info       vi; /* stores static vorbis bitstream settings */ +  vorbis_comment    vc; +  vorbis_dsp_state  vd; /* central working state for packet->PCM decoder */ +  vorbis_block      vb; /* local working state for packet->PCM decoder */ + +  int16_t           convbuffer[MAX_NUM_SAMPLES]; +  int               convsize; + +  int               header_count; + +  xine_stream_t    *stream; + +  /* data accumulation stuff */ +  unsigned char    *buf; +  int               bufsize; +  int               size; + +} vorbis_decoder_t; + + +static void vorbis_reset (audio_decoder_t *this_gen) { + +  vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + +  if( this->header_count ) return; +  this->size = 0; + +  /* clear block first, as it might contain allocated data */ +  vorbis_block_clear(&this->vb); +  vorbis_block_init(&this->vd,&this->vb);      +} + +static void vorbis_discontinuity (audio_decoder_t *this_gen) { + +  vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + +  this->pts=0; +} + +/* Known vorbis comment keys from ogg123 sources*/ +static const struct { +  const char *key;         /* includes the '=' for programming convenience */ +  int   xine_metainfo_index; +} vorbis_comment_keys[] = { +  {"ARTIST=", XINE_META_INFO_ARTIST}, +  {"ALBUM=", XINE_META_INFO_ALBUM}, +  {"TITLE=", XINE_META_INFO_TITLE}, +  {"GENRE=", XINE_META_INFO_GENRE}, +  {"DESCRIPTION=", XINE_META_INFO_COMMENT}, +  {"COMMENT=", XINE_META_INFO_COMMENT}, +  {"DATE=", XINE_META_INFO_YEAR}, +  {"TRACKNUMBER=", XINE_META_INFO_TRACK_NUMBER}, +  {NULL, 0} +}; + +static void get_metadata (vorbis_decoder_t *this) { + +  char **ptr=this->vc.user_comments; +  while(*ptr){ + +    char *comment = *ptr; +    int i; + +    lprintf("%s\n", comment); + +    for (i = 0; vorbis_comment_keys[i].key != NULL; i++) { + +      if ( !strncasecmp (vorbis_comment_keys[i].key, comment, +			 strlen(vorbis_comment_keys[i].key)) ) { + +	lprintf ("known metadata %d %d\n", +		 i, vorbis_comment_keys[i].xine_metainfo_index); + +        _x_meta_info_set_utf8(this->stream, vorbis_comment_keys[i].xine_metainfo_index, +	  comment + strlen(vorbis_comment_keys[i].key)); + +      } +    } +    ++ptr; +  } + +  _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "vorbis"); +} + +static void vorbis_check_bufsize (vorbis_decoder_t *this, int size) { +  if (size > this->bufsize) { +    this->bufsize = size + size / 2; +    xprintf(this->stream->xine, XINE_VERBOSITY_LOG,  +	    _("vorbis: increasing buffer to %d to avoid overflow.\n"),  +	    this->bufsize); +    this->buf = realloc(this->buf, this->bufsize); +  } +} + +static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + +  vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + +  memset( &this->op, 0, sizeof(this->op) ); + +  /* data accumulation */ +  vorbis_check_bufsize(this, this->size + buf->size); +  xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); +  this->size += buf->size; + +  if (buf->decoder_flags & BUF_FLAG_FRAME_END) { +    this->op.packet = this->buf; +    this->op.bytes = this->size; + +    /* reset accumultaion buffer */ +    this->size = 0; +   +    if ( (buf->decoder_flags & BUF_FLAG_HEADER) && +        !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { +   +      lprintf ("%d headers to go\n", this->header_count); +   +      if (this->header_count) { +        int res = 0; +   +        if (this->header_count == 3) +          this->op.b_o_s = 1; +   +        if ( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ) { +          /* error case; not a vorbis header */ +          xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); +          xine_hexdump((char *)this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); +          return; +        } +   +        this->header_count--; +   +        if (!this->header_count) { +         +          int mode = AO_CAP_MODE_MONO; +           +          get_metadata (this); +   +          mode = _x_ao_channels2mode(this->vi.channels); +           +          this->convsize=MAX_NUM_SAMPLES/this->vi.channels; +           +          if (!this->output_open) { +            this->output_open = (this->stream->audio_out->open) (this->stream->audio_out,  +                                                      this->stream, +                                                      16, +                                                      this->vi.rate, +                                                      mode) ; +           +            _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE,  +              this->vi.bitrate_nominal); +           +          } +   +          /* OK, got and parsed all three headers. Initialize the Vorbis +                  * packet->PCM decoder. */ +          lprintf("all three headers parsed. initializing decoder.\n"); +          /* initialize central decode state */  +          vorbis_synthesis_init(&this->vd,&this->vi);  +          /* initialize local state for most of the decode so multiple +            * block decodes can proceed in parallel. We could init  +            * multiple vorbis_block structures for vd here */ +          vorbis_block_init(&this->vd,&this->vb);       +        } +      } +   +    } else if (this->output_open) { +   +      float **pcm; +      int samples; +   +      if(vorbis_synthesis(&this->vb,&this->op)==0)  +        vorbis_synthesis_blockin(&this->vd,&this->vb); +   +      if (buf->pts!=0) +        this->pts=buf->pts; +   +      while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ +   +        /* **pcm is a multichannel float vector. In stereo, for +        * example, pcm[0][...] is left, and pcm[1][...] is right. +        * samples is the size of each channel. Convert the float +        * values (-1.<=range<=1.) to whatever PCM format and write +        * it out +        */ +   +        int i,j; +        int bout=(samples<this->convsize?samples:this->convsize); +        audio_buffer_t *audio_buffer; +   +        audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); +         +        /* convert floats to 16 bit signed ints (host order) and +          interleave */ +        for(i=0;i<this->vi.channels;i++){ +          ogg_int16_t *ptr=audio_buffer->mem+i; +          float  *mono=pcm[i]; +          for(j=0;j<bout;j++){ +            int val=(mono[j] + 1.0f) * 32768.f; +            val -= 32768; +            /* might as well guard against clipping */ +            if(val>32767){ +              val=32767; +            } else if(val<-32768){ +              val=-32768; +            } +            *ptr=val; +            ptr+=this->vi.channels; +          } +        } +   +        audio_buffer->vpts       = this->pts; +        this->pts=0; +        audio_buffer->num_frames = bout; +   +        this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); +   +        buf->pts=0; +   +        /* tell libvorbis how many samples we actually consumed */ +        vorbis_synthesis_read(&this->vd,bout); +      } +    } else { +      lprintf("output not open\n"); +    } +  } +} + +static void vorbis_dispose (audio_decoder_t *this_gen) { + +  vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen;  + +  if( !this->header_count ) { +    lprintf("deinitializing decoder\n"); + +    vorbis_block_clear(&this->vb); +    vorbis_dsp_clear(&this->vd); +  } + +  vorbis_comment_clear(&this->vc); + +  vorbis_info_clear(&this->vi);  /* must be called last */ + +  if (this->output_open)  +    this->stream->audio_out->close (this->stream->audio_out, this->stream); + +  lprintf("libvorbis instance destroyed\n"); + +  free (this_gen); +} + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen,  +				     xine_stream_t *stream) { + +  vorbis_decoder_t *this ; + +  this = (vorbis_decoder_t *) xine_xmalloc (sizeof (vorbis_decoder_t)); + +  this->audio_decoder.decode_data         = vorbis_decode_data; +  this->audio_decoder.reset               = vorbis_reset; +  this->audio_decoder.discontinuity       = vorbis_discontinuity; +  this->audio_decoder.dispose             = vorbis_dispose; +  this->stream                            = stream; + +  this->output_open     = 0; +  this->header_count    = 3; +  this->convsize        = 0; + +  this->bufsize         = INIT_BUFSIZE; +  this->buf             = xine_xmalloc(INIT_BUFSIZE); +  this->size            = 0; + +  vorbis_info_init(&this->vi); +  vorbis_comment_init(&this->vc); + +  lprintf("libvorbis decoder instance created\n"); + +  return (audio_decoder_t *) this; +} + +/* + * vorbis plugin class + */ +void *vorbis_init_plugin (xine_t *xine, void *data) { + +  vorbis_class_t *this; +   +  this = (vorbis_class_t *) xine_xmalloc (sizeof (vorbis_class_t)); + +  this->decoder_class.open_plugin     = open_plugin; +  this->decoder_class.identifier      = "vorbis"; +  this->decoder_class.description     = N_("vorbis audio decoder plugin"); +  this->decoder_class.dispose         = default_audio_decoder_class_dispose; + +  return this; +} + +static const uint32_t audio_types[] = {  +  BUF_AUDIO_VORBIS, 0 + }; + +const decoder_info_t dec_info_vorbis = { +  audio_types,         /* supported types */ +  5                    /* priority        */ +}; | 
