1 /* GStreamer
2 * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
3 * Copyright (C) 2007,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 *
5 * gstvideoparse.c:
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22 /**
23 * SECTION:element-videoparse
24 * @title: videoparse
25 *
26 * Converts a byte stream into video frames.
27 *
28 * > This element is deprecated. Use #GstRawVideoParse instead.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 /* FIXME 0.11: suppress warnings for deprecated API such as g_value_array stuff
36 * for now with newer GLib versions (>= 2.31.0) */
37 #define GLIB_DISABLE_DEPRECATION_WARNINGS
38
39 #include <gst/gst.h>
40 #include <gst/video/video.h>
41 #include "gstvideoparse.h"
42
43 static GstStaticPadTemplate static_sink_template =
44 GST_STATIC_PAD_TEMPLATE ("sink",
45 GST_PAD_SINK,
46 GST_PAD_ALWAYS,
47 GST_STATIC_CAPS_ANY);
48
49 static GstStaticPadTemplate static_src_template =
50 GST_STATIC_PAD_TEMPLATE ("src",
51 GST_PAD_SRC,
52 GST_PAD_ALWAYS,
53 GST_STATIC_CAPS ("video/x-raw")
54 );
55
56 static void gst_video_parse_set_property (GObject * object, guint prop_id,
57 const GValue * value, GParamSpec * pspec);
58 static void gst_video_parse_get_property (GObject * object, guint prop_id,
59 GValue * value, GParamSpec * pspec);
60
61 static gboolean gst_video_parse_int_valarray_from_string (const gchar *
62 str, GValue * valarray);
63 static gchar *gst_video_parse_int_valarray_to_string (GValue * valarray);
64
65 GST_DEBUG_CATEGORY_STATIC (gst_video_parse_debug);
66 #define GST_CAT_DEFAULT gst_video_parse_debug
67
68 enum
69 {
70 PROP_0,
71 PROP_FORMAT,
72 PROP_WIDTH,
73 PROP_HEIGHT,
74 PROP_PAR,
75 PROP_FRAMERATE,
76 PROP_INTERLACED,
77 PROP_TOP_FIELD_FIRST,
78 PROP_STRIDES,
79 PROP_OFFSETS,
80 PROP_FRAMESIZE
81 };
82
83 #define gst_video_parse_parent_class parent_class
84 G_DEFINE_TYPE (GstVideoParse, gst_video_parse, GST_TYPE_BIN);
85
86 static void
gst_video_parse_class_init(GstVideoParseClass * klass)87 gst_video_parse_class_init (GstVideoParseClass * klass)
88 {
89 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
90 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
91
92 gobject_class->set_property = gst_video_parse_set_property;
93 gobject_class->get_property = gst_video_parse_get_property;
94
95 g_object_class_install_property (gobject_class, PROP_FORMAT,
96 g_param_spec_enum ("format", "Format", "Format of images in raw stream",
97 GST_TYPE_VIDEO_FORMAT, GST_VIDEO_FORMAT_I420,
98 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
99 g_object_class_install_property (gobject_class, PROP_WIDTH,
100 g_param_spec_int ("width", "Width", "Width of images in raw stream",
101 0, INT_MAX, 320, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102 g_object_class_install_property (gobject_class, PROP_HEIGHT,
103 g_param_spec_int ("height", "Height", "Height of images in raw stream",
104 0, INT_MAX, 240, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
105 g_object_class_install_property (gobject_class, PROP_FRAMERATE,
106 gst_param_spec_fraction ("framerate", "Frame Rate",
107 "Frame rate of images in raw stream", 0, 1, G_MAXINT, 1, 25, 1,
108 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109 g_object_class_install_property (gobject_class, PROP_PAR,
110 gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
111 "Pixel aspect ratio of images in raw stream", 1, 100, 100, 1, 1, 1,
112 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
113 g_object_class_install_property (gobject_class, PROP_INTERLACED,
114 g_param_spec_boolean ("interlaced", "Interlaced flag",
115 "True if video is interlaced", FALSE,
116 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117 g_object_class_install_property (gobject_class, PROP_TOP_FIELD_FIRST,
118 g_param_spec_boolean ("top-field-first", "Top field first",
119 "True if top field is earlier than bottom field", TRUE,
120 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121 g_object_class_install_property (gobject_class, PROP_STRIDES,
122 g_param_spec_string ("strides", "Strides",
123 "Stride of each planes in bytes using string format: 's0,s1,s2,s3'",
124 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125 g_object_class_install_property (gobject_class, PROP_OFFSETS,
126 g_param_spec_string ("offsets", "Offsets",
127 "Offset of each planes in bytes using string format: 'o0,o1,o2,o3'",
128 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129 g_object_class_install_property (gobject_class, PROP_FRAMESIZE,
130 g_param_spec_uint ("framesize", "Framesize",
131 "Size of an image in raw stream (0: default)", 0, G_MAXUINT, 0,
132 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
133
134 gst_element_class_set_static_metadata (gstelement_class, "Video Parse",
135 "Filter/Video",
136 "Converts stream into video frames (deprecated: use rawvideoparse instead)",
137 "David Schleef <ds@schleef.org>, "
138 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
139
140 gst_element_class_add_pad_template (gstelement_class,
141 gst_static_pad_template_get (&static_sink_template));
142 gst_element_class_add_pad_template (gstelement_class,
143 gst_static_pad_template_get (&static_src_template));
144
145 GST_DEBUG_CATEGORY_INIT (gst_video_parse_debug, "videoparse", 0,
146 "videoparse element");
147 }
148
149 static void
gst_video_parse_init(GstVideoParse * vp)150 gst_video_parse_init (GstVideoParse * vp)
151 {
152 GstPad *inner_pad;
153 GstPad *ghostpad;
154
155 vp->rawvideoparse =
156 gst_element_factory_make ("rawvideoparse", "inner_rawvideoparse");
157 g_assert (vp->rawvideoparse != NULL);
158
159 gst_bin_add (GST_BIN (vp), vp->rawvideoparse);
160
161 inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "sink");
162 ghostpad =
163 gst_ghost_pad_new_from_template ("sink", inner_pad,
164 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "sink"));
165 gst_element_add_pad (GST_ELEMENT (vp), ghostpad);
166 gst_object_unref (GST_OBJECT (inner_pad));
167
168 inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "src");
169 ghostpad =
170 gst_ghost_pad_new_from_template ("src", inner_pad,
171 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "src"));
172 gst_element_add_pad (GST_ELEMENT (vp), ghostpad);
173 gst_object_unref (GST_OBJECT (inner_pad));
174 }
175
176 static void
gst_video_parse_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)177 gst_video_parse_set_property (GObject * object, guint prop_id,
178 const GValue * value, GParamSpec * pspec)
179 {
180 GstVideoParse *vp = GST_VIDEO_PARSE (object);
181
182 switch (prop_id) {
183 case PROP_FORMAT:
184 g_object_set (G_OBJECT (vp->rawvideoparse), "format",
185 g_value_get_enum (value), NULL);
186 break;
187
188 case PROP_WIDTH:
189 g_object_set (G_OBJECT (vp->rawvideoparse), "width",
190 g_value_get_int (value), NULL);
191 break;
192
193 case PROP_HEIGHT:
194 g_object_set (G_OBJECT (vp->rawvideoparse), "height",
195 g_value_get_int (value), NULL);
196 break;
197
198 case PROP_FRAMERATE:
199 g_object_set (G_OBJECT (vp->rawvideoparse), "framerate",
200 gst_value_get_fraction_numerator (value),
201 gst_value_get_fraction_denominator (value), NULL);
202 break;
203
204 case PROP_PAR:
205 g_object_set (G_OBJECT (vp->rawvideoparse), "pixel-aspect-ratio",
206 gst_value_get_fraction_numerator (value),
207 gst_value_get_fraction_denominator (value), NULL);
208 break;
209
210 case PROP_INTERLACED:
211 g_object_set (G_OBJECT (vp->rawvideoparse), "interlaced",
212 g_value_get_boolean (value), NULL);
213 break;
214
215 case PROP_TOP_FIELD_FIRST:
216 g_object_set (G_OBJECT (vp->rawvideoparse), "top-field-first",
217 g_value_get_boolean (value), NULL);
218 break;
219
220 case PROP_STRIDES:{
221 GValue valarray = G_VALUE_INIT;
222
223 if (gst_video_parse_int_valarray_from_string (g_value_get_string (value),
224 &valarray)) {
225 g_object_set (G_OBJECT (vp->rawvideoparse), "plane-strides",
226 &valarray, NULL);
227 g_value_unset (&valarray);
228 } else {
229 GST_WARNING_OBJECT (vp, "failed to deserialize given strides");
230 }
231
232 break;
233 }
234
235 case PROP_OFFSETS:{
236 GValue valarray = G_VALUE_INIT;
237
238 if (gst_video_parse_int_valarray_from_string (g_value_get_string (value),
239 &valarray)) {
240 g_object_set (G_OBJECT (vp->rawvideoparse), "plane-offsets",
241 valarray, NULL);
242 g_value_unset (&valarray);
243 } else {
244 GST_WARNING_OBJECT (vp, "failed to deserialize given offsets");
245 }
246
247 break;
248 }
249
250 case PROP_FRAMESIZE:
251 g_object_set (G_OBJECT (vp->rawvideoparse), "frame-size",
252 g_value_get_uint (value), NULL);
253 break;
254
255 default:
256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
257 break;
258 }
259 }
260
261 static void
gst_video_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)262 gst_video_parse_get_property (GObject * object, guint prop_id, GValue * value,
263 GParamSpec * pspec)
264 {
265 GstVideoParse *vp = GST_VIDEO_PARSE (object);
266
267 switch (prop_id) {
268 case PROP_FORMAT:{
269 GstVideoFormat format;
270 g_object_get (G_OBJECT (vp->rawvideoparse), "format", &format, NULL);
271 g_value_set_enum (value, format);
272 break;
273 }
274
275 case PROP_WIDTH:{
276 gint width;
277 g_object_get (G_OBJECT (vp->rawvideoparse), "width", &width, NULL);
278 g_value_set_int (value, width);
279 break;
280 }
281
282 case PROP_HEIGHT:{
283 gint height;
284 g_object_get (G_OBJECT (vp->rawvideoparse), "height", &height, NULL);
285 g_value_set_int (value, height);
286 break;
287 }
288
289 case PROP_FRAMERATE:{
290 gint fps_n, fps_d;
291 g_object_get (G_OBJECT (vp->rawvideoparse), "framerate", &fps_n, &fps_d,
292 NULL);
293 gst_value_set_fraction (value, fps_n, fps_d);
294 break;
295 }
296
297 case PROP_PAR:{
298 gint par_n, par_d;
299 g_object_get (G_OBJECT (vp->rawvideoparse), "pixel-aspect-ratio", &par_n,
300 &par_d, NULL);
301 gst_value_set_fraction (value, par_n, par_d);
302 break;
303 }
304
305 case PROP_INTERLACED:{
306 gboolean interlaced;
307 g_object_get (G_OBJECT (vp->rawvideoparse), "interlaced", &interlaced,
308 NULL);
309 g_value_set_boolean (value, interlaced);
310 break;
311 }
312
313 case PROP_TOP_FIELD_FIRST:{
314 gboolean top_field_first;
315 g_object_get (G_OBJECT (vp->rawvideoparse), "top-field-first",
316 &top_field_first, NULL);
317 g_value_set_boolean (value, top_field_first);
318 break;
319 }
320
321 case PROP_STRIDES:{
322 GValue array = { 0, };
323
324 g_value_init (&array, GST_TYPE_ARRAY);
325 g_object_get_property (G_OBJECT (vp->rawvideoparse), "plane-strides",
326 &array);
327 g_value_take_string (value,
328 gst_video_parse_int_valarray_to_string (&array));
329 break;
330 }
331
332 case PROP_OFFSETS:{
333 GValue array = { 0, };
334
335 g_value_init (&array, GST_TYPE_ARRAY);
336 g_object_get_property (G_OBJECT (vp->rawvideoparse), "plane-offsets",
337 &array);
338 g_value_take_string (value,
339 gst_video_parse_int_valarray_to_string (&array));
340 break;
341 }
342
343 case PROP_FRAMESIZE:{
344 guint frame_size;
345 g_object_get (G_OBJECT (vp->rawvideoparse), "frame-size", &frame_size,
346 NULL);
347 g_value_set_uint (value, frame_size);
348 break;
349 }
350
351 default:
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
353 break;
354 }
355 }
356
357 static gboolean
gst_video_parse_int_valarray_from_string(const gchar * str,GValue * valarray)358 gst_video_parse_int_valarray_from_string (const gchar * str, GValue * valarray)
359 {
360 gchar **strv;
361 guint length;
362 guint i;
363 GValue gvalue = G_VALUE_INIT;
364
365 if (str == NULL)
366 return FALSE;
367
368 strv = g_strsplit (str, ",", GST_VIDEO_MAX_PLANES);
369 if (strv == NULL)
370 return FALSE;
371
372 length = g_strv_length (strv);
373 g_value_init (valarray, GST_TYPE_ARRAY);
374 g_value_init (&gvalue, G_TYPE_UINT);
375
376 for (i = 0; i < length; i++) {
377 gint64 val;
378
379 val = g_ascii_strtoll (strv[i], NULL, 10);
380 if (val < G_MININT || val > G_MAXINT) {
381 goto error;
382 }
383
384 g_value_set_uint (&gvalue, val);
385 gst_value_array_append_value (valarray, &gvalue);
386 }
387
388 g_strfreev (strv);
389 return TRUE;
390
391 error:
392 return FALSE;
393 }
394
395 static gchar *
gst_video_parse_int_valarray_to_string(GValue * valarray)396 gst_video_parse_int_valarray_to_string (GValue * valarray)
397 {
398 /* holds a 64-bit number as string, which can have max. 20 digits
399 * (with extra char for nullbyte) */
400 gchar stride_str[21];
401 gchar *str = NULL;
402 guint i;
403
404 for (i = 0; i < gst_value_array_get_size (valarray); i++) {
405 const GValue *gvalue = gst_value_array_get_value (valarray, i);
406 guint val;
407
408 val = g_value_get_int (gvalue);
409 g_snprintf (stride_str, sizeof (stride_str), "%u", val);
410
411 if (str == NULL) {
412 str = g_strdup (stride_str);
413 } else {
414 gchar *new_str = g_strdup_printf ("%s,%s", str, stride_str);
415 g_free (str);
416 str = new_str;
417 }
418 }
419
420 return str;
421 }
422