| /* GStreamer | 
 |  * Copyright (C) 2006 David A. Schleef <ds@schleef.org> | 
 |  * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk> | 
 |  * | 
 |  * 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., 51 Franklin St, Fifth Floor, | 
 |  * Boston, MA 02110-1301, USA. | 
 |  */ | 
 | /** | 
 |  * SECTION:element-videoparse | 
 |  * @title: videoparse | 
 |  * | 
 |  * Converts a byte stream into video frames. | 
 |  * | 
 |  * > This element is deprecated. Use #GstRawVideoParse instead. | 
 |  */ | 
 |  | 
 | #ifdef HAVE_CONFIG_H | 
 | #  include "config.h" | 
 | #endif | 
 |  | 
 | /* FIXME 0.11: suppress warnings for deprecated API such as g_value_array stuff | 
 |  * for now with newer GLib versions (>= 2.31.0) */ | 
 | #define GLIB_DISABLE_DEPRECATION_WARNINGS | 
 |  | 
 | #include <gst/gst.h> | 
 | #include <gst/video/video.h> | 
 | #include "gstvideoparse.h" | 
 |  | 
 | static GstStaticPadTemplate static_sink_template = | 
 | GST_STATIC_PAD_TEMPLATE ("sink", | 
 |     GST_PAD_SINK, | 
 |     GST_PAD_ALWAYS, | 
 |     GST_STATIC_CAPS_ANY); | 
 |  | 
 | static GstStaticPadTemplate static_src_template = | 
 | GST_STATIC_PAD_TEMPLATE ("src", | 
 |     GST_PAD_SRC, | 
 |     GST_PAD_ALWAYS, | 
 |     GST_STATIC_CAPS ("video/x-raw") | 
 |     ); | 
 |  | 
 | 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 gboolean gst_video_parse_int_valarray_from_string (const gchar * | 
 |     str, GValue * valarray); | 
 | static gchar *gst_video_parse_int_valarray_to_string (GValue * valarray); | 
 |  | 
 | GST_DEBUG_CATEGORY_STATIC (gst_video_parse_debug); | 
 | #define GST_CAT_DEFAULT gst_video_parse_debug | 
 |  | 
 | enum | 
 | { | 
 |   PROP_0, | 
 |   PROP_FORMAT, | 
 |   PROP_WIDTH, | 
 |   PROP_HEIGHT, | 
 |   PROP_PAR, | 
 |   PROP_FRAMERATE, | 
 |   PROP_INTERLACED, | 
 |   PROP_TOP_FIELD_FIRST, | 
 |   PROP_STRIDES, | 
 |   PROP_OFFSETS, | 
 |   PROP_FRAMESIZE | 
 | }; | 
 |  | 
 | #define gst_video_parse_parent_class parent_class | 
 | G_DEFINE_TYPE (GstVideoParse, gst_video_parse, GST_TYPE_BIN); | 
 |  | 
 | 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; | 
 |  | 
 |   g_object_class_install_property (gobject_class, PROP_FORMAT, | 
 |       g_param_spec_enum ("format", "Format", "Format of images in raw stream", | 
 |           GST_TYPE_VIDEO_FORMAT, GST_VIDEO_FORMAT_I420, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_WIDTH, | 
 |       g_param_spec_int ("width", "Width", "Width of images in raw stream", | 
 |           0, INT_MAX, 320, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_HEIGHT, | 
 |       g_param_spec_int ("height", "Height", "Height of images in raw stream", | 
 |           0, INT_MAX, 240, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_FRAMERATE, | 
 |       gst_param_spec_fraction ("framerate", "Frame Rate", | 
 |           "Frame rate of images in raw stream", 0, 1, G_MAXINT, 1, 25, 1, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_PAR, | 
 |       gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio", | 
 |           "Pixel aspect ratio of images in raw stream", 1, 100, 100, 1, 1, 1, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_INTERLACED, | 
 |       g_param_spec_boolean ("interlaced", "Interlaced flag", | 
 |           "True if video is interlaced", FALSE, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_TOP_FIELD_FIRST, | 
 |       g_param_spec_boolean ("top-field-first", "Top field first", | 
 |           "True if top field is earlier than bottom field", TRUE, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_STRIDES, | 
 |       g_param_spec_string ("strides", "Strides", | 
 |           "Stride of each planes in bytes using string format: 's0,s1,s2,s3'", | 
 |           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_OFFSETS, | 
 |       g_param_spec_string ("offsets", "Offsets", | 
 |           "Offset of each planes in bytes using string format: 'o0,o1,o2,o3'", | 
 |           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |   g_object_class_install_property (gobject_class, PROP_FRAMESIZE, | 
 |       g_param_spec_uint ("framesize", "Framesize", | 
 |           "Size of an image in raw stream (0: default)", 0, G_MAXUINT, 0, | 
 |           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); | 
 |  | 
 |   gst_element_class_set_static_metadata (gstelement_class, "Video Parse", | 
 |       "Filter/Video", | 
 |       "Converts stream into video frames (deprecated: use rawvideoparse instead)", | 
 |       "David Schleef <ds@schleef.org>, " | 
 |       "Sebastian Dröge <sebastian.droege@collabora.co.uk>"); | 
 |  | 
 |   gst_element_class_add_pad_template (gstelement_class, | 
 |       gst_static_pad_template_get (&static_sink_template)); | 
 |   gst_element_class_add_pad_template (gstelement_class, | 
 |       gst_static_pad_template_get (&static_src_template)); | 
 |  | 
 |   GST_DEBUG_CATEGORY_INIT (gst_video_parse_debug, "videoparse", 0, | 
 |       "videoparse element"); | 
 | } | 
 |  | 
 | static void | 
 | gst_video_parse_init (GstVideoParse * vp) | 
 | { | 
 |   GstPad *inner_pad; | 
 |   GstPad *ghostpad; | 
 |  | 
 |   vp->rawvideoparse = | 
 |       gst_element_factory_make ("rawvideoparse", "inner_rawvideoparse"); | 
 |   g_assert (vp->rawvideoparse != NULL); | 
 |  | 
 |   gst_bin_add (GST_BIN (vp), vp->rawvideoparse); | 
 |  | 
 |   inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "sink"); | 
 |   ghostpad = | 
 |       gst_ghost_pad_new_from_template ("sink", inner_pad, | 
 |       gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "sink")); | 
 |   gst_element_add_pad (GST_ELEMENT (vp), ghostpad); | 
 |   gst_object_unref (GST_OBJECT (inner_pad)); | 
 |  | 
 |   inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "src"); | 
 |   ghostpad = | 
 |       gst_ghost_pad_new_from_template ("src", inner_pad, | 
 |       gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "src")); | 
 |   gst_element_add_pad (GST_ELEMENT (vp), ghostpad); | 
 |   gst_object_unref (GST_OBJECT (inner_pad)); | 
 | } | 
 |  | 
 | 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) { | 
 |     case PROP_FORMAT: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "format", | 
 |           g_value_get_enum (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_WIDTH: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "width", | 
 |           g_value_get_int (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_HEIGHT: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "height", | 
 |           g_value_get_int (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_FRAMERATE: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "framerate", | 
 |           gst_value_get_fraction_numerator (value), | 
 |           gst_value_get_fraction_denominator (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_PAR: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "pixel-aspect-ratio", | 
 |           gst_value_get_fraction_numerator (value), | 
 |           gst_value_get_fraction_denominator (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_INTERLACED: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "interlaced", | 
 |           g_value_get_boolean (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_TOP_FIELD_FIRST: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "top-field-first", | 
 |           g_value_get_boolean (value), NULL); | 
 |       break; | 
 |  | 
 |     case PROP_STRIDES:{ | 
 |       GValue valarray = G_VALUE_INIT; | 
 |  | 
 |       if (gst_video_parse_int_valarray_from_string (g_value_get_string (value), | 
 |               &valarray)) { | 
 |         g_object_set (G_OBJECT (vp->rawvideoparse), "plane-strides", | 
 |             &valarray, NULL); | 
 |         g_value_unset (&valarray); | 
 |       } else { | 
 |         GST_WARNING_OBJECT (vp, "failed to deserialize given strides"); | 
 |       } | 
 |  | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_OFFSETS:{ | 
 |       GValue valarray = G_VALUE_INIT; | 
 |  | 
 |       if (gst_video_parse_int_valarray_from_string (g_value_get_string (value), | 
 |               &valarray)) { | 
 |         g_object_set (G_OBJECT (vp->rawvideoparse), "plane-offsets", | 
 |             valarray, NULL); | 
 |         g_value_unset (&valarray); | 
 |       } else { | 
 |         GST_WARNING_OBJECT (vp, "failed to deserialize given offsets"); | 
 |       } | 
 |  | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_FRAMESIZE: | 
 |       g_object_set (G_OBJECT (vp->rawvideoparse), "frame-size", | 
 |           g_value_get_uint (value), NULL); | 
 |       break; | 
 |  | 
 |     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) { | 
 |     case PROP_FORMAT:{ | 
 |       GstVideoFormat format; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "format", &format, NULL); | 
 |       g_value_set_enum (value, format); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_WIDTH:{ | 
 |       gint width; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "width", &width, NULL); | 
 |       g_value_set_int (value, width); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_HEIGHT:{ | 
 |       gint height; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "height", &height, NULL); | 
 |       g_value_set_int (value, height); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_FRAMERATE:{ | 
 |       gint fps_n, fps_d; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "framerate", &fps_n, &fps_d, | 
 |           NULL); | 
 |       gst_value_set_fraction (value, fps_n, fps_d); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_PAR:{ | 
 |       gint par_n, par_d; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "pixel-aspect-ratio", &par_n, | 
 |           &par_d, NULL); | 
 |       gst_value_set_fraction (value, par_n, par_d); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_INTERLACED:{ | 
 |       gboolean interlaced; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "interlaced", &interlaced, | 
 |           NULL); | 
 |       g_value_set_boolean (value, interlaced); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_TOP_FIELD_FIRST:{ | 
 |       gboolean top_field_first; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "top-field-first", | 
 |           &top_field_first, NULL); | 
 |       g_value_set_boolean (value, top_field_first); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_STRIDES:{ | 
 |       GValue array = { 0, }; | 
 |  | 
 |       g_value_init (&array, GST_TYPE_ARRAY); | 
 |       g_object_get_property (G_OBJECT (vp->rawvideoparse), "plane-strides", | 
 |           &array); | 
 |       g_value_take_string (value, | 
 |           gst_video_parse_int_valarray_to_string (&array)); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_OFFSETS:{ | 
 |       GValue array = { 0, }; | 
 |  | 
 |       g_value_init (&array, GST_TYPE_ARRAY); | 
 |       g_object_get_property (G_OBJECT (vp->rawvideoparse), "plane-offsets", | 
 |           &array); | 
 |       g_value_take_string (value, | 
 |           gst_video_parse_int_valarray_to_string (&array)); | 
 |       break; | 
 |     } | 
 |  | 
 |     case PROP_FRAMESIZE:{ | 
 |       guint frame_size; | 
 |       g_object_get (G_OBJECT (vp->rawvideoparse), "frame-size", &frame_size, | 
 |           NULL); | 
 |       g_value_set_uint (value, frame_size); | 
 |       break; | 
 |     } | 
 |  | 
 |     default: | 
 |       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | 
 |       break; | 
 |   } | 
 | } | 
 |  | 
 | static gboolean | 
 | gst_video_parse_int_valarray_from_string (const gchar * str, GValue * valarray) | 
 | { | 
 |   gchar **strv; | 
 |   guint length; | 
 |   guint i; | 
 |   GValue gvalue = G_VALUE_INIT; | 
 |  | 
 |   if (str == NULL) | 
 |     return FALSE; | 
 |  | 
 |   strv = g_strsplit (str, ",", GST_VIDEO_MAX_PLANES); | 
 |   if (strv == NULL) | 
 |     return FALSE; | 
 |  | 
 |   length = g_strv_length (strv); | 
 |   g_value_init (valarray, GST_TYPE_ARRAY); | 
 |   g_value_init (&gvalue, G_TYPE_UINT); | 
 |  | 
 |   for (i = 0; i < length; i++) { | 
 |     gint64 val; | 
 |  | 
 |     val = g_ascii_strtoll (strv[i], NULL, 10); | 
 |     if (val < G_MININT || val > G_MAXINT) { | 
 |       goto error; | 
 |     } | 
 |  | 
 |     g_value_set_uint (&gvalue, val); | 
 |     gst_value_array_append_value (valarray, &gvalue); | 
 |   } | 
 |  | 
 |   g_strfreev (strv); | 
 |   return TRUE; | 
 |  | 
 | error: | 
 |   return FALSE; | 
 | } | 
 |  | 
 | static gchar * | 
 | gst_video_parse_int_valarray_to_string (GValue * valarray) | 
 | { | 
 |   /* holds a 64-bit number as string, which can have max. 20 digits | 
 |    * (with extra char for nullbyte) */ | 
 |   gchar stride_str[21]; | 
 |   gchar *str = NULL; | 
 |   guint i; | 
 |  | 
 |   for (i = 0; i < gst_value_array_get_size (valarray); i++) { | 
 |     const GValue *gvalue = gst_value_array_get_value (valarray, i); | 
 |     guint val; | 
 |  | 
 |     val = g_value_get_int (gvalue); | 
 |     g_snprintf (stride_str, sizeof (stride_str), "%u", val); | 
 |  | 
 |     if (str == NULL) { | 
 |       str = g_strdup (stride_str); | 
 |     } else { | 
 |       gchar *new_str = g_strdup_printf ("%s,%s", str, stride_str); | 
 |       g_free (str); | 
 |       str = new_str; | 
 |     } | 
 |   } | 
 |  | 
 |   return str; | 
 | } |