From 70431177ff80bbbc4eb7051d5d35bc4770daeffb Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sat, 11 Nov 2006 00:22:24 +0000 Subject: A little pluggy to make sense out of the random chunks we get from multifilesrc. Original commit message from CVS: * configure.ac: * gst/videoparse/Makefile.am: * gst/videoparse/gstvideoparse.c: A little pluggy to make sense out of the random chunks we get from multifilesrc. --- gst/videoparse/Makefile.am | 8 + gst/videoparse/gstvideoparse.c | 382 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 390 insertions(+) create mode 100644 gst/videoparse/Makefile.am create mode 100644 gst/videoparse/gstvideoparse.c (limited to 'gst/videoparse') diff --git a/gst/videoparse/Makefile.am b/gst/videoparse/Makefile.am new file mode 100644 index 00000000..7cc5fd2a --- /dev/null +++ b/gst/videoparse/Makefile.am @@ -0,0 +1,8 @@ + +plugin_LTLIBRARIES = libgstvideoparse.la + +libgstvideoparse_la_SOURCES = gstvideoparse.c +libgstvideoparse_la_CFLAGS = $(GST_CFLAGS) +libgstvideoparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) +libgstvideoparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + diff --git a/gst/videoparse/gstvideoparse.c b/gst/videoparse/gstvideoparse.c new file mode 100644 index 00000000..98378443 --- /dev/null +++ b/gst/videoparse/gstvideoparse.c @@ -0,0 +1,382 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef + * + * gstvideoparse.c: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-videoparse + * @short_description: parses a byte stream into video frames + * + * Converts a byte stream into video frames. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#define GST_TYPE_VIDEO_PARSE \ + (gst_video_parse_get_type()) +#define GST_VIDEO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_PARSE,GstVideoParse)) +#define GST_VIDEO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_PARSE,GstVideoParseClass)) +#define GST_IS_VIDEO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_PARSE)) +#define GST_IS_VIDEO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_PARSE)) + +typedef struct _GstVideoParse GstVideoParse; +typedef struct _GstVideoParseClass GstVideoParseClass; + +struct _GstVideoParse +{ + GstElement parent; + + GstPad *sinkpad; + GstPad *srcpad; + + int fps_n; + int fps_d; + + int frame_num; + + GstSegment segment; + + int negotiated; +}; + +struct _GstVideoParseClass +{ + GstElementClass parent_class; +}; + + +static void gst_video_parse_dispose (GObject * object); + +static void gst_video_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_video_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstFlowReturn gst_video_parse_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_video_parse_event (GstPad * pad, GstEvent * event); +static gboolean gst_video_parse_set_caps (GstPad * pad, GstCaps * caps); +static gboolean gst_video_parse_src_query (GstPad * pad, GstQuery * query); + + +static GstStaticPadTemplate gst_video_parse_src_pad_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate gst_video_parse_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC (gst_video_parse_debug); +#define GST_CAT_DEFAULT gst_video_parse_debug + +static const GstElementDetails gst_video_parse_details = +GST_ELEMENT_DETAILS ("Video Parse", + "Filter/Video", + "Converts stream into video frames", + "David Schleef "); + +enum +{ + ARG_0 +}; + + +GST_BOILERPLATE (GstVideoParse, gst_video_parse, GstElement, GST_TYPE_ELEMENT); + +static void +gst_video_parse_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + GST_DEBUG_CATEGORY_INIT (gst_video_parse_debug, "videoparse", 0, + "videoparse element"); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_video_parse_src_pad_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_video_parse_sink_pad_template)); + gst_element_class_set_details (gstelement_class, &gst_video_parse_details); +} + +static void +gst_video_parse_class_init (GstVideoParseClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + //GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_video_parse_set_property; + gobject_class->get_property = gst_video_parse_get_property; + + gobject_class->dispose = gst_video_parse_dispose; +} + +static void +gst_video_parse_init (GstVideoParse * vp, GstVideoParseClass * g_class) +{ + vp->sinkpad = + gst_pad_new_from_static_template (&gst_video_parse_sink_pad_template, + "sink"); + gst_element_add_pad (GST_ELEMENT (vp), vp->sinkpad); + + gst_pad_set_chain_function (vp->sinkpad, gst_video_parse_chain); + gst_pad_set_event_function (vp->sinkpad, gst_video_parse_event); + + vp->srcpad = + gst_pad_new_from_static_template (&gst_video_parse_src_pad_template, + "src"); + gst_element_add_pad (GST_ELEMENT (vp), vp->srcpad); + + gst_pad_set_setcaps_function (vp->srcpad, gst_video_parse_set_caps); + gst_pad_set_query_function (vp->srcpad, gst_video_parse_src_query); +} + +static void +gst_video_parse_dispose (GObject * object) +{ + //GstVideoParse *vp = GST_VIDEO_PARSE (object); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_video_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + //GstVideoParse *vp = GST_VIDEO_PARSE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_video_parse_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + //GstVideoParse *vp = GST_VIDEO_PARSE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_video_parse_negotiate (GstVideoParse * vp) +{ + GstCaps *caps; + gboolean ret = FALSE; + + caps = gst_pad_peer_get_caps (vp->srcpad); + + caps = gst_caps_make_writable (caps); + gst_caps_truncate (caps); + + if (!gst_caps_is_empty (caps)) { + gst_pad_fixate_caps (vp->srcpad, caps); + + if (gst_caps_is_any (caps)) { + ret = TRUE; + } else if (gst_caps_is_fixed (caps)) { + /* yay, fixed caps, use those then */ + gst_pad_set_caps (vp->srcpad, caps); + ret = TRUE; + } + } + + gst_caps_unref (caps); + + return ret; +} + +static GstFlowReturn +gst_video_parse_chain (GstPad * pad, GstBuffer * buffer) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (gst_pad_get_parent (pad)); + GstFlowReturn ret; + + GST_INFO ("here"); + + if (!vp->negotiated) { + gst_video_parse_negotiate (vp); + vp->negotiated = TRUE; + } + + if (vp->fps_n) { + GST_BUFFER_TIMESTAMP (buffer) = vp->segment.start + + gst_util_uint64_scale (vp->frame_num, GST_SECOND * vp->fps_d, + vp->fps_n); + GST_BUFFER_DURATION (buffer) = + gst_util_uint64_scale (GST_SECOND, vp->fps_d, vp->fps_n); + } else { + GST_BUFFER_TIMESTAMP (buffer) = vp->segment.start; + GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; + } + gst_buffer_set_caps (buffer, GST_PAD_CAPS (vp->srcpad)); + + vp->frame_num++; + + ret = gst_pad_push (vp->srcpad, buffer); + + gst_object_unref (vp); + + return ret; +} + +static gboolean +gst_video_parse_event (GstPad * pad, GstEvent * event) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (gst_pad_get_parent (pad)); + gboolean ret; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstClockTimeDiff start, stop, time; + gdouble rate, arate; + gboolean update; + GstFormat format; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + if (format == GST_FORMAT_TIME) { + gst_segment_set_newsegment_full (&vp->segment, update, rate, arate, + format, start, stop, time); + + GST_DEBUG_OBJECT (vp, "update segment: %" GST_SEGMENT_FORMAT, + &vp->segment); + } else { + GST_ERROR_OBJECT (vp, + "Segment doesn't have GST_FORMAT_TIME format (%d)", format); + + gst_event_unref (event); + gst_object_unref (vp); + return FALSE; + } + break; + } + default: + break; + } + + ret = gst_pad_push_event (vp->srcpad, event); + gst_object_unref (vp); + + return ret; +} + +static gboolean +gst_video_parse_set_caps (GstPad * pad, GstCaps * caps) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (gst_pad_get_parent (pad)); + GstStructure *s; + + s = gst_caps_get_structure (caps, 0); + + vp->fps_n = 0; + vp->fps_d = 1; + gst_structure_get_fraction (s, "framerate", &vp->fps_n, &vp->fps_d); + + GST_ERROR_OBJECT (vp, "framerate %d/%d", vp->fps_n, vp->fps_d); + + gst_object_unref (vp); + + return TRUE; +} + +static gboolean +gst_video_parse_src_query (GstPad * pad, GstQuery * query) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (gst_pad_get_parent (pad)); + gboolean ret = TRUE; + + if (GST_QUERY_TYPE (query) == GST_QUERY_CONVERT) { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); + if (src_fmt == dest_fmt) { + dest_val = src_val; + } else if (src_fmt == GST_FORMAT_DEFAULT && dest_fmt == GST_FORMAT_TIME) { + /* frames to time */ + + if (vp->fps_n) { + dest_val = gst_util_uint64_scale (src_val, vp->fps_d * GST_SECOND, + vp->fps_d); + } else { + dest_val = 0; + } + } else if (src_fmt == GST_FORMAT_DEFAULT && dest_fmt == GST_FORMAT_TIME) { + /* time to frames */ + + if (vp->fps_n) { + dest_val = gst_util_uint64_scale (src_val, vp->fps_n, + vp->fps_d * GST_SECOND); + } else { + dest_val = 0; + } + } else { + GST_DEBUG_OBJECT (vp, "query failed"); + ret = FALSE; + } + + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + } else { + ret = GST_ELEMENT_CLASS (parent_class)->query (GST_ELEMENT (vp), query); + } + + gst_object_unref (vp); + return ret; +} + + + + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gst_element_register (plugin, "videoparse", GST_RANK_NONE, + gst_video_parse_get_type ()); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "videoparse", + "Parses byte streams into video frames", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); -- cgit v1.2.1