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