diff options
| author | Thibaut Mattern <tmattern@users.sourceforge.net> | 2004-02-11 20:40:00 +0000 | 
|---|---|---|
| committer | Thibaut Mattern <tmattern@users.sourceforge.net> | 2004-02-11 20:40:00 +0000 | 
| commit | 34560d0ad0726e354eb5679541d9dc7453555114 (patch) | |
| tree | 6d679388d2fa293ba1796f606281948d12a400dd /src | |
| parent | 07193b78bd361cbdc9cca0936aeec7509b3c36c7 (diff) | |
| download | xine-lib-34560d0ad0726e354eb5679541d9dc7453555114.tar.gz xine-lib-34560d0ad0726e354eb5679541d9dc7453555114.tar.bz2 | |
Amiga MOD music file demuxer from Paul Eggleton (uses the ModPlug engine).
configure.ac and Makefile.am from Daniel
I've ported the demuxer to current cvs (BUF_FLAG_FRAME_END issue), i've fixed the seeking problem and the pts computing.
Tested with some .mod files, it rocks ;)
Back to the amiga era ;)
(you have to install the ModPlug engine first)
CVS patchset: 6130
CVS date: 2004/02/11 20:40:00
Diffstat (limited to 'src')
| -rw-r--r-- | src/demuxers/Makefile.am | 6 | ||||
| -rw-r--r-- | src/demuxers/demux_mod.c | 364 | ||||
| -rw-r--r-- | src/demuxers/group_audio.c | 5 | ||||
| -rw-r--r-- | src/demuxers/group_audio.h | 6 | 
4 files changed, 376 insertions, 5 deletions
| diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index d11a9f75f..f577aab72 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -1,6 +1,6 @@  include $(top_srcdir)/misc/Makefile.common -AM_CFLAGS = $(THEORA_CFLAGS) $(OGG_CFLAGS) $(SPEEX_CFLAGS) +AM_CFLAGS = $(THEORA_CFLAGS) $(OGG_CFLAGS) $(SPEEX_CFLAGS) $(LIBMODPLUG_CFLAGS)  libdir = $(XINE_PLUGINDIR) @@ -120,8 +120,8 @@ xineplug_dmx_audio_la_SOURCES = group_audio.c demux_aud.c demux_aiff.c \  				demux_cdda.c demux_mpgaudio.c demux_nsf.c \  				demux_realaudio.c demux_snd.c demux_voc.c \  				demux_vox.c demux_wav.c demux_ac3.c id3.c \ -				demux_aac.c -xineplug_dmx_audio_la_LIBADD = $(XINE_LIB) +				demux_aac.c demux_mod.c +xineplug_dmx_audio_la_LIBADD = $(XINE_LIB) $(LIBMODPLUG_LIBS)  xineplug_dmx_audio_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@  xineplug_dmx_yuv_frames_la_SOURCES = demux_yuv_frames.c diff --git a/src/demuxers/demux_mod.c b/src/demuxers/demux_mod.c new file mode 100644 index 000000000..1554e960a --- /dev/null +++ b/src/demuxers/demux_mod.c @@ -0,0 +1,364 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA + */ + +/* + * MOD File "demuxer" by Paul Eggleton (bluelightning@bluelightning.org) + * This is really just a loader for Amiga MOD (and similar) music files + * which reads an entire MOD file and passes it over to the ModPlug library + * for playback. + * + * This file was based on demux_nsf.c by Mike Melanson. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MODPLUG + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +/********** logging **********/ +#define LOG_MODULE "demux_mod" +/* #define LOG_VERBOSE */ +/* #define LOG */ + +#include "xine_internal.h" +#include "xineutils.h" +#include "compat.h" +#include "demux.h" +#include "group_audio.h" +#include "modplug.h" + +#define MOD_SAMPLERATE 44100 +#define MOD_BITS 16 +#define MOD_CHANNELS 2 + +//#define MOD_REFRESH_RATE 60 +#define OUT_BYTES_PER_SECOND (MOD_SAMPLERATE * MOD_CHANNELS * (MOD_BITS >> 3)) + +#define BLOCK_SIZE 4096 + + +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; + +  char                *title; +  char                *artist; +  char                *copyright; +  off_t                filesize; +   +  char                *buffer; + +  int64_t              current_pts; +   +  ModPlug_Settings     settings; +  ModPlugFile         *mpfile; +  int                  mod_length; +  int                  seek_flag;  /* this is set when a seek just occurred */ +   +} demux_mod_t; + +typedef struct { +  demux_class_t     demux_class; +} demux_mod_class_t; + +/* returns 1 if the MOD file was opened successfully, 0 otherwise */ +static int open_mod_file(demux_mod_t *this) { +  int total_read; +   +  /* Get size and create buffer */ +  this->filesize = this->input->get_length(this->input); +  this->buffer = (char *)malloc(this->filesize); +   +  /* Seek to beginning */ +  this->input->seek(this->input, 0, SEEK_SET); +   +  /* Read data */ +  total_read = this->input->read(this->input, this->buffer, this->filesize); +   +  if(total_read != this->filesize) { +    xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - filesize error\n"); +    free(this->buffer); +    return 0; +  } +       +  this->mpfile = ModPlug_Load(this->buffer, this->filesize); +  if (this->mpfile==NULL) { +    xine_log(this->stream->xine, XINE_LOG_PLUGIN, "modplug - load error\n"); +    free(this->buffer); +    return 0; +  } +   +  /* Set up modplug engine */ +  ModPlug_GetSettings(&this->settings); +  this->settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */ +  this->settings.mChannels = MOD_CHANNELS; +  this->settings.mBits = MOD_BITS; +  this->settings.mFrequency = MOD_SAMPLERATE; +  ModPlug_SetSettings(&this->settings); +   +  this->title = strdup(ModPlug_GetName(this->mpfile)); +  this->artist = strdup(""); +  this->copyright = strdup(""); +   +  this->mod_length = ModPlug_GetLength(this->mpfile); +     +  return 1; +} + +static int demux_mod_send_chunk(demux_plugin_t *this_gen) { +  demux_mod_t *this = (demux_mod_t *) this_gen; +  buf_element_t *buf; +  int mlen; + +  buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); +  buf->type = BUF_AUDIO_LPCM_LE; + +  mlen = ModPlug_Read(this->mpfile, buf->content, buf->max_size); +  if (mlen == 0) { +    this->status = DEMUX_FINISHED; +    buf->free_buffer(buf); +  } +  else { +    int64_t input_pos; +   +    buf->size = mlen; +    buf->pts = this->current_pts; +    buf->extra_info->input_time = buf->pts / 90; +    buf->extra_info->input_length = this->input->get_length(this->input); +     +    input_pos = buf->extra_info->input_length; +    input_pos *= buf->extra_info->input_time; +    input_pos /= this->mod_length; +    buf->extra_info->input_pos = input_pos; +    buf->decoder_flags = BUF_FLAG_FRAME_END; +     +    if (this->seek_flag) { +      _x_demux_control_newpts(this->stream, buf->pts, BUF_FLAG_SEEK); +      this->seek_flag = 0; +    } + +    this->audio_fifo->put (this->audio_fifo, buf); +     +    this->current_pts += 90000 * mlen / OUT_BYTES_PER_SECOND; +  } +   +  return this->status; +} + +static void demux_mod_send_headers(demux_plugin_t *this_gen) { +  demux_mod_t *this = (demux_mod_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, MOD_CHANNELS); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, MOD_SAMPLERATE); +  _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, MOD_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 */ +  buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); +  buf->type = BUF_AUDIO_LPCM_LE; +  buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; +  buf->decoder_info[0] = 0; +  buf->decoder_info[1] = MOD_SAMPLERATE; +  buf->decoder_info[2] = MOD_BITS; +  buf->decoder_info[3] = MOD_CHANNELS; +  buf->size = 0; +  this->audio_fifo->put (this->audio_fifo, buf); +} + +static int demux_mod_seek (demux_plugin_t *this_gen, +                           off_t start_pos, int start_time, int playing) { + +  demux_mod_t *this = (demux_mod_t *) this_gen; +  int64_t seek_millis; +   +   +  if (start_pos) { +    seek_millis = this->mod_length;  +    seek_millis *= start_pos; +    seek_millis /= this->input->get_length(this->input); +  } else { +    seek_millis = start_time; +  } + +  _x_demux_flush_engine(this->stream); +  ModPlug_Seek(this->mpfile, seek_millis); +  this->current_pts = seek_millis * 90; +   +  this->seek_flag = 1; +  return this->status; +} + +static void demux_mod_dispose (demux_plugin_t *this_gen) { +  demux_mod_t *this = (demux_mod_t *) this_gen; + +  free(this->title); +  free(this->artist); +  free(this->copyright); +  free(this); +} + +static int demux_mod_get_status (demux_plugin_t *this_gen) { +  demux_mod_t *this = (demux_mod_t *) this_gen; +  return this->status; +} + +/* return the approximate length in miliseconds */ +static int demux_mod_get_stream_length (demux_plugin_t *this_gen) { +  demux_mod_t *this = (demux_mod_t *) this_gen; +  return ModPlug_GetLength(this->mpfile); +} + +static uint32_t demux_mod_get_capabilities(demux_plugin_t *this_gen) { +  return DEMUX_CAP_NOCAP; +} + +static int demux_mod_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_mod_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_mod_t)); +  this->stream = stream; +  this->input  = input; + +  this->demux_plugin.send_headers      = demux_mod_send_headers; +  this->demux_plugin.send_chunk        = demux_mod_send_chunk; +  this->demux_plugin.seek              = demux_mod_seek; +  this->demux_plugin.dispose           = demux_mod_dispose; +  this->demux_plugin.get_status        = demux_mod_get_status; +  this->demux_plugin.get_stream_length = demux_mod_get_stream_length; +  this->demux_plugin.get_capabilities  = demux_mod_get_capabilities; +  this->demux_plugin.get_optional_data = demux_mod_get_optional_data; +  this->demux_plugin.demux_class       = class_gen; + +  this->status = DEMUX_FINISHED; + +  xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "TEST mod decode\n"); +   +  switch (stream->content_detection_method) { + +  case METHOD_BY_EXTENSION: { +    char *extensions, *mrl; + +    mrl = input->get_mrl (input); +    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_CONTENT: +  case METHOD_EXPLICIT: + +    if (!open_mod_file(this)) { +      free (this); +      return NULL; +    } + +  break; + +  default: +    free (this); +    return NULL; +  } + +  return &this->demux_plugin; +} + +static char *get_description (demux_class_t *this_gen) { +  return "ModPlug Amiga MOD Music file demux plugin"; +} + +static char *get_identifier (demux_class_t *this_gen) { +  return "mod"; +} + +static char *get_extensions (demux_class_t *this_gen) { +  return "mod it stm s3m 669 amf med mdl"; +} + +static char *get_mimetypes (demux_class_t *this_gen) { +  return NULL; +} + +static void class_dispose (demux_class_t *this_gen) { +  demux_mod_class_t *this = (demux_mod_class_t *) this_gen; + +  free (this); +} + +void *demux_mod_init_plugin (xine_t *xine, void *data) { +  demux_mod_class_t     *this; + +  this = xine_xmalloc (sizeof (demux_mod_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; + +  return this; +} + +#endif  /* HAVE_MODPLUG */ diff --git a/src/demuxers/group_audio.c b/src/demuxers/group_audio.c index 94ffee634..bcf0ddb63 100644 --- a/src/demuxers/group_audio.c +++ b/src/demuxers/group_audio.c @@ -19,7 +19,7 @@   *   * This file contains plugin entries for several demuxers used in games   * - * $Id: group_audio.c,v 1.11 2004/01/12 17:35:15 miguelfreitas Exp $ + * $Id: group_audio.c,v 1.12 2004/02/11 20:40:00 tmattern Exp $   */  #ifdef HAVE_CONFIG_H @@ -49,5 +49,8 @@ plugin_info_t xine_plugin_info[] = {    { PLUGIN_DEMUX, 24, "voc", XINE_VERSION_CODE, NULL, demux_voc_init_plugin },    { PLUGIN_DEMUX, 24, "vox", XINE_VERSION_CODE, NULL, demux_vox_init_plugin },    { PLUGIN_DEMUX, 24, "wav", XINE_VERSION_CODE, NULL, demux_wav_init_plugin }, +#ifdef HAVE_MODPLUG +  { PLUGIN_DEMUX, 24, "mod", XINE_VERSION_CODE, NULL, demux_mod_init_plugin }, +#endif    { PLUGIN_NONE, 0, "", 0, NULL, NULL }  }; diff --git a/src/demuxers/group_audio.h b/src/demuxers/group_audio.h index 8c4dd01e9..847f4857f 100644 --- a/src/demuxers/group_audio.h +++ b/src/demuxers/group_audio.h @@ -17,7 +17,7 @@   * along with this program; if not, write to the Free Software   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA   * - * $Id: group_audio.h,v 1.3 2003/12/19 05:09:16 tmmm Exp $ + * $Id: group_audio.h,v 1.4 2004/02/11 20:40:00 tmattern Exp $   */  #ifndef HAVE_GROUP_AUDIO_H @@ -38,4 +38,8 @@ void *demux_voc_init_plugin (xine_t *xine, void *data);  void *demux_vox_init_plugin (xine_t *xine, void *data);  void *demux_wav_init_plugin (xine_t *xine, void *data); +#ifdef HAVE_MODPLUG +void *demux_mod_init_plugin (xine_t *xine, void *data); +#endif +  #endif | 
