summaryrefslogtreecommitdiff
path: root/ext/daala
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2013-06-23 11:29:23 +0200
committerSebastian Dröge <slomo@circular-chaos.org>2013-06-23 11:32:42 +0200
commit21ccbbffe562d1488e6117a4d8257ddfd77a4f7c (patch)
tree5450a6a143bbe6150bfdd5959387f3f4d8b34c79 /ext/daala
parentda47131cd629b899d617243f01cb23fa815597f1 (diff)
downloadgstreamer-plugins-bad-21ccbbffe562d1488e6117a4d8257ddfd77a4f7c.tar.gz
daaladec: Add decoder element
Diffstat (limited to 'ext/daala')
-rw-r--r--ext/daala/gstdaala.c1
-rw-r--r--ext/daala/gstdaaladec.c669
-rw-r--r--ext/daala/gstdaaladec.h84
3 files changed, 754 insertions, 0 deletions
diff --git a/ext/daala/gstdaala.c b/ext/daala/gstdaala.c
index eb8fd850c..f3f26d815 100644
--- a/ext/daala/gstdaala.c
+++ b/ext/daala/gstdaala.c
@@ -30,6 +30,7 @@ static gboolean
plugin_init (GstPlugin * plugin)
{
gst_daala_enc_register (plugin);
+ gst_daala_dec_register (plugin);
return TRUE;
}
diff --git a/ext/daala/gstdaaladec.c b/ext/daala/gstdaaladec.c
index e69de29bb..a08e8a833 100644
--- a/ext/daala/gstdaaladec.c
+++ b/ext/daala/gstdaaladec.c
@@ -0,0 +1,669 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ * Copyright (c) 2012 Collabora Ltd.
+ * Author : Edward Hervey <edward@collabora.com>
+ * Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (c) 2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-daaladec
+ * @see_also: daalaenc, oggdemux
+ *
+ * This element decodes daala streams into raw video
+ * <ulink url="http://www.xiph.org/daala/">Daala</ulink> is a royalty-free
+ * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
+ * Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! daaladec ! xvimagesink
+ * ]| This example pipeline will decode an ogg stream and decodes the daala video. Refer to
+ * the daalaenc example to create the ogg file.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-03-01 (0.10.4)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstdaaladec.h"
+#include <gst/tag/tag.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+
+#define GST_CAT_DEFAULT daaladec_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
+
+/* This was removed from the base class, this is used as a
+ temporary return to signal the need to call _drop_frame,
+ and does not leave daalaenc. */
+#define GST_CUSTOM_FLOW_DROP GST_FLOW_CUSTOM_SUCCESS_1
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate daala_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw, "
+ "format = (string) { I420, Y444 }, "
+ "framerate = (fraction) [0/1, MAX], "
+ "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate daala_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-daala")
+ );
+
+#define gst_daala_dec_parent_class parent_class
+G_DEFINE_TYPE (GstDaalaDec, gst_daala_dec, GST_TYPE_VIDEO_DECODER);
+
+static gboolean daala_dec_start (GstVideoDecoder * decoder);
+static gboolean daala_dec_stop (GstVideoDecoder * decoder);
+static gboolean daala_dec_set_format (GstVideoDecoder * decoder,
+ GstVideoCodecState * state);
+static gboolean daala_dec_reset (GstVideoDecoder * decoder, gboolean hard);
+static GstFlowReturn daala_dec_parse (GstVideoDecoder * decoder,
+ GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
+static GstFlowReturn daala_dec_handle_frame (GstVideoDecoder * decoder,
+ GstVideoCodecFrame * frame);
+static gboolean daala_dec_decide_allocation (GstVideoDecoder * decoder,
+ GstQuery * query);
+
+static GstFlowReturn daala_dec_decode_buffer (GstDaalaDec * dec,
+ GstBuffer * buf, GstVideoCodecFrame * frame);
+
+static void
+gst_daala_dec_class_init (GstDaalaDecClass * klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&daala_dec_src_factory));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&daala_dec_sink_factory));
+ gst_element_class_set_static_metadata (element_class,
+ "Daala video decoder", "Codec/Decoder/Video",
+ "Decode raw Daala streams to raw YUV video",
+ "Sebastian Dröge <slomo@circular-chaos.org>");
+
+ video_decoder_class->start = GST_DEBUG_FUNCPTR (daala_dec_start);
+ video_decoder_class->stop = GST_DEBUG_FUNCPTR (daala_dec_stop);
+ video_decoder_class->reset = GST_DEBUG_FUNCPTR (daala_dec_reset);
+ video_decoder_class->set_format = GST_DEBUG_FUNCPTR (daala_dec_set_format);
+ video_decoder_class->parse = GST_DEBUG_FUNCPTR (daala_dec_parse);
+ video_decoder_class->handle_frame =
+ GST_DEBUG_FUNCPTR (daala_dec_handle_frame);
+ video_decoder_class->decide_allocation =
+ GST_DEBUG_FUNCPTR (daala_dec_decide_allocation);
+
+ GST_DEBUG_CATEGORY_INIT (daaladec_debug, "daaladec", 0, "Daala decoder");
+}
+
+static void
+gst_daala_dec_init (GstDaalaDec * dec)
+{
+ /* input is packetized,
+ * but is not marked that way so data gets parsed and keyframes marked */
+ gst_video_decoder_set_packetized (GST_VIDEO_DECODER (dec), FALSE);
+}
+
+static void
+gst_daala_dec_reset (GstDaalaDec * dec)
+{
+ dec->need_keyframe = TRUE;
+}
+
+static gboolean
+daala_dec_start (GstVideoDecoder * decoder)
+{
+ GstDaalaDec *dec = GST_DAALA_DEC (decoder);
+
+ GST_DEBUG_OBJECT (dec, "start");
+ daala_info_clear (&dec->info);
+ daala_comment_clear (&dec->comment);
+ GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE");
+ dec->have_header = FALSE;
+ gst_daala_dec_reset (dec);
+
+ return TRUE;
+}
+
+static gboolean
+daala_dec_stop (GstVideoDecoder * decoder)
+{
+ GstDaalaDec *dec = GST_DAALA_DEC (decoder);
+
+ GST_DEBUG_OBJECT (dec, "stop");
+ daala_info_clear (&dec->info);
+ daala_comment_clear (&dec->comment);
+ daala_setup_free (dec->setup);
+ dec->setup = NULL;
+ daala_decode_free (dec->decoder);
+ dec->decoder = NULL;
+ gst_daala_dec_reset (dec);
+ if (dec->input_state) {
+ gst_video_codec_state_unref (dec->input_state);
+ dec->input_state = NULL;
+ }
+ if (dec->output_state) {
+ gst_video_codec_state_unref (dec->output_state);
+ dec->output_state = NULL;
+ }
+
+ return TRUE;
+}
+
+/* FIXME : Do we want to handle hard resets differently ? */
+static gboolean
+daala_dec_reset (GstVideoDecoder * bdec, gboolean hard)
+{
+ gst_daala_dec_reset (GST_DAALA_DEC (bdec));
+ return TRUE;
+}
+
+static GstFlowReturn
+daala_dec_parse (GstVideoDecoder * decoder,
+ GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
+{
+ gint av;
+ const guint8 *data;
+
+ av = gst_adapter_available (adapter);
+
+ if (av > 0) {
+ data = gst_adapter_map (adapter, 1);
+ /* check for keyframe; must not be header packet */
+ if (!(data[0] & 0x80) && (data[0] & 0x40)) {
+ GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+ }
+ gst_adapter_unmap (adapter);
+ }
+
+ /* and pass along all */
+ gst_video_decoder_add_to_frame (decoder, av);
+ return gst_video_decoder_have_frame (decoder);
+}
+
+
+static gboolean
+daala_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
+{
+ GstDaalaDec *dec;
+
+ dec = GST_DAALA_DEC (bdec);
+
+ /* Keep a copy of the input state */
+ if (dec->input_state)
+ gst_video_codec_state_unref (dec->input_state);
+ dec->input_state = gst_video_codec_state_ref (state);
+
+ /* FIXME : Interesting, we always accept any kind of caps ? */
+ if (state->codec_data) {
+ GstBuffer *buffer;
+ GstMapInfo minfo;
+ guint8 *data;
+ guint size;
+ guint offset;
+
+ buffer = state->codec_data;
+ gst_buffer_map (buffer, &minfo, GST_MAP_READ);
+
+ offset = 0;
+ size = minfo.size;
+ data = (guint8 *) minfo.data;
+
+ while (size > 2) {
+ guint psize;
+ GstBuffer *buf;
+
+ psize = (data[0] << 8) | data[1];
+ /* skip header */
+ data += 2;
+ size -= 2;
+ offset += 2;
+
+ /* make sure we don't read too much */
+ psize = MIN (psize, size);
+
+ buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
+
+ /* first buffer is a discont buffer */
+ if (offset == 2)
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+
+ /* now feed it to the decoder we can ignore the error */
+ daala_dec_decode_buffer (dec, buf, NULL);
+ gst_buffer_unref (buf);
+
+ /* skip the data */
+ size -= psize;
+ data += psize;
+ offset += psize;
+ }
+
+ gst_buffer_unmap (buffer, &minfo);
+ }
+
+ GST_DEBUG_OBJECT (dec, "Done");
+
+ return TRUE;
+}
+
+static GstFlowReturn
+daala_handle_comment_packet (GstDaalaDec * dec, ogg_packet * packet)
+{
+ gchar *encoder = NULL;
+ GstTagList *list;
+
+ GST_DEBUG_OBJECT (dec, "parsing comment packet");
+
+ list =
+ gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
+ (guint8 *) "\201daala", 6, &encoder);
+
+ if (!list) {
+ GST_ERROR_OBJECT (dec, "couldn't decode comments");
+ list = gst_tag_list_new_empty ();
+ }
+ if (encoder) {
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_ENCODER, encoder, NULL);
+ g_free (encoder);
+ }
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_ENCODER_VERSION, dec->info.version_major,
+ GST_TAG_VIDEO_CODEC, "Daala", NULL);
+
+ gst_video_decoder_merge_tags (GST_VIDEO_DECODER (dec),
+ list, GST_TAG_MERGE_REPLACE);
+
+ gst_tag_list_unref (list);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+daala_handle_type_packet (GstDaalaDec * dec)
+{
+ gint par_num, par_den;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstVideoCodecState *state;
+ GstVideoFormat fmt;
+ GstVideoInfo *info;
+
+ if (!dec->input_state)
+ return GST_FLOW_NOT_NEGOTIATED;
+
+ info = &dec->input_state->info;
+
+ GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
+ dec->info.timebase_numerator, dec->info.timebase_denominator,
+ dec->info.pixel_aspect_numerator, dec->info.pixel_aspect_denominator);
+
+ /* calculate par
+ * the info.aspect_* values reflect PAR;
+ * 0:x and x:0 are allowed and can be interpreted as 1:1.
+ */
+ par_num = GST_VIDEO_INFO_PAR_N (info);
+ par_den = GST_VIDEO_INFO_PAR_D (info);
+
+ /* If we have a default PAR, see if the decoder specified a different one */
+ if (par_num == 1 && par_den == 1 &&
+ (dec->info.pixel_aspect_numerator != 0 && dec->info.pixel_aspect_denominator != 0)) {
+ par_num = dec->info.pixel_aspect_numerator;
+ par_den = dec->info.pixel_aspect_denominator;
+ }
+ /* daala has:
+ *
+ * width/height : dimension of the encoded frame
+ * pic_width/pic_height : dimension of the visible part
+ * pic_x/pic_y : offset in encoded frame where visible part starts
+ */
+ GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
+ dec->info.pic_height, par_num, par_den);
+
+ if (dec->info.nplanes == 3 && dec->info.plane_info[0].xdec == 0 &&
+ dec->info.plane_info[0].ydec == 0 &&
+ dec->info.plane_info[1].xdec == 1 &&
+ dec->info.plane_info[1].ydec == 1 &&
+ dec->info.plane_info[2].xdec == 1 &&
+ dec->info.plane_info[2].ydec == 1) {
+ fmt = GST_VIDEO_FORMAT_I420;
+ } else if (dec->info.nplanes == 3 && dec->info.plane_info[0].xdec == 0 &&
+ dec->info.plane_info[0].ydec == 0 &&
+ dec->info.plane_info[1].xdec == 0 &&
+ dec->info.plane_info[1].ydec == 0 &&
+ dec->info.plane_info[2].xdec == 0 &&
+ dec->info.plane_info[2].ydec == 0) {
+ fmt = GST_VIDEO_FORMAT_Y444;
+ } else {
+ goto unsupported_format;
+ }
+
+ GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
+ GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;
+
+ /* done */
+ dec->decoder = daala_decode_alloc (&dec->info, dec->setup);
+
+ /* Create the output state */
+ dec->output_state = state =
+ gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), fmt,
+ info->width, info->height, dec->input_state);
+
+ /* FIXME : Do we still need to set fps/par now that we pass the reference input stream ? */
+ state->info.fps_n = dec->info.timebase_numerator;
+ state->info.fps_d = dec->info.timebase_denominator;
+ state->info.par_n = par_num;
+ state->info.par_d = par_den;
+
+ gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
+
+ dec->have_header = TRUE;
+
+ return ret;
+
+ /* ERRORS */
+unsupported_format:
+ {
+ GST_ERROR_OBJECT (dec, "Invalid pixel format");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+daala_handle_header_packet (GstDaalaDec * dec, ogg_packet * packet)
+{
+ GstFlowReturn res;
+ int ret;
+
+ GST_DEBUG_OBJECT (dec, "parsing header packet");
+
+ ret = daala_decode_header_in (&dec->info, &dec->comment, &dec->setup, packet);
+ if (ret < 0)
+ goto header_read_error;
+
+ switch (packet->packet[0]) {
+ case 0x81:
+ res = daala_handle_comment_packet (dec, packet);
+ break;
+ case 0x82:
+ res = daala_handle_type_packet (dec);
+ break;
+ default:
+ /* ignore */
+ g_warning ("unknown daala header packet found");
+ case 0x80:
+ /* nothing special, this is the identification header */
+ res = GST_FLOW_OK;
+ break;
+ }
+ return res;
+
+ /* ERRORS */
+header_read_error:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("couldn't read header packet"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+/* Allocate buffer and copy image data into Y444 format */
+static GstFlowReturn
+daala_handle_image (GstDaalaDec * dec, od_img * img,
+ GstVideoCodecFrame * frame)
+{
+ GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
+ gint width, height, stride;
+ GstFlowReturn result;
+ gint i, comp;
+ guint8 *dest, *src;
+ GstVideoFrame vframe;
+
+ result = gst_video_decoder_allocate_output_frame (decoder, frame);
+
+ if (G_UNLIKELY (result != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
+ gst_flow_get_name (result));
+ return result;
+ }
+
+ /* if only libdaala would allow us to give it a destination frame */
+ GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec,
+ "doing unavoidable video frame copy");
+
+ if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
+ frame->output_buffer, GST_MAP_WRITE)))
+ goto invalid_frame;
+
+ for (comp = 0; comp < 3; comp++) {
+ width =
+ GST_VIDEO_FRAME_COMP_WIDTH (&vframe, comp);
+ height =
+ GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, comp);
+ stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp);
+ dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp);
+
+ src = img->planes[comp].data;
+
+ for (i = 0; i < height; i++) {
+ memcpy (dest, src, width);
+
+ dest += stride;
+ src += img->planes[comp].ystride;
+ }
+ }
+ gst_video_frame_unmap (&vframe);
+
+ return GST_FLOW_OK;
+invalid_frame:
+ {
+ GST_DEBUG_OBJECT (dec, "could not map video frame");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+daala_handle_data_packet (GstDaalaDec * dec, ogg_packet * packet,
+ GstVideoCodecFrame * frame)
+{
+ /* normal data packet */
+ od_img img;
+ gboolean keyframe;
+ GstFlowReturn result;
+
+ if (G_UNLIKELY (!dec->have_header))
+ goto not_initialized;
+
+ /* the second most significant bit of the first data byte is cleared
+ * for keyframes. We can only check it if it's not a zero-length packet. */
+ keyframe = packet->bytes && ((packet->packet[0] & 0x40));
+ if (G_UNLIKELY (keyframe)) {
+ GST_DEBUG_OBJECT (dec, "we have a keyframe");
+ dec->need_keyframe = FALSE;
+ } else if (G_UNLIKELY (dec->need_keyframe)) {
+ goto dropping;
+ }
+
+ GST_DEBUG_OBJECT (dec, "parsing data packet");
+
+ /* this does the decoding */
+ if (G_UNLIKELY (daala_decode_packet_in (dec->decoder, &img, packet) < 0))
+ goto decode_error;
+
+ if (frame &&
+ (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec),
+ frame) < 0))
+ goto dropping_qos;
+
+ if (G_UNLIKELY ((img.width != dec->info.pic_width
+ || img.height != dec->info.pic_height)))
+ goto wrong_dimensions;
+
+ result = daala_handle_image (dec, &img, frame);
+
+ return result;
+
+ /* ERRORS */
+not_initialized:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("no header sent yet"));
+ return GST_FLOW_ERROR;
+ }
+dropping:
+ {
+ GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
+ return GST_CUSTOM_FLOW_DROP;
+ }
+dropping_qos:
+ {
+ GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
+ return GST_CUSTOM_FLOW_DROP;
+ }
+decode_error:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("daala decoder did not decode data packet"));
+ return GST_FLOW_ERROR;
+ }
+wrong_dimensions:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
+ (NULL), ("dimensions of image do not match header"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+daala_dec_decode_buffer (GstDaalaDec * dec, GstBuffer * buf,
+ GstVideoCodecFrame * frame)
+{
+ ogg_packet packet;
+ GstFlowReturn result = GST_FLOW_OK;
+ GstMapInfo minfo;
+
+ /* make ogg_packet out of the buffer */
+ gst_buffer_map (buf, &minfo, GST_MAP_READ);
+ packet.packet = minfo.data;
+ packet.bytes = minfo.size;
+ packet.granulepos = -1;
+ packet.packetno = 0; /* we don't really care */
+ packet.b_o_s = dec->have_header ? 0 : 1;
+ /* EOS does not matter for the decoder */
+ packet.e_o_s = 0;
+
+ GST_LOG_OBJECT (dec, "decode buffer of size %ld", packet.bytes);
+
+ GST_DEBUG_OBJECT (dec, "header=%02x", packet.bytes ? packet.packet[0] : -1);
+
+ /* switch depending on packet type. A zero byte packet is always a data
+ * packet; we don't dereference it in that case. */
+ if (packet.bytes && packet.packet[0] & 0x80) {
+ if (dec->have_header) {
+ GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
+ GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
+ GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+ result = GST_CUSTOM_FLOW_DROP;
+ goto done;
+ }
+ result = daala_handle_header_packet (dec, &packet);
+ /* header packets are not meant to be displayed */
+ /* FIXME : This is a temporary hack. The proper fix would be to
+ * not call _finish_frame() for these types of packets */
+ GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
+ GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+ } else {
+ result = daala_handle_data_packet (dec, &packet, frame);
+ }
+
+done:
+ gst_buffer_unmap (buf, &minfo);
+
+ return result;
+}
+
+static GstFlowReturn
+daala_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
+{
+ GstDaalaDec *dec;
+ GstFlowReturn res;
+
+ dec = GST_DAALA_DEC (bdec);
+
+ res = daala_dec_decode_buffer (dec, frame->input_buffer, frame);
+ switch (res) {
+ case GST_FLOW_OK:
+ res = gst_video_decoder_finish_frame (bdec, frame);
+ break;
+ case GST_CUSTOM_FLOW_DROP:
+ res = gst_video_decoder_drop_frame (bdec, frame);
+ break;
+ default:
+ gst_video_codec_frame_unref (frame);
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+daala_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
+{
+ GstBufferPool *pool;
+ GstStructure *config;
+
+ if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder, query))
+ return FALSE;
+
+ g_assert (gst_query_get_n_allocation_pools (query) > 0);
+ gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
+ g_assert (pool != NULL);
+
+ config = gst_buffer_pool_get_config (pool);
+ if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+ }
+ gst_buffer_pool_set_config (pool, config);
+ gst_object_unref (pool);
+
+ return TRUE;
+}
+
+gboolean
+gst_daala_dec_register (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "daaladec",
+ GST_RANK_PRIMARY, GST_TYPE_DAALA_DEC);
+}
diff --git a/ext/daala/gstdaaladec.h b/ext/daala/gstdaaladec.h
index e69de29bb..ff2a01ecf 100644
--- a/ext/daala/gstdaaladec.h
+++ b/ext/daala/gstdaaladec.h
@@ -0,0 +1,84 @@
+/* GStreamer
+ * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ * Copyright (c) 2012 Collabora Ltd.
+ * Author : Edward Hervey <edward@collabora.com>
+ * Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (c) 2013 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DAALADEC_H__
+#define __GST_DAALADEC_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/gstvideodecoder.h>
+#include <daala/daaladec.h>
+#include <string.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DAALA_DEC \
+ (gst_daala_dec_get_type())
+#define GST_DAALA_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DAALA_DEC,GstDaalaDec))
+#define GST_DAALA_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DAALA_DEC,GstDaalaDecClass))
+#define GST_IS_DAALA_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DAALA_DEC))
+#define GST_IS_DAALA_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DAALA_DEC))
+
+typedef struct _GstDaalaDec GstDaalaDec;
+typedef struct _GstDaalaDecClass GstDaalaDecClass;
+
+/**
+ * GstDaalaDec:
+ *
+ * Opaque object data structure.
+ */
+struct _GstDaalaDec
+{
+ GstVideoDecoder element;
+
+ /* daala decoder state */
+ daala_dec_ctx *decoder;
+ daala_setup_info *setup;
+ daala_info info;
+ daala_comment comment;
+
+ gboolean have_header;
+
+ gboolean need_keyframe;
+ GstVideoCodecState *input_state;
+ GstVideoCodecState *output_state;
+};
+
+struct _GstDaalaDecClass
+{
+ GstVideoDecoderClass parent_class;
+};
+
+GType gst_daala_dec_get_type (void);
+gboolean gst_daala_dec_register (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_DAALADEC_H__ */