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