summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>2014-03-04 15:46:58 +0100
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>2014-04-28 14:06:45 +0200
commit644a807cce30b54bb8a8221fe475954b81eaef42 (patch)
treea99a3c7e78ba2734d849523461d4252835eedc9e
parentff02aef7342da44a6292d8a1b288e0405e4b8781 (diff)
downloadgstreamer-plugins-bad-644a807cce30b54bb8a8221fe475954b81eaef42.tar.gz
ivfparse: port to baseparse.
https://bugzilla.gnome.org/show_bug.cgi?id=710855 Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com> (cherry picked from commit 3d0ce67fcd886cf6e03f4f123d7da64491b96a8d)
-rw-r--r--configure.ac2
-rw-r--r--gst/ivfparse/gstivfparse.c346
-rw-r--r--gst/ivfparse/gstivfparse.h10
3 files changed, 196 insertions, 162 deletions
diff --git a/configure.ac b/configure.ac
index 8f1a4cb36..71453ab8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -338,7 +338,7 @@ dnl Non ported plugins (non-dependant, then dependant)
dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" cdxaparse \
dccp faceoverlay \
- hdvparse ivfparse jp2kdecimator \
+ hdvparse jp2kdecimator \
mve mythtv nuvdemux \
patchdetect real \
sdi stereo tta \
diff --git a/gst/ivfparse/gstivfparse.c b/gst/ivfparse/gstivfparse.c
index 8a2dc4d83..54122f238 100644
--- a/gst/ivfparse/gstivfparse.c
+++ b/gst/ivfparse/gstivfparse.c
@@ -51,6 +51,9 @@
#include "gstivfparse.h"
+#define IVF_FILE_HEADER_SIZE 32
+#define IVF_FRAME_HEADER_SIZE 12
+
GST_DEBUG_CATEGORY_STATIC (gst_ivf_parse_debug);
#define GST_CAT_DEFAULT gst_ivf_parse_debug
@@ -67,48 +70,51 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("ANY")
);
-GST_BOILERPLATE (GstIvfParse, gst_ivf_parse, GstElement, GST_TYPE_ELEMENT);
-
-static void gst_ivf_parse_dispose (GObject * object);
-static GstFlowReturn gst_ivf_parse_chain (GstPad * pad, GstBuffer * buf);
-
-/* GObject vmethod implementations */
-
-static void
-gst_ivf_parse_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+#define gst_ivf_parse_parent_class parent_class
+G_DEFINE_TYPE (GstIvfParse, gst_ivf_parse, GST_TYPE_BASE_PARSE);
- gst_element_class_set_static_metadata (element_class,
- "IVF parser",
- "Codec/Demuxer",
- "Demuxes a IVF stream", "Philip Jägenstedt <philipj@opera.com>");
+static void gst_ivf_parse_finalize (GObject * object);
+static gboolean gst_ivf_parse_start (GstBaseParse * parse);
+static gboolean gst_ivf_parse_stop (GstBaseParse * parse);
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
-}
+static GstFlowReturn
+gst_ivf_parse_handle_frame (GstBaseParse * parse,
+ GstBaseParseFrame * frame, gint * skipsize);
/* initialize the ivfparse's class */
static void
gst_ivf_parse_class_init (GstIvfParseClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseParseClass *gstbaseparse_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbaseparse_class = (GstBaseParseClass *) klass;
+
+ gobject_class->finalize = gst_ivf_parse_finalize;
+
+ gstbaseparse_class->start = gst_ivf_parse_start;
+ gstbaseparse_class->stop = gst_ivf_parse_stop;
+ gstbaseparse_class->handle_frame = gst_ivf_parse_handle_frame;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
- gobject_class->dispose = gst_ivf_parse_dispose;
+ gst_element_class_set_static_metadata (gstelement_class,
+ "IVF parser", "Codec/Demuxer",
+ "Demuxes a IVF stream", "Philip Jägenstedt <philipj@opera.com>");
+
+ /* debug category for filtering log messages */
+ GST_DEBUG_CATEGORY_INIT (gst_ivf_parse_debug, "ivfparse", 0, "IVF parser");
}
static void
gst_ivf_parse_reset (GstIvfParse * ivf)
{
- if (ivf->adapter) {
- gst_adapter_clear (ivf->adapter);
- g_object_unref (ivf->adapter);
- ivf->adapter = NULL;
- }
ivf->state = GST_IVF_PARSE_START;
ivf->rate_num = 0;
ivf->rate_den = 0;
@@ -120,170 +126,202 @@ gst_ivf_parse_reset (GstIvfParse * ivf)
* initialize instance structure
*/
static void
-gst_ivf_parse_init (GstIvfParse * ivf, GstIvfParseClass * gclass)
+gst_ivf_parse_init (GstIvfParse * ivf)
{
- /* sink pad */
- ivf->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
- gst_pad_set_chain_function (ivf->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ivf_parse_chain));
-
- /* src pad */
- ivf->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
- gst_pad_use_fixed_caps (ivf->srcpad);
-
- gst_element_add_pad (GST_ELEMENT (ivf), ivf->sinkpad);
- gst_element_add_pad (GST_ELEMENT (ivf), ivf->srcpad);
-
- /* reset */
gst_ivf_parse_reset (ivf);
}
static void
-gst_ivf_parse_dispose (GObject * object)
+gst_ivf_parse_finalize (GObject * object)
{
- GstIvfParse *ivf = GST_IVF_PARSE (object);
+ GstIvfParse *const ivf = GST_IVF_PARSE (object);
- GST_DEBUG_OBJECT (ivf, "disposing");
+ GST_DEBUG_OBJECT (ivf, "finalizing");
gst_ivf_parse_reset (ivf);
- G_OBJECT_CLASS (parent_class)->dispose (object);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
-/* GstElement vmethod implementations */
-
-/* chain function
- * this function does the actual processing
- */
-static GstFlowReturn
-gst_ivf_parse_chain (GstPad * pad, GstBuffer * buf)
+static gboolean
+gst_ivf_parse_start (GstBaseParse * parse)
{
- GstIvfParse *ivf = GST_IVF_PARSE (GST_OBJECT_PARENT (pad));
- gboolean res;
+ GstIvfParse *const ivf = GST_IVF_PARSE (parse);
- /* lazy creation of the adapter */
- if (G_UNLIKELY (ivf->adapter == NULL)) {
- ivf->adapter = gst_adapter_new ();
- }
-
- GST_LOG_OBJECT (ivf, "Pushing buffer of size %u to adapter",
- GST_BUFFER_SIZE (buf));
+ gst_ivf_parse_reset (ivf);
- gst_adapter_push (ivf->adapter, buf); /* adapter takes ownership of buf */
+ /* Minimal file header size needed at start */
+ gst_base_parse_set_min_frame_size (parse, IVF_FILE_HEADER_SIZE);
- res = GST_FLOW_OK;
+ /* No sync code to detect frame boundaries */
+ gst_base_parse_set_syncable (parse, FALSE);
- switch (ivf->state) {
- case GST_IVF_PARSE_START:
- if (gst_adapter_available (ivf->adapter) >= 32) {
- GstCaps *caps;
-
- const guint8 *data = gst_adapter_peek (ivf->adapter, 32);
- guint32 magic = GST_READ_UINT32_LE (data);
- guint16 version = GST_READ_UINT16_LE (data + 4);
- guint16 header_size = GST_READ_UINT16_LE (data + 6);
- guint32 fourcc = GST_READ_UINT32_LE (data + 8);
- guint16 width = GST_READ_UINT16_LE (data + 12);
- guint16 height = GST_READ_UINT16_LE (data + 14);
- guint32 rate_num = GST_READ_UINT32_LE (data + 16);
- guint32 rate_den = GST_READ_UINT32_LE (data + 20);
-#ifndef GST_DISABLE_GST_DEBUG
- guint32 num_frames = GST_READ_UINT32_LE (data + 24);
-#endif
-
- /* last 4 bytes unused */
- gst_adapter_flush (ivf->adapter, 32);
+ return TRUE;
+}
- if (magic != GST_MAKE_FOURCC ('D', 'K', 'I', 'F') ||
- version != 0 || header_size != 32 ||
- fourcc != GST_MAKE_FOURCC ('V', 'P', '8', '0')) {
- GST_ELEMENT_ERROR (ivf, STREAM, WRONG_TYPE, (NULL), (NULL));
- return GST_FLOW_ERROR;
- }
+static gboolean
+gst_ivf_parse_stop (GstBaseParse * parse)
+{
+ GstIvfParse *const ivf = GST_IVF_PARSE (parse);
- /* create src pad caps */
- caps = gst_caps_new_simple ("video/x-vp8",
- "width", G_TYPE_INT, width, "height", G_TYPE_INT, height,
- "framerate", GST_TYPE_FRACTION, rate_num, rate_den, NULL);
+ gst_ivf_parse_reset (ivf);
- GST_INFO_OBJECT (ivf, "Found stream: %" GST_PTR_FORMAT, caps);
+ return TRUE;
+}
- GST_LOG_OBJECT (ivf, "Stream has %d frames", num_frames);
+static GstFlowReturn
+gst_ivf_parse_handle_frame_start (GstIvfParse * ivf, GstBaseParseFrame * frame,
+ gint * skipsize)
+{
+ GstBuffer *const buffer = frame->buffer;
+ GstMapInfo map;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstCaps *caps;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ if (map.size >= IVF_FILE_HEADER_SIZE) {
+ guint32 magic = GST_READ_UINT32_LE (map.data);
+ guint16 version = GST_READ_UINT16_LE (map.data + 4);
+ guint16 header_size = GST_READ_UINT16_LE (map.data + 6);
+ guint32 fourcc = GST_READ_UINT32_LE (map.data + 8);
+ guint16 width = GST_READ_UINT16_LE (map.data + 12);
+ guint16 height = GST_READ_UINT16_LE (map.data + 14);
+ guint32 rate_num = GST_READ_UINT32_LE (map.data + 16);
+ guint32 rate_den = GST_READ_UINT32_LE (map.data + 20);
+#ifndef GST_DISABLE_GST_DEBUG
+ guint32 num_frames = GST_READ_UINT32_LE (map.data + 24);
+#endif
- gst_pad_set_caps (ivf->srcpad, caps);
- gst_caps_unref (caps);
+ if (magic != GST_MAKE_FOURCC ('D', 'K', 'I', 'F') ||
+ version != 0 || header_size != 32 ||
+ fourcc != GST_MAKE_FOURCC ('V', 'P', '8', '0')) {
+ GST_ELEMENT_ERROR (ivf, STREAM, WRONG_TYPE, (NULL), (NULL));
+ ret = GST_FLOW_ERROR;
+ goto end;
+ }
+
+ /* create src pad caps */
+ caps = gst_caps_new_simple ("video/x-vp8",
+ "width", G_TYPE_INT, width, "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, rate_num, rate_den, NULL);
+
+ GST_INFO_OBJECT (ivf, "Found stream: %" GST_PTR_FORMAT, caps);
+
+ GST_LOG_OBJECT (ivf, "Stream has %d frames", num_frames);
+
+ gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (ivf), caps);
+ gst_caps_unref (caps);
+
+ /* keep framerate in instance for convenience */
+ ivf->rate_num = rate_num;
+ ivf->rate_den = rate_den;
+
+ /* move along */
+ ivf->state = GST_IVF_PARSE_DATA;
+ gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (ivf),
+ IVF_FRAME_HEADER_SIZE);
+ *skipsize = IVF_FILE_HEADER_SIZE;
+ } else {
+ GST_LOG_OBJECT (ivf, "Header data not yet available.");
+ *skipsize = 0;
+ }
- /* keep framerate in instance for convenience */
- ivf->rate_num = rate_num;
- ivf->rate_den = rate_den;
+end:
+ gst_buffer_unmap (buffer, &map);
+ return ret;
+}
- gst_pad_push_event (ivf->srcpad, gst_event_new_new_segment (FALSE, 1.0,
- GST_FORMAT_TIME, 0, -1, 0));
+static GstFlowReturn
+gst_ivf_parse_handle_frame_data (GstIvfParse * ivf, GstBaseParseFrame * frame,
+ gint * skipsize)
+{
+ GstBuffer *const buffer = frame->buffer;
+ GstMapInfo map;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *out_buffer;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ if (map.size >= IVF_FILE_HEADER_SIZE) {
+ guint32 frame_size = GST_READ_UINT32_LE (map.data);
+ guint64 frame_pts = GST_READ_UINT64_LE (map.data + 4);
+
+ GST_LOG_OBJECT (ivf,
+ "Read frame header: size %u, pts %" G_GUINT64_FORMAT, frame_size,
+ frame_pts);
+
+ if (map.size < IVF_FRAME_HEADER_SIZE + frame_size) {
+ gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (ivf),
+ IVF_FRAME_HEADER_SIZE + frame_size);
+ gst_buffer_unmap (buffer, &map);
+ *skipsize = 0;
+ goto end;
+ }
+
+ gst_buffer_unmap (buffer, &map);
+
+ /* Eventually, we would need the buffer memory in a merged state anyway */
+ out_buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_FLAGS |
+ GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META |
+ GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_MERGE,
+ IVF_FRAME_HEADER_SIZE, frame_size);
+ if (!out_buffer) {
+ GST_ERROR_OBJECT (ivf, "Failed to copy frame buffer");
+ ret = GST_FLOW_ERROR;
+ *skipsize = IVF_FRAME_HEADER_SIZE + frame_size;
+ goto end;
+ }
+ gst_buffer_replace (&frame->out_buffer, out_buffer);
+ gst_buffer_unref (out_buffer);
+
+ GST_BUFFER_TIMESTAMP (out_buffer) =
+ gst_util_uint64_scale_int (GST_SECOND * frame_pts, ivf->rate_den,
+ ivf->rate_num);
+ GST_BUFFER_DURATION (out_buffer) =
+ gst_util_uint64_scale_int (GST_SECOND, ivf->rate_den, ivf->rate_num);
+
+ GST_DEBUG_OBJECT (ivf, "Pushing frame of size %u, ts %"
+ GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %"
+ G_GUINT64_FORMAT ", off_end %" G_GUINT64_FORMAT,
+ frame_size,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buffer)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (out_buffer)),
+ GST_BUFFER_OFFSET (out_buffer), GST_BUFFER_OFFSET_END (out_buffer));
+
+ ret = gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (ivf), frame,
+ IVF_FRAME_HEADER_SIZE + frame_size);
+ *skipsize = 0;
+ } else {
+ GST_LOG_OBJECT (ivf, "Frame data not yet available.");
+ gst_buffer_unmap (buffer, &map);
+ *skipsize = 0;
+ }
- /* move along */
- ivf->state = GST_IVF_PARSE_DATA;
- } else {
- GST_LOG_OBJECT (ivf, "Header data not yet available.");
- break;
- }
+end:
+ return ret;
+}
- /* fall through */
+static GstFlowReturn
+gst_ivf_parse_handle_frame (GstBaseParse * parse,
+ GstBaseParseFrame * frame, gint * skipsize)
+{
+ GstIvfParse *const ivf = GST_IVF_PARSE (parse);
+ switch (ivf->state) {
+ case GST_IVF_PARSE_START:
+ return gst_ivf_parse_handle_frame_start (ivf, frame, skipsize);
case GST_IVF_PARSE_DATA:
- while (gst_adapter_available (ivf->adapter) > 12) {
- const guint8 *data = gst_adapter_peek (ivf->adapter, 12);
- guint32 frame_size = GST_READ_UINT32_LE (data);
- guint64 frame_pts = GST_READ_UINT64_LE (data + 4);
-
- GST_LOG_OBJECT (ivf,
- "Read frame header: size %u, pts %" G_GUINT64_FORMAT, frame_size,
- frame_pts);
-
- if (gst_adapter_available (ivf->adapter) >= 12 + frame_size) {
- GstBuffer *frame;
-
- gst_adapter_flush (ivf->adapter, 12);
-
- frame = gst_adapter_take_buffer (ivf->adapter, frame_size);
- gst_buffer_set_caps (frame, GST_PAD_CAPS (ivf->srcpad));
- GST_BUFFER_TIMESTAMP (frame) =
- gst_util_uint64_scale_int (GST_SECOND * frame_pts, ivf->rate_den,
- ivf->rate_num);
- GST_BUFFER_DURATION (frame) =
- gst_util_uint64_scale_int (GST_SECOND, ivf->rate_den,
- ivf->rate_num);
-
- GST_DEBUG_OBJECT (ivf, "Pushing frame of size %u, ts %"
- GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %"
- G_GUINT64_FORMAT ", off_end %" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (frame),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (frame)),
- GST_BUFFER_OFFSET (frame), GST_BUFFER_OFFSET_END (frame));
-
- res = gst_pad_push (ivf->srcpad, frame);
- if (res != GST_FLOW_OK)
- break;
- } else {
- GST_LOG_OBJECT (ivf, "Frame data not yet available.");
- break;
- }
- }
- break;
-
+ return gst_ivf_parse_handle_frame_data (ivf, frame, skipsize);
default:
- g_return_val_if_reached (GST_FLOW_ERROR);
+ break;
}
- return res;
+ g_assert_not_reached ();
+ return GST_FLOW_ERROR;
}
/* entry point to initialize the plug-in */
static gboolean
ivfparse_init (GstPlugin * ivfparse)
{
- /* debug category for filtering log messages */
- GST_DEBUG_CATEGORY_INIT (gst_ivf_parse_debug, "ivfparse", 0, "IVF parser");
-
/* register parser element */
if (!gst_element_register (ivfparse, "ivfparse", GST_RANK_PRIMARY,
GST_TYPE_IVF_PARSE))
diff --git a/gst/ivfparse/gstivfparse.h b/gst/ivfparse/gstivfparse.h
index efbf58bbd..c0abc6b87 100644
--- a/gst/ivfparse/gstivfparse.h
+++ b/gst/ivfparse/gstivfparse.h
@@ -23,7 +23,7 @@
#define __GST_IVF_PARSE_H__
#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
+#include <gst/base/gstbaseparse.h>
G_BEGIN_DECLS
@@ -48,11 +48,7 @@ typedef struct _GstIvfParseClass GstIvfParseClass;
struct _GstIvfParse
{
- GstElement element;
-
- GstPad *sinkpad, *srcpad;
-
- GstAdapter *adapter;
+ GstBaseParse baseparse;
GstIvfParseState state;
@@ -63,7 +59,7 @@ struct _GstIvfParse
struct _GstIvfParseClass
{
- GstElementClass parent_class;
+ GstBaseParseClass parent_class;
};
GType gst_ivf_parse_get_type (void);