summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/combined/ffmpeg/Makefile.am6
-rw-r--r--src/combined/ffmpeg/ffmpeg_decoder.c12
-rw-r--r--src/combined/ffmpeg/ffmpeg_decoder.h8
-rw-r--r--src/combined/ffmpeg/input_avio.c356
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 */
+};