summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_dec/Makefile.am9
-rw-r--r--src/video_dec/libvpx.c364
2 files changed, 373 insertions, 0 deletions
diff --git a/src/video_dec/Makefile.am b/src/video_dec/Makefile.am
index 10c6b18eb..c68c9192a 100644
--- a/src/video_dec/Makefile.am
+++ b/src/video_dec/Makefile.am
@@ -24,10 +24,15 @@ if ENABLE_LIBJPEG
libjpeg_module = xineplug_decode_libjpeg.la
endif
+if ENABLE_VPX
+libvpx_module = xineplug_decode_libvpx.la
+endif
+
xineplug_LTLIBRARIES = $(image_module) \
$(gdkpixbuf_module) \
$(libjpeg_module) \
$(theora_module) \
+ $(libvpx_module) \
xineplug_decode_bitplane.la \
xineplug_decode_rgb.la \
xineplug_decode_yuv.la
@@ -52,3 +57,7 @@ xineplug_decode_gdk_pixbuf_la_CFLAGS = $(AM_CFLAGS) $(GDK_PIXBUF_CFLAGS)
xineplug_decode_libjpeg_la_SOURCES = libjpeg.c
xineplug_decode_libjpeg_la_LIBADD = $(XINE_LIB) $(JPEG_LIBS)
xineplug_decode_libjpeg_la_CFLAGS = $(AM_CFLAGS) $(JPEG_CFLAGS)
+
+xineplug_decode_libvpx_la_SOURCES = libvpx.c
+xineplug_decode_libvpx_la_LIBADD = $(XINE_LIB) $(VPX_LIBS)
+xineplug_decode_libvpx_la_CFLAGS = $(AM_CFLAGS) $(VPX_CFLAGS)
diff --git a/src/video_dec/libvpx.c b/src/video_dec/libvpx.c
new file mode 100644
index 000000000..6b67675df
--- /dev/null
+++ b/src/video_dec/libvpx.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2013 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
+ *
+ * libvpx decoder wrapped by Petri Hintukainen <phintuka@users.sourceforge.net>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vpx/vpx_decoder.h>
+#include <vpx/vp8dx.h>
+
+#include <xine/xine_internal.h>
+#include <xine/video_out.h>
+#include <xine/buffer.h>
+#include <xine/xineutils.h>
+
+typedef struct {
+ video_decoder_class_t decoder_class;
+ uint32_t buffer_type;
+} vpx_class_t;
+
+typedef struct vpx_decoder_s {
+ video_decoder_t video_decoder; /* parent video decoder structure */
+
+ vpx_class_t *class;
+ xine_stream_t *stream;
+
+ int64_t pts;
+ struct vpx_codec_ctx ctx;
+ int decoder_ok; /* current decoder status */
+
+ unsigned char *buf; /* the accumulated buffer data */
+ int bufsize; /* the maximum size of buf */
+ int size; /* the current size of buf */
+
+ int width; /* the width of a video frame */
+ int height; /* the height of a video frame */
+ double ratio; /* the width to height ratio */
+
+} vpx_decoder_t;
+
+/**************************************************************************
+ * xine video plugin functions
+ *************************************************************************/
+
+static void vpx_handle_header(vpx_decoder_t *this, buf_element_t *buf)
+{
+ xine_bmiheader *bih;
+
+ (this->stream->video_out->open) (this->stream->video_out, this->stream);
+
+ bih = (xine_bmiheader *) buf->content;
+ this->width = (bih->biWidth + 1) & ~1;
+ this->height = (bih->biHeight + 1) & ~1;
+
+ if (buf->decoder_flags & BUF_FLAG_ASPECT)
+ this->ratio = (double)buf->decoder_info[1] / (double)buf->decoder_info[2];
+ else
+ this->ratio = (double)this->width / (double)this->height;
+
+ free (this->buf);
+ this->buf = NULL;
+ this->bufsize = 0;
+ this->size = 0;
+
+ this->decoder_ok = 1;
+
+ switch (buf->type) {
+ case BUF_VIDEO_VP8:
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "VP8");
+ break;
+ case BUF_VIDEO_VP9:
+ _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "VP9");
+ break;
+ }
+
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->width);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->height);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->ratio*10000);
+}
+
+static void vpx_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
+{
+ vpx_decoder_t *this = (vpx_decoder_t *) this_gen;
+
+ if (buf->decoder_flags & BUF_FLAG_PREVIEW) {
+ return;
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
+ vpx_handle_header(this, buf);
+ return;
+ }
+
+ if (!this->decoder_ok || buf->decoder_flags & BUF_FLAG_SPECIAL) {
+ return;
+ }
+
+ /* collect data */
+ if (this->size + buf->size > this->bufsize) {
+ this->bufsize = this->size + 2 * buf->size;
+ this->buf = realloc (this->buf, this->bufsize);
+ }
+ xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
+ this->size += buf->size;
+
+ /* save pts */
+ if (buf->pts > 0) {
+ this->pts = buf->pts;
+ }
+
+ if (!(buf->decoder_flags & BUF_FLAG_FRAME_END)) {
+ return;
+ }
+
+ /* decode */
+
+ struct vpx_codec_ctx *ctx = &this->ctx;
+ vpx_codec_err_t err;
+ vo_frame_t *img;
+ int64_t pts, *p_pts;
+
+ p_pts = malloc(sizeof(*p_pts));
+ *p_pts = this->pts;
+ err = vpx_codec_decode(ctx, this->buf, this->size, p_pts, 0);
+
+ this->size = 0;
+
+ if (err != VPX_CODEC_OK) {
+ const char *error = vpx_codec_error(ctx);
+ const char *detail = vpx_codec_error_detail(ctx);
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ LOG_MODULE": Failed to decode frame: %s (%s)\n",
+ error, detail ? detail : "");
+ free(p_pts);
+ return;
+ }
+
+ const void *iter = NULL;
+ struct vpx_image *vpx_img = vpx_codec_get_frame(ctx, &iter);
+ if (!vpx_img)
+ return;
+
+ p_pts = vpx_img->user_priv;
+ vpx_img->user_priv = NULL;
+ pts = *p_pts;
+ free(p_pts);
+
+ if (vpx_img->fmt != VPX_IMG_FMT_I420) {
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ LOG_MODULE": Unsupported color space %d\n", vpx_img->fmt);
+ return;
+ }
+
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ this->width, this->height,
+ this->ratio, XINE_IMGFMT_YV12, VO_BOTH_FIELDS);
+
+ yv12_to_yv12(
+ /* Y */
+ vpx_img->planes[0], vpx_img->stride[0],
+ img->base[0], img->pitches[0],
+ /* U */
+ vpx_img->planes[1], vpx_img->stride[1],
+ img->base[1], img->pitches[1],
+ /* V */
+ vpx_img->planes[2], vpx_img->stride[2],
+ img->base[2], img->pitches[2],
+ /* width x height */
+ this->width, this->height);
+
+ img->pts = pts;
+ img->bad_frame = 0;
+ img->progressive_frame = 1;
+
+ img->draw(img, this->stream);
+ img->free(img);
+}
+
+static void vpx_flush (video_decoder_t *this_gen)
+{
+}
+
+static void vpx_reset (video_decoder_t *this_gen)
+{
+ vpx_decoder_t *this = (vpx_decoder_t *) this_gen;
+
+ this->size = 0;
+}
+
+static void vpx_discontinuity (video_decoder_t *this_gen)
+{
+}
+
+/*
+ * This function frees the video decoder instance allocated to the decoder.
+ */
+static void vpx_dispose (video_decoder_t *this_gen)
+{
+ vpx_decoder_t *this = (vpx_decoder_t *) this_gen;
+
+ const void *iter = NULL;
+ while (1) {
+ struct vpx_image *img = vpx_codec_get_frame(&this->ctx, &iter);
+ if (!img)
+ break;
+ free(img->user_priv);
+ img->user_priv = NULL;
+ }
+
+ vpx_codec_destroy(&this->ctx);
+
+ free (this->buf);
+
+ if (this->decoder_ok) {
+ this->decoder_ok = 0;
+ this->stream->video_out->close(this->stream->video_out, this->stream);
+ }
+
+ free (this_gen);
+}
+
+static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream)
+{
+ vpx_class_t *cls = (vpx_class_t *)class_gen;
+ vpx_decoder_t *this;
+
+ const struct vpx_codec_iface *iface;
+ struct vpx_codec_dec_cfg deccfg = { 0 };
+ int vp_version;
+
+ switch (cls->buffer_type) {
+ case BUF_VIDEO_VP8:
+ iface = &vpx_codec_vp8_dx_algo;
+ vp_version = 8;
+ break;
+#ifdef HAVE_VPX_VP9_DECODER
+ case BUF_VIDEO_VP9:
+ iface = &vpx_codec_vp9_dx_algo;
+ vp_version = 9;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+
+ this = (vpx_decoder_t *) calloc(1, sizeof(vpx_decoder_t));
+
+ this->video_decoder.decode_data = vpx_decode_data;
+ this->video_decoder.flush = vpx_flush;
+ this->video_decoder.reset = vpx_reset;
+ this->video_decoder.discontinuity = vpx_discontinuity;
+ this->video_decoder.dispose = vpx_dispose;
+
+ this->size = 0;
+
+ this->stream = stream;
+ this->class = (vpx_class_t *) class_gen;
+
+ this->decoder_ok = 0;
+ this->buf = NULL;
+
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ LOG_MODULE "VP%d: using libvpx version %s\n",
+ vp_version, vpx_codec_version_str());
+
+ if (vpx_codec_dec_init(&this->ctx, iface, &deccfg, 0) != VPX_CODEC_OK) {
+ const char *err = vpx_codec_error(&this->ctx);
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ LOG_MODULE": Failed to initialize VP%d decoder: %s\n",
+ vp_version, err);
+ free(this);
+ return NULL;
+ }
+
+ return &this->video_decoder;
+}
+
+static void *init_plugin (xine_t *xine, uint32_t buffer_type, const char *identifier)
+{
+ vpx_class_t *this;
+
+ this = (vpx_class_t *) calloc(1, sizeof(vpx_class_t));
+
+ this->decoder_class.open_plugin = open_plugin;
+ this->decoder_class.identifier = identifier;
+ this->decoder_class.description = N_("WebM (VP8/VP9) video decoder plugin");
+ this->decoder_class.dispose = default_video_decoder_class_dispose;
+
+ this->buffer_type = buffer_type;
+
+ return this;
+}
+
+static void *init_plugin_vp8 (xine_t *xine, void *data)
+{
+ return init_plugin(xine, BUF_VIDEO_VP8, "libvpx-vp8");
+}
+
+#ifdef HAVE_VPX_VP9_DECODER
+static void *init_plugin_vp9 (xine_t *xine, void *data)
+{
+ return init_plugin(xine, BUF_VIDEO_VP9, "libvpx-vp9");
+}
+#endif
+
+/*
+ * exported plugin catalog entry
+ */
+
+static const uint32_t video_types_vp8[] = {
+ BUF_VIDEO_VP8,
+ 0
+};
+
+#ifdef HAVE_VPX_VP9_DECODER
+static const uint32_t video_types_vp9[] = {
+ BUF_VIDEO_VP9,
+ 0
+};
+#endif
+
+static const decoder_info_t dec_info_video_vp8 = {
+ video_types_vp8, /* supported types */
+ 1 /* priority */
+};
+
+#ifdef HAVE_VPX_VP9_DECODER
+static const decoder_info_t dec_info_video_vp9 = {
+ video_types_vp9, /* supported types */
+ 1 /* priority */
+};
+#endif
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_DECODER, 19, "libvpx-vp8", XINE_VERSION_CODE, &dec_info_video_vp8, init_plugin_vp8 },
+#ifdef HAVE_VPX_VP9_DECODER
+ { PLUGIN_VIDEO_DECODER, 19, "libvpx-vp9", XINE_VERSION_CODE, &dec_info_video_vp9, init_plugin_vp9 },
+#endif
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};