• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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