diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/combined/ffmpeg/Makefile.am | 6 | ||||
| -rw-r--r-- | src/combined/ffmpeg/ffmpeg_decoder.c | 12 | ||||
| -rw-r--r-- | src/combined/ffmpeg/ffmpeg_decoder.h | 8 | ||||
| -rw-r--r-- | src/combined/ffmpeg/input_avio.c | 356 | 
4 files changed, 382 insertions, 0 deletions
| diff --git a/src/combined/ffmpeg/Makefile.am b/src/combined/ffmpeg/Makefile.am index 61ac6d294..5d7abed08 100644 --- a/src/combined/ffmpeg/Makefile.am +++ b/src/combined/ffmpeg/Makefile.am @@ -29,6 +29,12 @@ xineplug_decode_ff_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) -lm $(ZLIB_LIBS) \  	$(FFMPEG_LIBS) $(AVUTIL_LIBS) $(FFMPEG_POSTPROC_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL)  xineplug_decode_ff_la_LDFLAGS = $(AM_LDFLAGS) $(IMPURE_TEXT_LDFLAGS) +if ENABLE_AVFORMAT +xineplug_decode_ff_la_SOURCES += input_avio.c +xineplug_decode_ff_la_CFLAGS += $(AVFORMAT_CFLAGS) +xineplug_decode_ff_la_LIBADD += $(AVFORMAT_LIBS) +endif +  # Generation of ffmpeg->xine codec mapping lists (see xine_*.list).  AV_CPP = $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AVUTIL_CFLAGS) diff --git a/src/combined/ffmpeg/ffmpeg_decoder.c b/src/combined/ffmpeg/ffmpeg_decoder.c index e5480cc39..4915b538e 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.c +++ b/src/combined/ffmpeg/ffmpeg_decoder.c @@ -29,6 +29,10 @@  #include "ffmpeg_decoder.h"  #include "ffmpeg_compat.h" +#ifdef HAVE_AVFORMAT +#include <libavformat/avformat.h> // av_register_all() +#endif +  /*   * common initialisation   */ @@ -40,6 +44,11 @@ void init_once_routine(void) {    pthread_mutex_init(&ffmpeg_lock, NULL);    avcodec_init();    avcodec_register_all(); + +#ifdef HAVE_AVFORMAT +  av_register_all(); +  avformat_network_init(); +#endif  }  /* @@ -52,5 +61,8 @@ const plugin_info_t xine_plugin_info[] EXPORTED = {    { 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 }, +#ifdef HAVE_AVFORMAT +  { PLUGIN_INPUT,         18, INPUT_AVIO_ID,     XINE_VERSION_CODE, &input_info_avio,     init_avio_input_plugin }, +#endif    { PLUGIN_NONE, 0, "", 0, NULL, NULL }  }; diff --git a/src/combined/ffmpeg/ffmpeg_decoder.h b/src/combined/ffmpeg/ffmpeg_decoder.h index d3db20934..9e9ed1290 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.h +++ b/src/combined/ffmpeg/ffmpeg_decoder.h @@ -46,11 +46,19 @@ typedef struct ff_codec_s {  void *init_audio_plugin (xine_t *xine, void *data);  void *init_video_plugin (xine_t *xine, void *data); +void *init_avio_input_plugin (xine_t *xine, void *data);  extern decoder_info_t dec_info_ffmpeg_video;  extern decoder_info_t dec_info_ffmpeg_wmv8;  extern decoder_info_t dec_info_ffmpeg_wmv9;  extern decoder_info_t dec_info_ffmpeg_audio; +extern input_info_t   input_info_avio; + +/* communication between avio/avformat input and avformat demux plugins */ +#define INPUT_OPTIONAL_DATA_pb         0x1000 + +/* plugin ids */ +#define INPUT_AVIO_ID     "avio"  extern pthread_once_t once_control;  void init_once_routine(void); diff --git a/src/combined/ffmpeg/input_avio.c b/src/combined/ffmpeg/input_avio.c new file mode 100644 index 000000000..035b7a395 --- /dev/null +++ b/src/combined/ffmpeg/input_avio.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2013 the xine project + * Copyright (C) 2013 Petri Hintukainen <phintuka@users.sourceforge.net> + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include <libavformat/avio.h> + +#define LOG_MODULE "libavio" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/input_plugin.h> + +#include "ffmpeg_decoder.h" + +/* + * avio input plugin + */ + +typedef struct { +  input_plugin_t   input_plugin; + +  xine_stream_t   *stream; + +  char            *mrl; +  AVIOContext     *pb; + +  /* preview support */ +  char             preview[MAX_PREVIEW_SIZE]; +  off_t            preview_size; +  off_t            curpos; + +} avio_input_plugin_t; + +static off_t input_avio_read (input_plugin_t *this_gen, void *buf_gen, off_t len) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; +  char *buf = (char *)buf_gen; +  off_t total = 0; + +  if (len < 0) +    return -1; + +  if (this->curpos < this->preview_size) { +    off_t n = this->preview_size - this->curpos; +    if (n > (len - total)) +      n = len - total; + +    memcpy (&buf[total], &this->preview[this->curpos], n); +    this->curpos += n; +    total += n; +    len -= n; +  } + +  if (len > 0 && this->pb) { +    off_t n = avio_read(this->pb, buf + total, len); +    if (n < 0) { +      return n; +    } +    this->curpos += n; +    total += n; +  } + +  return total; +} + +static buf_element_t *input_avio_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) { +  return NULL; +} + +static off_t input_avio_get_length (input_plugin_t *this_gen) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  if (this->pb) { +    return avio_size(this->pb); +  } + +  return -1; +} + +static uint32_t input_avio_get_capabilities (input_plugin_t *this_gen) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  if (this->pb && this->pb->seekable) { +    return INPUT_CAP_SEEKABLE | INPUT_CAP_PREVIEW; +  } + +  return INPUT_CAP_PREVIEW; +} + +static off_t input_avio_seek_time (input_plugin_t *this_gen, int time_offset, int origin) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  if (origin == SEEK_SET && this->pb && this->pb->seekable) { +    int64_t ts     = (int64_t)time_offset * AV_TIME_BASE / 1000; +    off_t   result = avio_seek_time(this->pb, -1, ts, 0); +    if (result >= 0) { +      this->preview_size = 0; +      this->curpos = result; +      return this->curpos; +    } +  } + +  return -1; +} + +static uint32_t input_avio_get_blocksize (input_plugin_t *this_gen) { +  return 0; +} + +static off_t input_avio_get_current_pos (input_plugin_t *this_gen) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  if (this->pb && this->curpos >= this->preview_size) { +    this->curpos = avio_tell(this->pb); +  } + +  return this->curpos; +} + +static off_t input_avio_seek (input_plugin_t *this_gen, off_t offset, int origin) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; +  off_t size; +  off_t newpos; + +  if (!this->pb || !this->pb->seekable) { +    return -1; +  } + +  /* convert relative seeks to absolute */ +  switch (origin) { +    case SEEK_SET: +      break; +    case SEEK_CUR: +      offset += this->curpos; +      break; +    case SEEK_END: +      size = avio_size(this->pb); +      if (size < 1) { +        return -1; +      } +      offset = size + offset; +      if (offset < 0) +        offset = 0; +      if (offset > size) +        offset = size; +      break; +  } + +  /* seek, take care of preview buffer */ + +  newpos = offset; +  if (offset < this->preview_size) { +    offset = this->preview_size; +  } + +  if (offset != avio_seek(this->pb, offset, SEEK_SET)) { +    return -1; +  } + +  this->curpos = newpos; +  return this->curpos; +} + + +static const char* input_avio_get_mrl (input_plugin_t *this_gen) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  return this->mrl; +} + +static int input_avio_get_optional_data (input_plugin_t *this_gen, +                                          void *data, int data_type) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  switch (data_type) { +    case INPUT_OPTIONAL_DATA_PREVIEW: +      memcpy (data, this->preview, this->preview_size); +      return this->preview_size; + +    case INPUT_OPTIONAL_DATA_pb: +      *((AVIOContext **)data) = this->pb; +      this->pb = NULL; +      return INPUT_OPTIONAL_SUCCESS; +  } + +  return INPUT_OPTIONAL_UNSUPPORTED; +} + +static int input_avio_open (input_plugin_t *this_gen) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; +  int toread = MAX_PREVIEW_SIZE; +  int trycount = 0; + +  if (!this->pb) { + +    /* try to open libavio protocol */ +    if (avio_open2(&this->pb, this->mrl, AVIO_FLAG_READ, NULL, NULL) < 0) { +      xprintf (this->stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE": failed to open avio protocol for '%s'\n", this->mrl); +      return 0; +    } + +    xprintf (this->stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE": opened avio protocol for '%s'\n", this->mrl); +  } + + +  while ((toread > 0) && (trycount < 10)) { +    off_t n = avio_read (this->pb, this->preview + this->preview_size, toread); +    if (n > 0) { +      this->preview_size += n; +    } +    trycount++; +    toread = MAX_PREVIEW_SIZE - this->preview_size; +  } + +  return 1; +} + +static void input_avio_dispose (input_plugin_t *this_gen ) { +  avio_input_plugin_t *this = (avio_input_plugin_t *) this_gen; + +  avio_close(this->pb); +  free (this->mrl); +  free (this_gen); +} + +/* + * avio input class + */ + +static int is_avio_supported_protocol(xine_t *xine, const char *mrl) +{ +  char *mrl_protocol = strdup(mrl); +  char *pt = strchr(mrl_protocol, ':'); +  int   result = 0; + +  if (pt) { +    const char *protocol; +    void       *iter; + +    *pt = 0; + +    for (iter = NULL; NULL != (protocol = avio_enum_protocols(&iter, 0)); ) { +      if (!strcmp(mrl_protocol, protocol)) { +        xprintf (xine, XINE_VERBOSITY_LOG, LOG_MODULE": using avio protocol '%s' for '%s'\n", protocol, mrl); +        result = 1; +      } +    } +  } + +  if (!result) { +    xprintf (xine, XINE_VERBOSITY_LOG, LOG_MODULE": no avio protocol for '%s'\n", mrl); +  } + +  free(mrl_protocol); +  return result; +} + +static input_plugin_t *input_avio_get_instance (input_class_t *cls_gen, xine_stream_t *stream, const char *mrl) { +  avio_input_plugin_t *this; +  const int            proto_len = strlen(INPUT_AVIO_ID":"); + +  if (!mrl || !*mrl) { +    return NULL; +  } + +  /* accept only mrls with protocol part */ +  if (!strchr(mrl, ':') || (strchr(mrl, '/') < strchr(mrl, ':'))) { +    return NULL; +  } + +  /* always accept own protocol */ +  /* avio:http:// ... --> use avio instead of xine native http plugin */ +  if (!strncasecmp (mrl, INPUT_AVIO_ID":", proto_len)) { +    mrl += proto_len; +  } + +  if (!is_avio_supported_protocol(stream->xine, mrl)) { +    return NULL; +  } + +  this = calloc(1, sizeof(avio_input_plugin_t)); +  this->stream = stream; +  this->mrl    = strdup(mrl); + +  this->input_plugin.open              = input_avio_open; +  this->input_plugin.get_capabilities  = input_avio_get_capabilities; +  this->input_plugin.read              = input_avio_read; +  this->input_plugin.read_block        = input_avio_read_block; +  this->input_plugin.seek              = input_avio_seek; +  this->input_plugin.seek_time         = input_avio_seek_time; +  this->input_plugin.get_current_pos   = input_avio_get_current_pos; +  this->input_plugin.get_length        = input_avio_get_length; +  this->input_plugin.get_blocksize     = input_avio_get_blocksize; +  this->input_plugin.get_mrl           = input_avio_get_mrl; +  this->input_plugin.get_optional_data = input_avio_get_optional_data; +  this->input_plugin.dispose           = input_avio_dispose; +  this->input_plugin.input_class       = cls_gen; + +  return &this->input_plugin; +} + +void *init_avio_input_plugin (xine_t *xine, void *data) { +  input_class_t  *this; +  const char     *protocol; +  void           *iter; + +  for (iter = NULL; NULL != (protocol = avio_enum_protocols(&iter, 0)); ) { +    xprintf (xine, XINE_VERBOSITY_DEBUG, LOG_MODULE": found avio protocol '%s'\n", protocol); +  } + +  this = calloc(1, sizeof(input_class_t)); + +  pthread_once( &once_control, init_once_routine ); + +  this->get_instance      = input_avio_get_instance; +  this->description       = N_("libavio input plugin"); +  this->identifier        = INPUT_AVIO_ID; +  this->get_dir           = NULL; +  this->get_autoplay_list = NULL; +  this->dispose           = default_input_class_dispose; +  this->eject_media       = NULL; + +  return this; +} + +input_info_t input_info_avio = { +  -1   /* priority */ +}; | 
