1 /* GStreamer
2 * Copyright (C) <2016> Carlos Rafael Giani <dv at pseudoterminal dot org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-rawvideoparse
22 * @title: rawvideoparse
23 *
24 * This element parses incoming data as raw video frames and timestamps these.
25 * It also handles seek queries in said raw video data, and ensures that output
26 * buffers contain exactly one frame, even if the input buffers contain only
27 * partial frames or multiple frames. In the former case, it will continue to
28 * receive buffers until there is enough input data to output one frame. In the
29 * latter case, it will extract the first frame in the buffer and output it, then
30 * the second one etc. until the remaining unparsed bytes aren't enough to form
31 * a complete frame, and it will then continue as described in the earlier case.
32 *
33 * The element implements the properties and sink caps configuration as specified
34 * in the #GstRawBaseParse documentation. The properties configuration can be
35 * modified by using the width, height, pixel-aspect-ratio, framerate, interlaced,
36 * top-field-first, plane-strides, plane-offsets, and frame-size properties.
37 *
38 * If the properties configuration is used, plane strides and offsets will be
39 * computed by using gst_video_info_set_format(). This can be overridden by passing
40 * GstValueArrays to the plane-offsets and plane-strides properties. When this is
41 * done, these custom offsets and strides are used later even if new width,
42 * height, format etc. property values might be set. To switch back to computed
43 * plane strides & offsets, pass NULL to one or both of the plane-offset and
44 * plane-array properties.
45 *
46 * The frame size property is useful in cases where there is extra data between
47 * the frames (for example, trailing metadata, or headers). The parser calculates
48 * the actual frame size out of the other properties and compares it with this
49 * frame-size value. If the frame size is larger than the calculated size,
50 * then the extra bytes after the end of the frame are skipped. For example, with
51 * 8-bit grayscale frames and a actual frame size of 100x10 pixels and a frame-size of
52 * 1500 bytes, there are 500 excess bytes at the end of the actual frame which
53 * are then skipped. It is safe to set the frame size to a value that is smaller
54 * than the actual frame size (in fact, its default value is 0); if it is smaller,
55 * then no trailing data will be skipped.
56 *
57 * If a framerate of 0 Hz is set (for example, 0/1), then output buffers will have
58 * no duration set. The first output buffer will have a PTS 0, all subsequent ones
59 * an unset PTS.
60 *
61 * ## Example pipelines
62 * |[
63 * gst-launch-1.0 filesrc location=video.raw ! rawvideoparse use-sink-caps=false \
64 * width=500 height=400 format=y444 ! autovideosink
65 * ]|
66 * Read raw data from a local file and parse it as video data with 500x400 pixels
67 * and Y444 video format.
68 * |[
69 * gst-launch-1.0 filesrc location=video.raw ! queue ! "video/x-raw, width=320, \
70 * height=240, format=I420, framerate=1/1" ! rawvideoparse \
71 * use-sink-caps=true ! autovideosink
72 * ]|
73 * Read raw data from a local file and parse it as video data with 320x240 pixels
74 * and I420 video format. The queue element here is to force push based scheduling.
75 * See the documentation in #GstRawBaseParse for the reason why.
76 *
77 */
78
79 #ifdef HAVE_CONFIG_H
80 # include "config.h"
81 #endif
82
83 #include <string.h>
84 #include "gstrawvideoparse.h"
85 #include "unalignedvideo.h"
86
87 GST_DEBUG_CATEGORY_STATIC (raw_video_parse_debug);
88 #define GST_CAT_DEFAULT raw_video_parse_debug
89
90 enum
91 {
92 PROP_0,
93 PROP_WIDTH,
94 PROP_HEIGHT,
95 PROP_FORMAT,
96 PROP_PIXEL_ASPECT_RATIO,
97 PROP_FRAMERATE,
98 PROP_INTERLACED,
99 PROP_TOP_FIELD_FIRST,
100 PROP_PLANE_STRIDES,
101 PROP_PLANE_OFFSETS,
102 PROP_FRAME_SIZE
103 };
104
105 #define DEFAULT_WIDTH 320
106 #define DEFAULT_HEIGHT 240
107 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_I420
108 #define DEFAULT_PIXEL_ASPECT_RATIO_N 1
109 #define DEFAULT_PIXEL_ASPECT_RATIO_D 1
110 #define DEFAULT_FRAMERATE_N 25
111 #define DEFAULT_FRAMERATE_D 1
112 #define DEFAULT_INTERLACED FALSE
113 #define DEFAULT_TOP_FIELD_FIRST FALSE
114 #define DEFAULT_FRAME_STRIDE 0
115
116 #define GST_RAW_VIDEO_PARSE_CAPS \
117 GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) "; "
118
119 static GstStaticPadTemplate static_sink_template =
120 GST_STATIC_PAD_TEMPLATE ("sink",
121 GST_PAD_SINK,
122 GST_PAD_ALWAYS,
123 GST_STATIC_CAPS (GST_UNALIGNED_RAW_VIDEO_CAPS "; " GST_RAW_VIDEO_PARSE_CAPS)
124 );
125
126 static GstStaticPadTemplate static_src_template =
127 GST_STATIC_PAD_TEMPLATE ("src",
128 GST_PAD_SRC,
129 GST_PAD_ALWAYS,
130 GST_STATIC_CAPS (GST_RAW_VIDEO_PARSE_CAPS)
131 );
132
133 #define gst_raw_video_parse_parent_class parent_class
134 G_DEFINE_TYPE (GstRawVideoParse, gst_raw_video_parse, GST_TYPE_RAW_BASE_PARSE);
135
136 static void gst_raw_video_parse_set_property (GObject * object, guint prop_id,
137 GValue const *value, GParamSpec * pspec);
138 static void gst_raw_video_parse_get_property (GObject * object, guint prop_id,
139 GValue * value, GParamSpec * pspec);
140
141 static gboolean gst_raw_video_parse_stop (GstBaseParse * parse);
142
143 static gboolean gst_raw_video_parse_set_current_config (GstRawBaseParse *
144 raw_base_parse, GstRawBaseParseConfig config);
145 static GstRawBaseParseConfig
146 gst_raw_video_parse_get_current_config (GstRawBaseParse * raw_base_parse);
147 static gboolean gst_raw_video_parse_set_config_from_caps (GstRawBaseParse *
148 raw_base_parse, GstRawBaseParseConfig config, GstCaps * caps);
149 static gboolean gst_raw_video_parse_get_caps_from_config (GstRawBaseParse *
150 raw_base_parse, GstRawBaseParseConfig config, GstCaps ** caps);
151 static gsize gst_raw_video_parse_get_config_frame_size (GstRawBaseParse *
152 raw_base_parse, GstRawBaseParseConfig config);
153 static guint gst_raw_video_parse_get_max_frames_per_buffer (GstRawBaseParse *
154 raw_base_parse, GstRawBaseParseConfig config);
155 static gboolean gst_raw_video_parse_is_config_ready (GstRawBaseParse *
156 raw_base_parse, GstRawBaseParseConfig config);
157 static gboolean gst_raw_video_parse_process (GstRawBaseParse * raw_base_parse,
158 GstRawBaseParseConfig config, GstBuffer * in_data, gsize total_num_in_bytes,
159 gsize num_valid_in_bytes, GstBuffer ** processed_data);
160 static gboolean gst_raw_video_parse_is_unit_format_supported (GstRawBaseParse *
161 raw_base_parse, GstFormat format);
162 static void gst_raw_video_parse_get_units_per_second (GstRawBaseParse *
163 raw_base_parse, GstFormat format, GstRawBaseParseConfig config,
164 gsize * units_per_sec_n, gsize * units_per_sec_d);
165
166 static gint gst_raw_video_parse_get_overhead_size (GstRawBaseParse *
167 raw_base_parse, GstRawBaseParseConfig config);
168
169 static gboolean gst_raw_video_parse_is_using_sink_caps (GstRawVideoParse *
170 raw_video_parse);
171 static GstRawVideoParseConfig
172 * gst_raw_video_parse_get_config_ptr (GstRawVideoParse * raw_video_parse,
173 GstRawBaseParseConfig config);
174
175 static void gst_raw_video_parse_init_config (GstRawVideoParseConfig * config);
176 static void gst_raw_video_parse_update_info (GstRawVideoParseConfig * config);
177
178 static void
gst_raw_video_parse_class_init(GstRawVideoParseClass * klass)179 gst_raw_video_parse_class_init (GstRawVideoParseClass * klass)
180 {
181 GObjectClass *object_class;
182 GstElementClass *element_class;
183 GstBaseParseClass *baseparse_class;
184 GstRawBaseParseClass *rawbaseparse_class;
185
186 GST_DEBUG_CATEGORY_INIT (raw_video_parse_debug, "rawvideoparse", 0,
187 "rawvideoparse element");
188
189 object_class = G_OBJECT_CLASS (klass);
190 element_class = GST_ELEMENT_CLASS (klass);
191 baseparse_class = GST_BASE_PARSE_CLASS (klass);
192 rawbaseparse_class = GST_RAW_BASE_PARSE_CLASS (klass);
193
194 gst_element_class_add_pad_template (element_class,
195 gst_static_pad_template_get (&static_sink_template));
196 gst_element_class_add_pad_template (element_class,
197 gst_static_pad_template_get (&static_src_template));
198
199 object_class->set_property =
200 GST_DEBUG_FUNCPTR (gst_raw_video_parse_set_property);
201 object_class->get_property =
202 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_property);
203
204 baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_raw_video_parse_stop);
205
206 rawbaseparse_class->set_current_config =
207 GST_DEBUG_FUNCPTR (gst_raw_video_parse_set_current_config);
208 rawbaseparse_class->get_current_config =
209 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_current_config);
210 rawbaseparse_class->set_config_from_caps =
211 GST_DEBUG_FUNCPTR (gst_raw_video_parse_set_config_from_caps);
212 rawbaseparse_class->get_caps_from_config =
213 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_caps_from_config);
214 rawbaseparse_class->get_config_frame_size =
215 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_config_frame_size);
216 rawbaseparse_class->get_max_frames_per_buffer =
217 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_max_frames_per_buffer);
218 rawbaseparse_class->is_config_ready =
219 GST_DEBUG_FUNCPTR (gst_raw_video_parse_is_config_ready);
220 rawbaseparse_class->process = GST_DEBUG_FUNCPTR (gst_raw_video_parse_process);
221 rawbaseparse_class->is_unit_format_supported =
222 GST_DEBUG_FUNCPTR (gst_raw_video_parse_is_unit_format_supported);
223 rawbaseparse_class->get_units_per_second =
224 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_units_per_second);
225 rawbaseparse_class->get_overhead_size =
226 GST_DEBUG_FUNCPTR (gst_raw_video_parse_get_overhead_size);
227
228 g_object_class_install_property (object_class,
229 PROP_WIDTH,
230 g_param_spec_int ("width",
231 "Width",
232 "Width of frames in raw stream",
233 0, G_MAXINT, DEFAULT_WIDTH,
234 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
235 );
236 g_object_class_install_property (object_class,
237 PROP_HEIGHT,
238 g_param_spec_int ("height",
239 "Height",
240 "Height of frames in raw stream",
241 0, G_MAXINT,
242 DEFAULT_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
243 );
244 g_object_class_install_property (object_class,
245 PROP_FORMAT,
246 g_param_spec_enum ("format",
247 "Format",
248 "Format of frames in raw stream",
249 GST_TYPE_VIDEO_FORMAT,
250 DEFAULT_FORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
251 );
252 g_object_class_install_property (object_class,
253 PROP_FRAMERATE,
254 gst_param_spec_fraction ("framerate",
255 "Frame rate",
256 "Rate of frames in raw stream",
257 0, 1, G_MAXINT, 1,
258 DEFAULT_FRAMERATE_N, DEFAULT_FRAMERATE_D,
259 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
260 );
261 g_object_class_install_property (object_class,
262 PROP_PIXEL_ASPECT_RATIO,
263 gst_param_spec_fraction ("pixel-aspect-ratio",
264 "Pixel aspect ratio",
265 "Pixel aspect ratio of frames in raw stream",
266 1, 100, 100, 1,
267 DEFAULT_PIXEL_ASPECT_RATIO_N, DEFAULT_PIXEL_ASPECT_RATIO_D,
268 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
269 );
270 g_object_class_install_property (object_class,
271 PROP_INTERLACED,
272 g_param_spec_boolean ("interlaced",
273 "Interlaced flag",
274 "True if frames in raw stream are interlaced",
275 DEFAULT_INTERLACED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
276 );
277 g_object_class_install_property (object_class,
278 PROP_TOP_FIELD_FIRST,
279 g_param_spec_boolean ("top-field-first",
280 "Top field first",
281 "True if top field in frames in raw stream come first (not used if frames aren't interlaced)",
282 DEFAULT_INTERLACED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
283 );
284 g_object_class_install_property (object_class,
285 PROP_PLANE_STRIDES,
286 gst_param_spec_array ("plane-strides",
287 "Plane strides",
288 "Strides of the planes in bytes (e.g. plane-strides=\"<320,320>\")",
289 g_param_spec_int ("plane-stride",
290 "Plane stride",
291 "Stride of the n-th plane in bytes (0 = stride equals width*bytes-per-pixel)",
292 0, G_MAXINT,
293 0,
294 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
295 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
296 );
297 g_object_class_install_property (object_class,
298 PROP_PLANE_OFFSETS,
299 gst_param_spec_array ("plane-offsets",
300 "Plane offsets",
301 "Offsets of the planes in bytes (e.g. plane-offsets=\"<0,76800>\")",
302 g_param_spec_int ("plane-offset",
303 "Plane offset",
304 "Offset of the n-th plane in bytes",
305 0, G_MAXINT,
306 0,
307 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
308 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
309 );
310 g_object_class_install_property (object_class,
311 PROP_FRAME_SIZE,
312 g_param_spec_uint ("frame-size",
313 "Frame size",
314 "Size of a frame (0 = frames are tightly packed together)",
315 0, G_MAXUINT,
316 DEFAULT_FRAME_STRIDE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
317 );
318
319 gst_element_class_set_static_metadata (element_class,
320 "rawvideoparse",
321 "Codec/Parser/Video",
322 "Converts unformatted data streams into timestamped raw video frames",
323 "Carlos Rafael Giani <dv@pseudoterminal.org>");
324 }
325
326 static void
gst_raw_video_parse_init(GstRawVideoParse * raw_video_parse)327 gst_raw_video_parse_init (GstRawVideoParse * raw_video_parse)
328 {
329 gst_raw_video_parse_init_config (&(raw_video_parse->properties_config));
330 gst_raw_video_parse_init_config (&(raw_video_parse->sink_caps_config));
331
332 /* As required by GstRawBaseParse, ensure that the current configuration
333 * is initially set to be the properties config */
334 raw_video_parse->current_config = &(raw_video_parse->properties_config);
335
336 /* Properties config must be valid from the start, so set its ready value
337 * to TRUE, and make sure its bpf value is valid. */
338 raw_video_parse->properties_config.ready = TRUE;
339 raw_video_parse->properties_config.top_field_first = DEFAULT_TOP_FIELD_FIRST;
340 raw_video_parse->properties_config.frame_size = DEFAULT_FRAME_STRIDE;
341 }
342
343 static void
gst_raw_video_parse_set_property(GObject * object,guint prop_id,GValue const * value,GParamSpec * pspec)344 gst_raw_video_parse_set_property (GObject * object, guint prop_id,
345 GValue const *value, GParamSpec * pspec)
346 {
347 GstBaseParse *base_parse = GST_BASE_PARSE (object);
348 GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object);
349 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (object);
350 GstRawVideoParseConfig *props_cfg = &(raw_video_parse->properties_config);
351
352 /* All properties are handled similarly:
353 * - if the new value is the same as the current value, nothing is done
354 * - the parser lock is held while the new value is set
355 * - if the properties config is the current config, the source caps are
356 * invalidated to ensure that the code in handle_frame pushes a new CAPS
357 * event out
358 * - properties that affect the video frame size call the function to update
359 * the info and also call gst_base_parse_set_min_frame_size() to ensure
360 * that the minimum frame size can hold 1 frame (= one sample for each
361 * channel); to ensure that the min frame size includes any extra padding,
362 * it is set to the result of gst_raw_video_parse_get_config_frame_size()
363 * - property configuration values that require video info updates aren't
364 * written directory into the video info structure, but in the extra
365 * fields instead (gst_raw_video_parse_update_info() then copies the values
366 * from these fields into the video info); see the documentation inside
367 * gst_raw_video_parse_update_info() for the reason why
368 */
369
370 switch (prop_id) {
371 case PROP_WIDTH:
372 {
373 gint new_width = g_value_get_int (value);
374
375 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
376
377 if (new_width != props_cfg->width) {
378 props_cfg->width = new_width;
379 gst_raw_video_parse_update_info (props_cfg);
380
381 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) {
382 gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
383 gst_base_parse_set_min_frame_size (base_parse,
384 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
385 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
386 }
387 }
388
389 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
390 break;
391 }
392
393 case PROP_HEIGHT:
394 {
395 gint new_height = g_value_get_int (value);
396
397 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
398
399 if (new_height != props_cfg->height) {
400 props_cfg->height = new_height;
401 gst_raw_video_parse_update_info (props_cfg);
402
403 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) {
404 gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
405 gst_base_parse_set_min_frame_size (base_parse,
406 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
407 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
408 }
409 }
410
411 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
412 break;
413 }
414
415 case PROP_FORMAT:
416 {
417 GstVideoFormat new_format = g_value_get_enum (value);
418
419 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
420
421 if (new_format != props_cfg->format) {
422 props_cfg->format = new_format;
423 gst_raw_video_parse_update_info (props_cfg);
424
425 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse)) {
426 gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
427 gst_base_parse_set_min_frame_size (base_parse,
428 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
429 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
430 }
431 }
432
433 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
434 break;
435 }
436
437 case PROP_PIXEL_ASPECT_RATIO:
438 {
439 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
440
441 /* The pixel aspect ratio does not affect the video frame size,
442 * so it is just set directly without any updates */
443 props_cfg->pixel_aspect_ratio_n =
444 GST_VIDEO_INFO_PAR_N (&(props_cfg->info)) =
445 gst_value_get_fraction_numerator (value);
446 props_cfg->pixel_aspect_ratio_d =
447 GST_VIDEO_INFO_PAR_D (&(props_cfg->info)) =
448 gst_value_get_fraction_denominator (value);
449 GST_DEBUG_OBJECT (raw_video_parse, "setting pixel aspect ratio to %u/%u",
450 props_cfg->pixel_aspect_ratio_n, props_cfg->pixel_aspect_ratio_d);
451
452 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
453 break;
454 }
455
456 case PROP_FRAMERATE:
457 {
458 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
459
460 /* The framerate does not affect the video frame size,
461 * so it is just set directly without any updates */
462 props_cfg->framerate_n = GST_VIDEO_INFO_FPS_N (&(props_cfg->info)) =
463 gst_value_get_fraction_numerator (value);
464 props_cfg->framerate_d = GST_VIDEO_INFO_FPS_D (&(props_cfg->info)) =
465 gst_value_get_fraction_denominator (value);
466 GST_DEBUG_OBJECT (raw_video_parse, "setting framerate to %u/%u",
467 props_cfg->framerate_n, props_cfg->framerate_d);
468
469 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
470 break;
471 }
472
473 case PROP_INTERLACED:
474 {
475 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
476
477 /* Interlacing does not affect the video frame size,
478 * so it is just set directly without any updates */
479 props_cfg->interlaced = g_value_get_boolean (value);
480 GST_VIDEO_INFO_INTERLACE_MODE (&(props_cfg->info)) =
481 props_cfg->interlaced ? GST_VIDEO_INTERLACE_MODE_INTERLEAVED :
482 GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
483
484 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
485
486 break;
487 }
488
489 case PROP_TOP_FIELD_FIRST:
490 {
491 /* The top-field-first flag is a detail related to
492 * interlacing, so no video info update is needed */
493
494 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
495 props_cfg->top_field_first = g_value_get_boolean (value);
496 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
497 break;
498 }
499
500 case PROP_PLANE_STRIDES:
501 {
502 guint n_planes;
503 guint i;
504
505 /* If no array is given, then disable custom
506 * plane strides & offsets and stick to the
507 * standard computed ones */
508 if (gst_value_array_get_size (value) == 0) {
509 GST_DEBUG_OBJECT (raw_video_parse,
510 "custom plane strides & offsets disabled");
511 props_cfg->custom_plane_strides = FALSE;
512 gst_raw_video_parse_update_info (props_cfg);
513 break;
514 }
515
516 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
517
518 n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info));
519
520 /* Check that the array holds the right number of values */
521 if (gst_value_array_get_size (value) < n_planes) {
522 GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS,
523 ("incorrect number of elements in plane strides property"),
524 ("expected: %u, got: %u", n_planes,
525 gst_value_array_get_size (value)));
526 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
527 break;
528 }
529
530 /* Copy the values to the stride array */
531 for (i = 0; i < n_planes; ++i) {
532 const GValue *val = gst_value_array_get_value (value, i);
533 props_cfg->plane_strides[i] = g_value_get_int (val);
534 GST_DEBUG_OBJECT (raw_video_parse, "plane #%u stride: %d", i,
535 props_cfg->plane_strides[i]);
536 }
537
538 props_cfg->custom_plane_strides = TRUE;
539
540 gst_raw_video_parse_update_info (props_cfg);
541
542 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse))
543 gst_base_parse_set_min_frame_size (base_parse,
544 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
545 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
546
547 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
548 break;
549 }
550
551 case PROP_PLANE_OFFSETS:
552 {
553 guint n_planes;
554 guint i;
555
556 /* If no array is given, then disable custom
557 * plane strides & offsets and stick to the
558 * standard computed ones */
559 if (gst_value_array_get_size (value) == 0) {
560 GST_DEBUG_OBJECT (raw_video_parse,
561 "custom plane strides & offsets disabled");
562 props_cfg->custom_plane_strides = FALSE;
563 gst_raw_video_parse_update_info (props_cfg);
564 break;
565 }
566
567 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
568
569 n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info));
570
571 /* Check that the alarray holds the right number of values */
572 if (gst_value_array_get_size (value) < n_planes) {
573 GST_ELEMENT_ERROR (raw_video_parse, LIBRARY, SETTINGS,
574 ("incorrect number of elements in plane offsets property"),
575 ("expected: %u, got: %u", n_planes,
576 gst_value_array_get_size (value)));
577 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
578 break;
579 }
580
581 /* Copy the values to the offset array */
582 for (i = 0; i < n_planes; ++i) {
583 const GValue *val = gst_value_array_get_value (value, i);
584 props_cfg->plane_offsets[i] = g_value_get_int (val);
585 GST_DEBUG_OBJECT (raw_video_parse, "plane #%u offset: %" G_GSIZE_FORMAT,
586 i, props_cfg->plane_offsets[i]);
587 }
588
589 props_cfg->custom_plane_strides = TRUE;
590
591 gst_raw_video_parse_update_info (props_cfg);
592
593 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse))
594 gst_base_parse_set_min_frame_size (base_parse,
595 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
596 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
597
598 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
599 break;
600 }
601
602 case PROP_FRAME_SIZE:
603 {
604 /* The frame size is used to accumulate extra padding that may exist at
605 * the end of a frame. It does not affect GstVideoInfo::size, hence
606 * it is just set directly without any updates */
607
608 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
609 props_cfg->frame_size = g_value_get_uint (value);
610 gst_raw_video_parse_update_info (props_cfg);
611 if (!gst_raw_video_parse_is_using_sink_caps (raw_video_parse))
612 gst_base_parse_set_min_frame_size (base_parse,
613 gst_raw_video_parse_get_config_frame_size (raw_base_parse,
614 GST_RAW_BASE_PARSE_CONFIG_PROPERTIES));
615 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
616
617 break;
618 }
619
620 default:
621 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
622 break;
623 }
624 }
625
626 static void
gst_raw_video_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)627 gst_raw_video_parse_get_property (GObject * object, guint prop_id,
628 GValue * value, GParamSpec * pspec)
629 {
630 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (object);
631 GstRawVideoParseConfig *props_cfg = &(raw_video_parse->properties_config);
632
633 switch (prop_id) {
634 case PROP_WIDTH:
635 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
636 g_value_set_int (value, props_cfg->width);
637 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
638 break;
639
640 case PROP_HEIGHT:
641 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
642 g_value_set_int (value, props_cfg->height);
643 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
644 break;
645
646 case PROP_FORMAT:
647 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
648 g_value_set_enum (value, props_cfg->format);
649 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
650 break;
651
652 case PROP_PIXEL_ASPECT_RATIO:
653 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
654 gst_value_set_fraction (value, props_cfg->pixel_aspect_ratio_n,
655 props_cfg->pixel_aspect_ratio_d);
656 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
657
658 break;
659
660 case PROP_FRAMERATE:
661 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
662 gst_value_set_fraction (value, props_cfg->framerate_n,
663 props_cfg->framerate_d);
664 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
665 break;
666
667 case PROP_INTERLACED:
668 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
669 g_value_set_boolean (value, props_cfg->interlaced);
670 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
671 break;
672
673 case PROP_TOP_FIELD_FIRST:
674 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
675 g_value_set_boolean (value, props_cfg->top_field_first);
676 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
677 break;
678
679 case PROP_PLANE_STRIDES:
680 {
681 guint i, n_planes;
682 GValue val = G_VALUE_INIT;
683
684 g_value_reset (value);
685
686 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
687
688 n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info));
689 g_value_init (&val, G_TYPE_INT);
690
691 for (i = 0; i < n_planes; ++i) {
692 g_value_set_int (&val, props_cfg->plane_strides[i]);
693 gst_value_array_append_value (value, &val);
694 }
695
696 g_value_unset (&val);
697
698 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
699 break;
700 }
701
702 case PROP_PLANE_OFFSETS:
703 {
704 guint i, n_planes;
705 GValue val = G_VALUE_INIT;
706
707 g_value_reset (value);
708
709 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
710
711 n_planes = GST_VIDEO_INFO_N_PLANES (&(props_cfg->info));
712 g_value_init (&val, G_TYPE_INT);
713
714 for (i = 0; i < n_planes; ++i) {
715 g_value_set_int (&val, props_cfg->plane_offsets[i]);
716 gst_value_array_append_value (value, &val);
717 }
718
719 g_value_unset (&val);
720
721 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
722 break;
723 }
724
725 case PROP_FRAME_SIZE:
726 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
727 g_value_set_uint (value, raw_video_parse->properties_config.frame_size);
728 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
729 break;
730
731 default:
732 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
733 break;
734 }
735 }
736
737 static gboolean
gst_raw_video_parse_stop(GstBaseParse * parse)738 gst_raw_video_parse_stop (GstBaseParse * parse)
739 {
740 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (parse);
741
742 /* Sink caps config is not ready until caps come in.
743 * We are stopping processing, the element is being reset,
744 * so the config has to be un-readied.
745 * (Since the properties config is not depending on caps,
746 * its ready status is always TRUE.) */
747 raw_video_parse->sink_caps_config.ready = FALSE;
748
749 return GST_BASE_PARSE_CLASS (parent_class)->stop (parse);
750 }
751
752 static gboolean
gst_raw_video_parse_set_current_config(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)753 gst_raw_video_parse_set_current_config (GstRawBaseParse * raw_base_parse,
754 GstRawBaseParseConfig config)
755 {
756 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
757
758 switch (config) {
759 case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
760 raw_video_parse->current_config = &(raw_video_parse->properties_config);
761 break;
762
763 case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
764 raw_video_parse->current_config = &(raw_video_parse->sink_caps_config);
765 break;
766
767 default:
768 g_assert_not_reached ();
769 }
770
771 return TRUE;
772 }
773
774 static GstRawBaseParseConfig
gst_raw_video_parse_get_current_config(GstRawBaseParse * raw_base_parse)775 gst_raw_video_parse_get_current_config (GstRawBaseParse * raw_base_parse)
776 {
777 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
778 return gst_raw_video_parse_is_using_sink_caps (raw_video_parse) ?
779 GST_RAW_BASE_PARSE_CONFIG_SINKCAPS : GST_RAW_BASE_PARSE_CONFIG_PROPERTIES;
780 }
781
782 static gboolean
gst_raw_video_parse_set_config_from_caps(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstCaps * caps)783 gst_raw_video_parse_set_config_from_caps (GstRawBaseParse * raw_base_parse,
784 GstRawBaseParseConfig config, GstCaps * caps)
785 {
786 int i;
787 GstStructure *structure;
788 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
789 GstRawVideoParseConfig *config_ptr =
790 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
791
792 g_assert (caps != NULL);
793
794 /* Caps might get copied, and the copy needs to be unref'd.
795 * Also, the caller retains ownership over the original caps.
796 * So, to make this mechanism also work with cases where the
797 * caps are *not* copied, ref the original caps here first. */
798 gst_caps_ref (caps);
799
800 structure = gst_caps_get_structure (caps, 0);
801
802 /* For unaligned raw data, the output caps stay the same,
803 * except that video/x-unaligned-raw becomes video/x-raw,
804 * since the parser aligns the frame data */
805 if (gst_structure_has_name (structure, "video/x-unaligned-raw")) {
806 /* Copy the caps to be able to modify them */
807 GstCaps *new_caps = gst_caps_copy (caps);
808 gst_caps_unref (caps);
809 caps = new_caps;
810
811 /* Change the media type to video/x-raw , otherwise
812 * gst_video_info_from_caps() won't work */
813 structure = gst_caps_get_structure (caps, 0);
814 gst_structure_set_name (structure, "video/x-raw");
815 }
816
817 config_ptr->ready = gst_video_info_from_caps (&(config_ptr->info), caps);
818
819 if (config_ptr->ready) {
820 config_ptr->width = GST_VIDEO_INFO_WIDTH (&(config_ptr->info));
821 config_ptr->height = GST_VIDEO_INFO_HEIGHT (&(config_ptr->info));
822 config_ptr->pixel_aspect_ratio_n =
823 GST_VIDEO_INFO_PAR_N (&(config_ptr->info));
824 config_ptr->pixel_aspect_ratio_d =
825 GST_VIDEO_INFO_PAR_D (&(config_ptr->info));
826 config_ptr->framerate_n = GST_VIDEO_INFO_FPS_N (&(config_ptr->info));
827 config_ptr->framerate_d = GST_VIDEO_INFO_FPS_D (&(config_ptr->info));
828 config_ptr->interlaced = GST_VIDEO_INFO_IS_INTERLACED (&(config_ptr->info));
829 config_ptr->height = GST_VIDEO_INFO_HEIGHT (&(config_ptr->info));
830 config_ptr->top_field_first = 0;
831 config_ptr->frame_size = 0;
832
833 for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) {
834 config_ptr->plane_offsets[i] =
835 GST_VIDEO_INFO_PLANE_OFFSET (&(config_ptr->info), i);
836 config_ptr->plane_strides[i] =
837 GST_VIDEO_INFO_PLANE_STRIDE (&(config_ptr->info), i);
838 }
839 }
840
841 gst_caps_unref (caps);
842
843 return config_ptr->ready;
844 }
845
846 static gboolean
gst_raw_video_parse_get_caps_from_config(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstCaps ** caps)847 gst_raw_video_parse_get_caps_from_config (GstRawBaseParse * raw_base_parse,
848 GstRawBaseParseConfig config, GstCaps ** caps)
849 {
850 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
851 GstRawVideoParseConfig *config_ptr =
852 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
853
854 g_assert (caps != NULL);
855
856 *caps = gst_video_info_to_caps (&(config_ptr->info));
857
858 return *caps != NULL;
859 }
860
861 static gsize
gst_raw_video_parse_get_config_frame_size(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)862 gst_raw_video_parse_get_config_frame_size (GstRawBaseParse * raw_base_parse,
863 GstRawBaseParseConfig config)
864 {
865 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
866 GstRawVideoParseConfig *config_ptr =
867 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
868 return MAX (GST_VIDEO_INFO_SIZE (&(config_ptr->info)),
869 (gsize) (config_ptr->frame_size));
870 }
871
872 static guint
gst_raw_video_parse_get_max_frames_per_buffer(G_GNUC_UNUSED GstRawBaseParse * raw_base_parse,G_GNUC_UNUSED GstRawBaseParseConfig config)873 gst_raw_video_parse_get_max_frames_per_buffer (G_GNUC_UNUSED GstRawBaseParse *
874 raw_base_parse, G_GNUC_UNUSED GstRawBaseParseConfig config)
875 {
876 /* We want exactly one frame per buffer */
877 return 1;
878 }
879
880 static gboolean
gst_raw_video_parse_is_config_ready(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)881 gst_raw_video_parse_is_config_ready (GstRawBaseParse * raw_base_parse,
882 GstRawBaseParseConfig config)
883 {
884 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
885 return gst_raw_video_parse_get_config_ptr (raw_video_parse, config)->ready;
886 }
887
888 static gboolean
gst_raw_video_parse_process(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstBuffer * in_data,G_GNUC_UNUSED gsize total_num_in_bytes,G_GNUC_UNUSED gsize num_valid_in_bytes,GstBuffer ** processed_data)889 gst_raw_video_parse_process (GstRawBaseParse * raw_base_parse,
890 GstRawBaseParseConfig config, GstBuffer * in_data,
891 G_GNUC_UNUSED gsize total_num_in_bytes,
892 G_GNUC_UNUSED gsize num_valid_in_bytes, GstBuffer ** processed_data)
893 {
894 GstAllocationParams alloc_params = { 0, 31, 0, 0 };
895 GstMapInfo map_info;
896 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
897 GstRawVideoParseConfig *config_ptr =
898 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
899 guint frame_flags = 0;
900 GstVideoInfo *video_info = &(config_ptr->info);
901 GstBuffer *out_data;
902
903 if (!gst_buffer_map (in_data, &map_info, GST_MAP_READ)) {
904 GST_WARNING_OBJECT (raw_video_parse, "Failed to map input data");
905 return FALSE;
906 }
907
908 /* Allocate the output memory our required alignment */
909 *processed_data = out_data = gst_buffer_new_allocate (NULL,
910 GST_VIDEO_INFO_SIZE (video_info), &alloc_params);
911 gst_buffer_fill (*processed_data, 0, map_info.data,
912 GST_VIDEO_INFO_SIZE (video_info));
913 gst_buffer_unmap (in_data, &map_info);
914
915 /* And copy the metadata */
916 gst_buffer_copy_into (*processed_data, in_data,
917 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0,
918 GST_VIDEO_INFO_SIZE (video_info));
919
920 if (config_ptr->interlaced) {
921 GST_BUFFER_FLAG_SET (out_data, GST_VIDEO_BUFFER_FLAG_INTERLACED);
922 frame_flags |= GST_VIDEO_FRAME_FLAG_INTERLACED;
923
924 if (config_ptr->top_field_first) {
925 GST_BUFFER_FLAG_SET (out_data, GST_VIDEO_BUFFER_FLAG_TFF);
926 frame_flags |= GST_VIDEO_FRAME_FLAG_TFF;
927 } else
928 GST_BUFFER_FLAG_UNSET (out_data, GST_VIDEO_BUFFER_FLAG_TFF);
929 }
930
931 gst_buffer_add_video_meta_full (out_data,
932 frame_flags,
933 config_ptr->format,
934 config_ptr->width,
935 config_ptr->height,
936 GST_VIDEO_INFO_N_PLANES (video_info),
937 config_ptr->plane_offsets, config_ptr->plane_strides);
938
939
940 return TRUE;
941 }
942
943 static gboolean
gst_raw_video_parse_is_unit_format_supported(G_GNUC_UNUSED GstRawBaseParse * raw_base_parse,GstFormat format)944 gst_raw_video_parse_is_unit_format_supported (G_GNUC_UNUSED GstRawBaseParse *
945 raw_base_parse, GstFormat format)
946 {
947 switch (format) {
948 case GST_FORMAT_BYTES:
949 case GST_FORMAT_DEFAULT:
950 return TRUE;
951 default:
952 return FALSE;
953 }
954 }
955
956 static void
gst_raw_video_parse_get_units_per_second(GstRawBaseParse * raw_base_parse,GstFormat format,GstRawBaseParseConfig config,gsize * units_per_sec_n,gsize * units_per_sec_d)957 gst_raw_video_parse_get_units_per_second (GstRawBaseParse * raw_base_parse,
958 GstFormat format, GstRawBaseParseConfig config, gsize * units_per_sec_n,
959 gsize * units_per_sec_d)
960 {
961 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
962 GstRawVideoParseConfig *config_ptr =
963 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
964
965 switch (format) {
966 case GST_FORMAT_BYTES:
967 {
968 gsize framesize = GST_VIDEO_INFO_SIZE (&(config_ptr->info));
969 gint64 n = framesize * config_ptr->framerate_n;
970 gint64 d = config_ptr->framerate_d;
971 gint64 common_div = gst_util_greatest_common_divisor_int64 (n, d);
972 GST_DEBUG_OBJECT (raw_video_parse,
973 "n: %" G_GINT64_FORMAT " d: %" G_GINT64_FORMAT " common divisor: %"
974 G_GINT64_FORMAT, n, d, common_div);
975
976 /* Divide numerator and denominator by greatest common divisor.
977 * This minimizes the risk of integer overflows in the baseparse class. */
978 *units_per_sec_n = n / common_div;
979 *units_per_sec_d = d / common_div;
980
981 break;
982 }
983
984 case GST_FORMAT_DEFAULT:
985 {
986 *units_per_sec_n = config_ptr->framerate_n;
987 *units_per_sec_d = config_ptr->framerate_d;
988 break;
989 }
990
991 default:
992 g_assert_not_reached ();
993 }
994 }
995
996 static gint
gst_raw_video_parse_get_overhead_size(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)997 gst_raw_video_parse_get_overhead_size (GstRawBaseParse * raw_base_parse,
998 GstRawBaseParseConfig config)
999 {
1000 GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
1001 GstRawVideoParseConfig *config_ptr =
1002 gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
1003 gint64 info_size = GST_VIDEO_INFO_SIZE (&(config_ptr->info));
1004 gint64 frame_size = config_ptr->frame_size;
1005
1006 /* In the video parser, the overhead is defined by the difference between
1007 * the configured frame size and the GstVideoInfo size. If the former is
1008 * larger, then the additional bytes are considered padding bytes and get
1009 * ignored by the base class. */
1010
1011 GST_LOG_OBJECT (raw_video_parse,
1012 "info size: %" G_GINT64_FORMAT " frame size: %" G_GINT64_FORMAT,
1013 info_size, frame_size);
1014
1015 return (info_size < frame_size) ? (gint) (frame_size - info_size) : 0;
1016 }
1017
1018 static gboolean
gst_raw_video_parse_is_using_sink_caps(GstRawVideoParse * raw_video_parse)1019 gst_raw_video_parse_is_using_sink_caps (GstRawVideoParse * raw_video_parse)
1020 {
1021 return raw_video_parse->current_config ==
1022 &(raw_video_parse->sink_caps_config);
1023 }
1024
1025 static GstRawVideoParseConfig *
gst_raw_video_parse_get_config_ptr(GstRawVideoParse * raw_video_parse,GstRawBaseParseConfig config)1026 gst_raw_video_parse_get_config_ptr (GstRawVideoParse * raw_video_parse,
1027 GstRawBaseParseConfig config)
1028 {
1029 g_assert (raw_video_parse->current_config != NULL);
1030
1031 switch (config) {
1032 case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
1033 return &(raw_video_parse->properties_config);
1034
1035 case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
1036 return &(raw_video_parse->sink_caps_config);
1037
1038 default:
1039 g_assert (raw_video_parse->current_config != NULL);
1040 return raw_video_parse->current_config;
1041 }
1042 }
1043
1044 static void
gst_raw_video_parse_init_config(GstRawVideoParseConfig * config)1045 gst_raw_video_parse_init_config (GstRawVideoParseConfig * config)
1046 {
1047 int i;
1048
1049 config->ready = FALSE;
1050 config->width = DEFAULT_WIDTH;
1051 config->height = DEFAULT_HEIGHT;
1052 config->format = DEFAULT_FORMAT;
1053 config->pixel_aspect_ratio_n = DEFAULT_PIXEL_ASPECT_RATIO_N;
1054 config->pixel_aspect_ratio_d = DEFAULT_PIXEL_ASPECT_RATIO_D;
1055 config->framerate_n = DEFAULT_FRAMERATE_N;
1056 config->framerate_d = DEFAULT_FRAMERATE_D;
1057 config->interlaced = DEFAULT_INTERLACED;
1058
1059 config->top_field_first = DEFAULT_TOP_FIELD_FIRST;
1060 config->frame_size = DEFAULT_FRAME_STRIDE;
1061
1062 gst_video_info_set_format (&(config->info), DEFAULT_FORMAT, DEFAULT_WIDTH,
1063 DEFAULT_HEIGHT);
1064 for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) {
1065 config->plane_offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (&(config->info), i);
1066 config->plane_strides[i] = GST_VIDEO_INFO_PLANE_STRIDE (&(config->info), i);
1067 }
1068 }
1069
1070 static void
gst_raw_video_parse_update_info(GstRawVideoParseConfig * config)1071 gst_raw_video_parse_update_info (GstRawVideoParseConfig * config)
1072 {
1073 guint i;
1074 guint n_planes;
1075 guint last_plane;
1076 gsize last_plane_offset, last_plane_size;
1077 GstVideoInfo *info = &(config->info);
1078
1079 GST_DEBUG ("updating info with width %u height %u format %s "
1080 " custom plane strides&offsets %d", config->width, config->height,
1081 gst_video_format_to_string (config->format),
1082 config->custom_plane_strides);
1083
1084 gst_video_info_set_format (info, config->format, config->width,
1085 config->height);
1086
1087 GST_VIDEO_INFO_PAR_N (info) = config->pixel_aspect_ratio_n;
1088 GST_VIDEO_INFO_PAR_D (info) = config->pixel_aspect_ratio_d;
1089 GST_VIDEO_INFO_FPS_N (info) = config->framerate_n;
1090 GST_VIDEO_INFO_FPS_D (info) = config->framerate_d;
1091 GST_VIDEO_INFO_INTERLACE_MODE (info) =
1092 config->interlaced ? GST_VIDEO_INTERLACE_MODE_INTERLEAVED :
1093 GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
1094
1095 /* Check if there are custom plane strides & offsets that need to be preserved */
1096 if (config->custom_plane_strides) {
1097 /* In case there are, overwrite the offsets&strides computed by
1098 * gst_video_info_set_format with the custom ones */
1099 for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) {
1100 GST_VIDEO_INFO_PLANE_OFFSET (info, i) = config->plane_offsets[i];
1101 GST_VIDEO_INFO_PLANE_STRIDE (info, i) = config->plane_strides[i];
1102 }
1103 } else {
1104 /* No custom planes&offsets; copy the computed ones into
1105 * the plane_offsets & plane_strides arrays to ensure they
1106 * are equal to the ones in the videoinfo */
1107 for (i = 0; i < GST_VIDEO_MAX_PLANES; ++i) {
1108 config->plane_offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
1109 config->plane_strides[i] = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
1110 }
1111 }
1112
1113 n_planes = GST_VIDEO_INFO_N_PLANES (info);
1114 if (n_planes < 1)
1115 n_planes = 1;
1116
1117 /* Figure out what plane is the physically last one. Typically
1118 * this is the last plane in the list (= at index n_planes-1).
1119 * However, this is not guaranteed, so we have to scan the offsets
1120 * to find the last plane. */
1121 last_plane_offset = 0;
1122 last_plane = 0;
1123 for (i = 0; i < n_planes; ++i) {
1124 gsize plane_offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
1125 if (plane_offset >= last_plane_offset) {
1126 last_plane = i;
1127 last_plane_offset = plane_offset;
1128 }
1129 }
1130
1131 last_plane_size =
1132 GST_VIDEO_INFO_PLANE_STRIDE (info,
1133 last_plane) * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo,
1134 last_plane, config->height);
1135
1136 GST_VIDEO_INFO_SIZE (info) = last_plane_offset + last_plane_size;
1137
1138 GST_DEBUG ("last plane #%u: offset: %" G_GSIZE_FORMAT " size: %"
1139 G_GSIZE_FORMAT " => frame size minus extra padding: %" G_GSIZE_FORMAT,
1140 last_plane, last_plane_offset, last_plane_size,
1141 GST_VIDEO_INFO_SIZE (info));
1142 }
1143