diff options
Diffstat (limited to 'ext/dirac/gstdiracdec.cc')
-rw-r--r-- | ext/dirac/gstdiracdec.cc | 287 |
1 files changed, 213 insertions, 74 deletions
diff --git a/ext/dirac/gstdiracdec.cc b/ext/dirac/gstdiracdec.cc index 5a767c455..6a9c3abf6 100644 --- a/ext/dirac/gstdiracdec.cc +++ b/ext/dirac/gstdiracdec.cc @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) 2004 David A. Schleef <ds@schleef.org> + * Copyright (C) 2004 Ronald S. Bultje <rbultje@ronald.bitfreak.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,54 +23,19 @@ #include "config.h" #endif -#include <gst/gst.h> -#include <gst/video/video.h> - -#include <libdirac_decoder/seq_decompress.h> -#include <libdirac_common/pic_io.h> - -#define GST_TYPE_DIRACDEC \ - (gst_diracdec_get_type()) -#define GST_DIRACDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRACDEC,GstDiracDec)) -#define GST_DIRACDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRACDEC,GstDiracDec)) -#define GST_IS_DIRACDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRACDEC)) -#define GST_IS_DIRACDEC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRACDEC)) - -typedef struct _GstDiracDec GstDiracDec; -typedef struct _GstDiracDecClass GstDiracDecClass; - -struct _GstDiracDec -{ - GstElement element; - - /* pads */ - GstPad *sinkpad, *srcpad; - - SequenceDecompressor *decompress; - - std::istream * input_stream; - PicOutput *output_image; - -}; +#include <string.h> -struct _GstDiracDecClass -{ - GstElementClass parent_class; -}; - -GType gst_diracdec_get_type (void); +#include <gst/video/video.h> +#include "gstdiracdec.h" /* elementfactory information */ -GstElementDetails gst_diracdec_details = { +static GstElementDetails gst_diracdec_details = { "Dirac stream decoder", "Codec/Decoder/Video", "Decode DIRAC streams", - "David Schleef <ds@schleef.org>", + "David Schleef <ds@schleef.org>\n" + "Ronald Bultje <rbultje@ronald.bitfreak.net>", }; GST_DEBUG_CATEGORY (diracdec_debug); @@ -90,9 +56,10 @@ enum static void gst_diracdec_base_init (gpointer g_class); static void gst_diracdec_class_init (GstDiracDec * klass); static void gst_diracdec_init (GstDiracDec * diracdec); +static void gst_diracdec_dispose (GObject * object); -static void gst_diracdec_chain (GstPad * pad, GstData * _data); -static GstPadLinkReturn gst_diracdec_link (GstPad * pad, const GstCaps * caps); +static void gst_diracdec_chain (GstPad * pad, GstData * data); +static GstElementStateReturn gst_diracdec_change_state (GstElement * element); static GstElementClass *parent_class = NULL; @@ -120,6 +87,7 @@ gst_diracdec_get_type (void) g_type_register_static (GST_TYPE_ELEMENT, "GstDiracDec", &diracdec_info, (GTypeFlags) 0); } + return diracdec_type; } @@ -127,16 +95,15 @@ static GstStaticPadTemplate gst_diracdec_src_pad_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) + /* FIXME: 444 (planar? packed?), 411 (Y41B? Y41P?) */ + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YUY2, Y800 }")) ); static GstStaticPadTemplate gst_diracdec_sink_pad_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("image/dirac, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " "framerate = (double) [ 1, MAX ]") + GST_STATIC_CAPS ("video/x-dirac") ); static void @@ -154,29 +121,34 @@ gst_diracdec_base_init (gpointer g_class) static void gst_diracdec_class_init (GstDiracDec * klass) { - GstElementClass *gstelement_class; - - gstelement_class = (GstElementClass *) klass; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); parent_class = GST_ELEMENT_CLASS (g_type_class_ref (GST_TYPE_ELEMENT)); + gobject_class->dispose = gst_diracdec_dispose; + element_class->change_state = gst_diracdec_change_state; + GST_DEBUG_CATEGORY_INIT (diracdec_debug, "diracdec", 0, "DIRAC decoder"); } static void -gst_diracdec_init (GstDiracDec * diracdec) +gst_diracdec_dispose (GObject * object) { - SeqParams params; + G_OBJECT_CLASS (parent_class)->dispose (object); +} +static void +gst_diracdec_init (GstDiracDec * diracdec) +{ GST_DEBUG ("gst_diracdec_init: initializing"); /* create the sink and src pads */ diracdec->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&gst_diracdec_sink_pad_template), "sink"); - gst_element_add_pad (GST_ELEMENT (diracdec), diracdec->sinkpad); gst_pad_set_chain_function (diracdec->sinkpad, gst_diracdec_chain); - gst_pad_set_link_function (diracdec->sinkpad, gst_diracdec_link); + gst_element_add_pad (GST_ELEMENT (diracdec), diracdec->sinkpad); diracdec->srcpad = gst_pad_new_from_template (gst_static_pad_template_get @@ -184,37 +156,204 @@ gst_diracdec_init (GstDiracDec * diracdec) gst_pad_use_explicit_caps (diracdec->srcpad); gst_element_add_pad (GST_ELEMENT (diracdec), diracdec->srcpad); - //diracdec->input_stream = new std::istream (); - diracdec->input_stream = NULL; - diracdec->decompress = - new SequenceDecompressor (diracdec->input_stream, FALSE); - diracdec->output_image = new PicOutput ("moo", params, (bool) FALSE); + /* no capsnego done yet */ + diracdec->width = -1; + diracdec->height = -1; + diracdec->fps = 0; + diracdec->fcc = 0; } -static GstPadLinkReturn -gst_diracdec_link (GstPad * pad, const GstCaps * caps) +static guint32 +gst_diracdec_chroma_to_fourcc (dirac_chroma_t chroma) { - //GstDiracDec *diracdec = GST_DIRACDEC (gst_pad_get_parent (pad)); - GstStructure *structure; + guint32 fourcc = 0; + + switch (chroma) { + case Yonly: + fourcc = GST_MAKE_FOURCC ('Y', '8', '0', '0'); + break; + case format422: + fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); + break; + /* planar? */ + case format420: + case format444: + case format411: + default: + break; + } - //GstCaps *srccaps; + return fourcc; +} - structure = gst_caps_get_structure (caps, 0); +static gboolean +gst_diracdec_link (GstDiracDec * diracdec, + gint width, gint height, gdouble fps, guint32 fourcc) +{ + GstCaps *caps; + + if (width == diracdec->width && + height == diracdec->height && + fps == diracdec->fps && fourcc == diracdec->fcc) { + return TRUE; + } - return GST_PAD_LINK_OK; + if (!fourcc) { + g_warning ("Chroma not supported\n"); + return FALSE; + } + + caps = gst_caps_new_simple ("video/x-raw-yuv", + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "format", GST_TYPE_FOURCC, fourcc, "framerate", G_TYPE_DOUBLE, fps, NULL); + + if (gst_pad_set_explicit_caps (diracdec->srcpad, caps)) { + diracdec->width = width; + diracdec->height = height; + switch (fourcc) { + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + diracdec->size = width * height * 2; + break; + case GST_MAKE_FOURCC ('Y', '8', '0', '0'): + diracdec->size = width * height; + break; + } + diracdec->fcc = fourcc; + diracdec->fps = fps; + + return TRUE; + } + + return FALSE; } static void gst_diracdec_chain (GstPad * pad, GstData * _data) { - GstBuffer *buf = GST_BUFFER (_data); - GstDiracDec *diracdec; - - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); + GstDiracDec *diracdec = GST_DIRACDEC (gst_pad_get_parent (pad)); + GstBuffer *buf = GST_BUFFER (_data), *out; + gboolean c = TRUE; + + /* get state and do something */ + while (c) { + switch (dirac_parse (diracdec->decoder)) { + case STATE_BUFFER: + if (buf) { + /* provide data to decoder */ + dirac_buffer (diracdec->decoder, GST_BUFFER_DATA (buf), + GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf)); + gst_buffer_unref (buf); + buf = NULL; + } else { + /* need more data */ + c = FALSE; + } + break; + + case STATE_SEQUENCE:{ + guint8 *buf[3]; + + /* start-of-sequence - allocate buffer */ + if (!gst_diracdec_link (diracdec, + diracdec->decoder->seq_params.width, + diracdec->decoder->seq_params.height, + gst_diracdec_chroma_to_fourcc (diracdec->decoder->seq_params. + chroma), diracdec->decoder->seq_params.frame_rate)) { + GST_ELEMENT_ERROR (diracdec, CORE, NEGOTIATION, (NULL), + ("Failed to set caps to %dx%d @ %d fps (format=" GST_FOURCC_FORMAT + "/%d)", diracdec->decoder->seq_params.width, + diracdec->decoder->seq_params.height, + diracdec->decoder->seq_params.frame_rate, + gst_diracdec_chroma_to_fourcc (diracdec->decoder->seq_params. + chroma), diracdec->decoder->seq_params.chroma)); + c = FALSE; + break; + } + + g_free (diracdec->decoder->fbuf->buf[0]); + g_free (diracdec->decoder->fbuf->buf[1]); + g_free (diracdec->decoder->fbuf->buf[2]); + buf[0] = (guchar *) g_malloc (diracdec->decoder->seq_params.width * + diracdec->decoder->seq_params.height); + if (diracdec->decoder->seq_params.chroma != Yonly) { + buf[1] = + (guchar *) g_malloc (diracdec->decoder->seq_params.chroma_width * + diracdec->decoder->seq_params.chroma_height); + buf[2] = + (guchar *) g_malloc (diracdec->decoder->seq_params.chroma_width * + diracdec->decoder->seq_params.chroma_height); + } + dirac_set_buf (diracdec->decoder, buf, NULL); + break; + } + + case STATE_SEQUENCE_END: + /* end-of-sequence - free buffer */ + g_free (diracdec->decoder->fbuf->buf[0]); + diracdec->decoder->fbuf->buf[0] = NULL; + g_free (diracdec->decoder->fbuf->buf[1]); + diracdec->decoder->fbuf->buf[1] = NULL; + g_free (diracdec->decoder->fbuf->buf[2]); + diracdec->decoder->fbuf->buf[2] = NULL; + break; + + case STATE_PICTURE_START: + /* start of one picture */ + break; + + case STATE_PICTURE_AVAIL: + /* one picture is decoded */ + out = gst_pad_alloc_buffer (diracdec->srcpad, 0, diracdec->size); + memcpy (GST_BUFFER_DATA (out), diracdec->decoder->fbuf->buf[0], + diracdec->width * diracdec->height); + if (diracdec->fcc != GST_MAKE_FOURCC ('Y', '8', '0', '0')) { + memcpy (GST_BUFFER_DATA (out) + (diracdec->width * + diracdec->height), diracdec->decoder->fbuf->buf[1], + diracdec->decoder->seq_params.chroma_width * + diracdec->decoder->seq_params.chroma_height); + memcpy (GST_BUFFER_DATA (out) + + (diracdec->decoder->seq_params.chroma_width * + diracdec->decoder->seq_params.chroma_height) + + (diracdec->width * diracdec->height), + diracdec->decoder->fbuf->buf[2], + diracdec->decoder->seq_params.chroma_width * + diracdec->decoder->seq_params.chroma_height); + } + GST_BUFFER_TIMESTAMP (out) = (guint64) (GST_SECOND * + diracdec->decoder->frame_params.fnum / diracdec->fps); + GST_BUFFER_DURATION (out) = (guint64) (GST_SECOND / diracdec->fps); + gst_pad_push (diracdec->srcpad, GST_DATA (out)); + break; + + case STATE_INVALID: + default: + GST_ELEMENT_ERROR (diracdec, LIBRARY, TOO_LAZY, (NULL), (NULL)); + c = FALSE; + break; + } + } +} - diracdec = GST_DIRACDEC (GST_OBJECT_PARENT (pad)); +static GstElementStateReturn +gst_diracdec_change_state (GstElement * element) +{ + GstDiracDec *diracdec = GST_DIRACDEC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!(diracdec->decoder = dirac_decoder_init (0))) + return GST_STATE_FAILURE; + break; + case GST_STATE_READY_TO_NULL: + dirac_decoder_close (diracdec->decoder); + diracdec->width = diracdec->height = -1; + diracdec->fps = 0.; + diracdec->fcc = 0; + break; + default: + break; + } - gst_buffer_unref (buf); + return parent_class->change_state (element); } |