• 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:gstrawbaseparse
22  * @short_description: Base class for raw media data parsers
23  *
24  * This base class is for parsers which read raw media data and output
25  * timestamped buffers with an integer number of frames inside.
26  *
27  * The format of the raw media data is specified in one of two ways: either,
28  * the information from the sink pad's caps is taken, or the information from
29  * the properties is used (this is chosen by the use-sink-caps property).
30  * These two ways are internally referred to as "configurations". The configuration
31  * that receives its information from the sink pad's caps is called the
32  * "sink caps configuration", while the one that depends on the information from
33  * the properties is the "properties configuration". Configurations have a
34  * "readiness". A configuration is "ready" when it contains valid information.
35  * For example, with an audio parser, a configuration is not ready unless it
36  * contains a valid sample rate, sample format, and channel count.
37  *
38  * The properties configuration must always be ready, even right from the start.
39  * Subclasses must ensure this. The underlying reason is that properties have valid
40  * values right from the start, and with the properties configuration, there is
41  * nothing that readies it before actual data is sent (unlike with the sink caps
42  * configuration, where a sink caps event will ready it before data is pushed
43  * downstream).
44  *
45  * It is possible to switch between the configurations during a stream by
46  * setting the use-sink-caps property. Subclasses typically allow for updating the
47  * properties configuration during a stream by setting the various properties
48  * (like sample-rate for a raw audio parser).
49  * In these cases, the parser will produce a new CAPS event and push it downstream
50  * to announce the caps for the new configuration. This also happens if the sink
51  * caps change.
52  *
53  * A common mistake when trying to parse raw data with no input caps (for example,
54  * a file with raw PCM samples when using rawaudioparse) is to forget to set the
55  * use-sink-caps property to FALSE. In this case, the parser will report an error
56  * when it tries to access the current configuration (because then the sink caps
57  * configuration will be the current one and it will not contain valid values
58  * since no sink caps were seen at this point).
59  *
60  * Subclasses must ensure that the properties configuration is the default one.
61  *
62  * The sink caps configuration is mostly useful with push-based sources, because these
63  * will produce caps events and send them downstream. With pull-based sources, it is
64  * possible that this doesn't happen. Since the sink caps configuration requires a caps
65  * event to arrive at the sinkpad, this will cause the parser to fail then.
66  *
67  * The base class identifies the configurations by means of the GstRawAudioParseConfig
68  * enum. It instructs the subclass to switch between configurations this way, and
69  * also requests information about the current configuration, a configuration's
70  * frame size, its readiness, etc. Subclasses are not required to use any particular
71  * structure for the configuration implementations.
72  *
73  * Use the GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK and GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK
74  * macros to protect configuration modifications.
75  *
76  * <listitem>
77  *   <itemizedlist>
78  *   <title>Summary of the subclass requirements</title>
79  *     <listitem><para>
80  *       Sink caps and properties configurations must both be
81  *       implemented and supported. It must also be ensured that there is a
82  *       "current" configuration.
83  *     </para></listitem>
84  *       Modifications to the configurations must be protected with the
85  *       GstRawBaseParse lock. This is typically necessary when the
86  *       properties configuration is modified by setting new property values.
87  *       (Note that the lock is held during *all* vfunc calls.)
88  *     <listitem><para>
89  *       If the properties configuration is updated (typically by
90  *       setting new property values), gst_raw_base_parse_invalidate_src_caps()
91  *       must be called if the properties config is the current one. This is
92  *       necessary to ensure that GstBaseParse pushes a new caps event downstream
93  *       which contains caps from the updated configuration.
94  *     </para></listitem>
95  *     <listitem><para>
96  *       In case there are bytes in each frame that aren't part of the actual
97  *       payload, the get_overhead_size() vfunc must be defined, and the
98  *       @get_config_frame_size() vfunc must return a frame size that includes
99  *       the number of non-payload bytes (= the overhead). Otherwise, the
100  *       timestamps will incorrectly include the overhead bytes.
101  *     </para></listitem>
102  * </listitem>
103  */
104 
105 #ifdef HAVE_CONFIG_H
106 #  include "config.h"
107 #endif
108 
109 #include <string.h>
110 #include "gstrawbaseparse.h"
111 
112 GST_DEBUG_CATEGORY_STATIC (raw_base_parse_debug);
113 #define GST_CAT_DEFAULT raw_base_parse_debug
114 
115 enum
116 {
117   PROP_0,
118   PROP_USE_SINK_CAPS
119 };
120 
121 #define DEFAULT_USE_SINK_CAPS  FALSE
122 #define INITIAL_PARSER_CONFIG \
123   ((DEFAULT_USE_SINK_CAPS) ? GST_RAW_BASE_PARSE_CONFIG_SINKCAPS : \
124    GST_RAW_BASE_PARSE_CONFIG_PROPERTIES)
125 
126 #define gst_raw_base_parse_parent_class parent_class
127 G_DEFINE_ABSTRACT_TYPE (GstRawBaseParse, gst_raw_base_parse,
128     GST_TYPE_BASE_PARSE);
129 
130 static void gst_raw_base_parse_finalize (GObject * object);
131 static void gst_raw_base_parse_set_property (GObject * object, guint prop_id,
132     GValue const *value, GParamSpec * pspec);
133 static void gst_raw_base_parse_get_property (GObject * object, guint prop_id,
134     GValue * value, GParamSpec * pspec);
135 static gboolean gst_raw_base_parse_start (GstBaseParse * parse);
136 static gboolean gst_raw_base_parse_stop (GstBaseParse * parse);
137 static gboolean gst_raw_base_parse_set_sink_caps (GstBaseParse * parse,
138     GstCaps * caps);
139 static GstFlowReturn gst_raw_base_parse_handle_frame (GstBaseParse * parse,
140     GstBaseParseFrame * frame, gint * skipsize);
141 static gboolean gst_raw_base_parse_convert (GstBaseParse * parse,
142     GstFormat src_format, gint64 src_value, GstFormat dest_format,
143     gint64 * dest_value);
144 
145 static gboolean gst_raw_base_parse_is_using_sink_caps (GstRawBaseParse *
146     raw_base_parse);
147 static gboolean gst_raw_base_parse_is_gstformat_supported (GstRawBaseParse *
148     raw_base_parse, GstFormat format);
149 
150 static void
gst_raw_base_parse_class_init(GstRawBaseParseClass * klass)151 gst_raw_base_parse_class_init (GstRawBaseParseClass * klass)
152 {
153   GObjectClass *object_class;
154   GstBaseParseClass *baseparse_class;
155 
156   GST_DEBUG_CATEGORY_INIT (raw_base_parse_debug, "rawbaseparse", 0,
157       "raw base parse class");
158 
159   object_class = G_OBJECT_CLASS (klass);
160   baseparse_class = GST_BASE_PARSE_CLASS (klass);
161 
162   object_class->finalize = GST_DEBUG_FUNCPTR (gst_raw_base_parse_finalize);
163   object_class->set_property =
164       GST_DEBUG_FUNCPTR (gst_raw_base_parse_set_property);
165   object_class->get_property =
166       GST_DEBUG_FUNCPTR (gst_raw_base_parse_get_property);
167 
168   baseparse_class->start = GST_DEBUG_FUNCPTR (gst_raw_base_parse_start);
169   baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_raw_base_parse_stop);
170   baseparse_class->set_sink_caps =
171       GST_DEBUG_FUNCPTR (gst_raw_base_parse_set_sink_caps);
172   baseparse_class->handle_frame =
173       GST_DEBUG_FUNCPTR (gst_raw_base_parse_handle_frame);
174   baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_raw_base_parse_convert);
175 
176   /**
177    * GstRawBaseParse::use-sink-caps:
178    *
179    * Use sink caps configuration. If set to false, the parser
180    * will use the properties configuration instead. It is possible
181    * to switch between these during playback.
182    */
183   g_object_class_install_property (object_class,
184       PROP_USE_SINK_CAPS,
185       g_param_spec_boolean ("use-sink-caps",
186           "Use sink caps",
187           "Use the sink caps for defining the output format",
188           DEFAULT_USE_SINK_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
189       );
190 }
191 
192 static void
gst_raw_base_parse_init(GstRawBaseParse * raw_base_parse)193 gst_raw_base_parse_init (GstRawBaseParse * raw_base_parse)
194 {
195   raw_base_parse->src_caps_set = FALSE;
196   g_mutex_init (&(raw_base_parse->config_mutex));
197 }
198 
199 static void
gst_raw_base_parse_finalize(GObject * object)200 gst_raw_base_parse_finalize (GObject * object)
201 {
202   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object);
203 
204   g_mutex_clear (&(raw_base_parse->config_mutex));
205 
206   G_OBJECT_CLASS (parent_class)->finalize (object);
207 }
208 
209 static void
gst_raw_base_parse_set_property(GObject * object,guint prop_id,GValue const * value,GParamSpec * pspec)210 gst_raw_base_parse_set_property (GObject * object, guint prop_id,
211     GValue const *value, GParamSpec * pspec)
212 {
213   GstBaseParse *base_parse = GST_BASE_PARSE (object);
214   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object);
215   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (object);
216 
217   g_assert (klass->is_config_ready);
218   g_assert (klass->set_current_config);
219 
220   switch (prop_id) {
221     case PROP_USE_SINK_CAPS:
222     {
223       gboolean new_state, cur_state;
224       GstRawBaseParseConfig new_config;
225 
226       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
227 
228       /* Check to ensure nothing is done if the value stays the same */
229       new_state = g_value_get_boolean (value);
230       cur_state = gst_raw_base_parse_is_using_sink_caps (raw_base_parse);
231       if (new_state == cur_state) {
232         GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
233         break;
234       }
235 
236       GST_DEBUG_OBJECT (raw_base_parse, "switching to %s config",
237           new_state ? "sink caps" : "properties");
238       new_config =
239           new_state ? GST_RAW_BASE_PARSE_CONFIG_SINKCAPS :
240           GST_RAW_BASE_PARSE_CONFIG_PROPERTIES;
241 
242       if (!klass->set_current_config (raw_base_parse, new_config)) {
243         GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
244         GST_ELEMENT_ERROR (raw_base_parse, STREAM, FAILED,
245             ("could not set new current config"), ("use-sink-caps property: %d",
246                 new_state));
247         break;
248       }
249 
250       /* Update the minimum frame size if the config is ready. This ensures that
251        * the next buffer that is passed to handle_frame contains complete frames.
252        * If the current config is the properties config, then it will always be
253        * ready, and its frame size will be valid. Ensure that the baseparse minimum
254        * frame size is set properly then.
255        * If the current config is the sink caps config, then it will initially not
256        * be ready until the sink caps are set, so the minimum frame size cannot be
257        * set right here. However, since the caps always come in *before* the actual
258        * data, the config will be readied in the set_sink_caps function, and be ready
259        * by the time handle_frame is called. There, the minimum frame size is set as
260        * well. */
261       if (klass->is_config_ready (raw_base_parse,
262               GST_RAW_BASE_PARSE_CONFIG_CURRENT)) {
263         gsize frame_size = klass->get_config_frame_size (raw_base_parse,
264             GST_RAW_BASE_PARSE_CONFIG_CURRENT);
265         gst_base_parse_set_min_frame_size (base_parse, frame_size);
266       }
267 
268       /* Since the current config was switched, the source caps change. Ensure the
269        * new caps are pushed downstream by setting src_caps_set to FALSE: This way,
270        * the next handle_frame call will take care of that. */
271       raw_base_parse->src_caps_set = FALSE;
272 
273       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
274 
275       break;
276     }
277 
278     default:
279       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
280       break;
281   }
282 }
283 
284 static void
gst_raw_base_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)285 gst_raw_base_parse_get_property (GObject * object, guint prop_id,
286     GValue * value, GParamSpec * pspec)
287 {
288   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object);
289 
290   switch (prop_id) {
291     case PROP_USE_SINK_CAPS:
292       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
293       g_value_set_boolean (value,
294           gst_raw_base_parse_is_using_sink_caps (raw_base_parse));
295       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
296       break;
297 
298     default:
299       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300       break;
301   }
302 }
303 
304 static gboolean
gst_raw_base_parse_start(GstBaseParse * parse)305 gst_raw_base_parse_start (GstBaseParse * parse)
306 {
307   GstBaseParse *base_parse = GST_BASE_PARSE (parse);
308   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
309   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse);
310 
311   g_assert (klass->set_current_config);
312 
313   GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse);
314 
315   /* If the config is ready from the start, set the min frame size
316    * (this will happen with the properties config) */
317   if (klass->is_config_ready (raw_base_parse,
318           GST_RAW_BASE_PARSE_CONFIG_CURRENT)) {
319     gsize frame_size = klass->get_config_frame_size (raw_base_parse,
320         GST_RAW_BASE_PARSE_CONFIG_CURRENT);
321     gst_base_parse_set_min_frame_size (base_parse, frame_size);
322   }
323 
324   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
325 
326   return TRUE;
327 }
328 
329 static gboolean
gst_raw_base_parse_stop(GstBaseParse * parse)330 gst_raw_base_parse_stop (GstBaseParse * parse)
331 {
332   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
333 
334   GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse);
335   raw_base_parse->src_caps_set = FALSE;
336   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
337 
338   return TRUE;
339 }
340 
341 static gboolean
gst_raw_base_parse_set_sink_caps(GstBaseParse * parse,GstCaps * caps)342 gst_raw_base_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
343 {
344   gboolean ret = FALSE;
345   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
346   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse);
347 
348   g_assert (klass->set_config_from_caps);
349   g_assert (klass->get_caps_from_config);
350   g_assert (klass->get_config_frame_size);
351 
352   GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse);
353 
354   GST_DEBUG_OBJECT (parse, "getting config from new sink caps");
355 
356   /* Convert the new sink caps to sink caps config. This also
357    * readies the config. */
358   ret =
359       klass->set_config_from_caps (raw_base_parse,
360       GST_RAW_BASE_PARSE_CONFIG_SINKCAPS, caps);
361   if (!ret) {
362     GST_ERROR_OBJECT (raw_base_parse, "could not get config from sink caps");
363     goto done;
364   }
365 
366   /* If the sink caps config is currently active, push caps downstream,
367    * set the minimum frame size (to guarantee that input buffers hold
368    * complete frames), and update the src_caps_set flag. If the sink
369    * caps config isn't the currently active config, just exit, since in
370    * that case, the caps will always be pushed downstream in handle_frame. */
371   if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) {
372     GstCaps *new_src_caps;
373     gsize frame_size;
374 
375     GST_DEBUG_OBJECT (parse,
376         "sink caps config is the current one; trying to push new caps downstream");
377 
378     /* Convert back to caps. The caps may have changed, for example
379      * audio/x-unaligned-raw may have been replaced with audio/x-raw.
380      * (Also, this keeps the behavior in sync with that of the block
381      * in handle_frame that pushes caps downstream if not done already.) */
382     if (!klass->get_caps_from_config (raw_base_parse,
383             GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) {
384       GST_ERROR_OBJECT (raw_base_parse,
385           "could not get src caps from current config");
386       goto done;
387     }
388 
389     GST_DEBUG_OBJECT (raw_base_parse,
390         "got new sink caps; updating src caps to %" GST_PTR_FORMAT,
391         (gpointer) new_src_caps);
392 
393     frame_size =
394         klass->get_config_frame_size (raw_base_parse,
395         GST_RAW_BASE_PARSE_CONFIG_CURRENT);
396     gst_base_parse_set_min_frame_size (parse, frame_size);
397 
398     raw_base_parse->src_caps_set = TRUE;
399 
400     GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
401 
402     /* Push caps outside of the lock */
403     gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse),
404         gst_event_new_caps (new_src_caps)
405         );
406 
407     gst_caps_unref (new_src_caps);
408   } else {
409     GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
410   }
411 
412   ret = TRUE;
413 
414 done:
415   return ret;
416 }
417 
418 static GstBuffer *
gst_raw_base_parse_align_buffer(GstRawBaseParse * raw_base_parse,gsize alignment,GstBuffer * buffer,gsize out_size)419 gst_raw_base_parse_align_buffer (GstRawBaseParse * raw_base_parse,
420     gsize alignment, GstBuffer * buffer, gsize out_size)
421 {
422   GstMapInfo map;
423 
424   gst_buffer_map (buffer, &map, GST_MAP_READ);
425 
426   if (map.size < sizeof (guintptr)) {
427     gst_buffer_unmap (buffer, &map);
428     return NULL;
429   }
430 
431   if (((guintptr) map.data) & (alignment - 1)) {
432     GstBuffer *new_buffer;
433     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
434 
435     new_buffer = gst_buffer_new_allocate (NULL, out_size, &params);
436 
437     /* Copy data "by hand", so ensure alignment is kept: */
438     gst_buffer_fill (new_buffer, 0, map.data, out_size);
439 
440     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0,
441         out_size);
442     GST_DEBUG_OBJECT (raw_base_parse,
443         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
444         alignment);
445 
446     gst_buffer_unmap (buffer, &map);
447 
448     return new_buffer;
449   }
450 
451   gst_buffer_unmap (buffer, &map);
452 
453   return NULL;
454 }
455 
456 static GstFlowReturn
gst_raw_base_parse_handle_frame(GstBaseParse * parse,GstBaseParseFrame * frame,gint * skipsize)457 gst_raw_base_parse_handle_frame (GstBaseParse * parse,
458     GstBaseParseFrame * frame, gint * skipsize)
459 {
460   gsize in_size, out_size;
461   guint frame_size;
462   guint num_out_frames;
463   gsize units_n, units_d;
464   guint64 buffer_duration;
465   GstFlowReturn flow_ret = GST_FLOW_OK;
466   GstEvent *new_caps_event = NULL;
467   gint alignment;
468   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
469   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse);
470 
471   g_assert (klass->is_config_ready);
472   g_assert (klass->get_caps_from_config);
473   g_assert (klass->get_config_frame_size);
474   g_assert (klass->get_units_per_second);
475 
476   /* We never skip any bytes this way. Instead, subclass takes care
477    * of skipping any overhead (necessary, since the way it needs to
478    * be skipped is completely subclass specific). */
479   *skipsize = 0;
480 
481   /* The operations below access the current config. Protect
482    * against race conditions by using the object lock. */
483   GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse);
484 
485   /* If the source pad caps haven't been set yet, or need to be
486    * set again, do so now, BEFORE any buffers are pushed out */
487   if (G_UNLIKELY (!raw_base_parse->src_caps_set)) {
488     GstCaps *new_src_caps;
489 
490     if (G_UNLIKELY (!klass->is_config_ready (raw_base_parse,
491                 GST_RAW_BASE_PARSE_CONFIG_CURRENT))) {
492       /* The current configuration is not ready. No caps can be
493        * generated out of it.
494        * The most likely reason for this is that the sink caps config
495        * is the current one and no valid sink caps have been pushed
496        * by upstream. Report the problem and exit. */
497 
498       if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) {
499         goto config_not_ready;
500       } else {
501         /* This should not be reached if the property config is active */
502         g_assert_not_reached ();
503       }
504     }
505 
506     GST_DEBUG_OBJECT (parse,
507         "setting src caps since this has not been done yet");
508 
509     /* Convert the current config to a caps structure to
510      * inform downstream about the new format */
511     if (!klass->get_caps_from_config (raw_base_parse,
512             GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) {
513       GST_ERROR_OBJECT (raw_base_parse,
514           "could not get src caps from current config");
515       flow_ret = GST_FLOW_NOT_NEGOTIATED;
516       goto error_locked;
517     }
518 
519     new_caps_event = gst_event_new_caps (new_src_caps);
520     gst_caps_unref (new_src_caps);
521 
522     raw_base_parse->src_caps_set = TRUE;
523   }
524 
525   frame_size =
526       klass->get_config_frame_size (raw_base_parse,
527       GST_RAW_BASE_PARSE_CONFIG_CURRENT);
528   if (frame_size <= 0) {
529     GST_ELEMENT_ERROR (parse, STREAM, FORMAT,
530         ("Non strictly positive frame size"), (NULL));
531     flow_ret = GST_FLOW_ERROR;
532     goto error_locked;
533   }
534 
535   in_size = gst_buffer_get_size (frame->buffer);
536 
537   /* drop incomplete frame at the end of the stream
538    * https://bugzilla.gnome.org/show_bug.cgi?id=773666
539    */
540   if (GST_BASE_PARSE_DRAINING (parse) && in_size < frame_size) {
541     GST_DEBUG_OBJECT (raw_base_parse,
542         "Dropping %" G_GSIZE_FORMAT " bytes at EOS", in_size);
543     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
544     GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
545 
546     return gst_base_parse_finish_frame (parse, frame, in_size);
547   }
548 
549   /* gst_base_parse_set_min_frame_size() is called when the current
550    * configuration changes and the change affects the frame size. This
551    * means that a buffer must contain at least as many bytes as indicated
552    * by the frame size. If there are fewer inside an error occurred;
553    * either something in the parser went wrong, or the min frame size
554    * wasn't updated properly. */
555   g_assert (in_size >= frame_size);
556 
557   /* Determine how many complete frames would fit in the input buffer.
558    * Then check if this amount exceeds the maximum number of frames
559    * as indicated by the subclass. */
560   num_out_frames = (in_size / frame_size);
561   if (klass->get_max_frames_per_buffer) {
562     guint max_num_out_frames = klass->get_max_frames_per_buffer (raw_base_parse,
563         GST_RAW_BASE_PARSE_CONFIG_CURRENT);
564     num_out_frames = MIN (num_out_frames, max_num_out_frames);
565   }
566 
567   /* Ensure that the size of the buffers that get pushed downstream
568    * is always an integer multiple of the frame size to prevent cases
569    * where downstream gets buffers with incomplete frames. */
570   out_size = num_out_frames * frame_size;
571 
572   /* Set the overhead size to ensure that timestamping excludes these
573    * extra overhead bytes. */
574   frame->overhead =
575       klass->get_overhead_size ? klass->get_overhead_size (raw_base_parse,
576       GST_RAW_BASE_PARSE_CONFIG_CURRENT) : 0;
577 
578   g_assert (out_size >= (guint) (frame->overhead));
579   out_size -= frame->overhead;
580 
581   GST_LOG_OBJECT (raw_base_parse,
582       "%" G_GSIZE_FORMAT " bytes input  %" G_GSIZE_FORMAT
583       " bytes output (%u frame(s))  %d bytes overhead", in_size, out_size,
584       num_out_frames, frame->overhead);
585 
586   /* Calculate buffer duration */
587   klass->get_units_per_second (raw_base_parse, GST_FORMAT_BYTES,
588       GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d);
589   if (units_n == 0 || units_d == 0)
590     buffer_duration = GST_CLOCK_TIME_NONE;
591   else
592     buffer_duration =
593         gst_util_uint64_scale (out_size, GST_SECOND * units_d, units_n);
594 
595   if (klass->process) {
596     GstBuffer *processed_data = NULL;
597 
598     if (!klass->process (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT,
599             frame->buffer, in_size, out_size, &processed_data))
600       goto process_error;
601 
602     frame->out_buffer = processed_data;
603   } else {
604     frame->out_buffer = NULL;
605   }
606 
607   if (klass->get_alignment
608       && (alignment =
609           klass->get_alignment (raw_base_parse,
610               GST_RAW_BASE_PARSE_CONFIG_CURRENT)) != 1) {
611     GstBuffer *aligned_buffer;
612 
613     aligned_buffer =
614         gst_raw_base_parse_align_buffer (raw_base_parse, alignment,
615         frame->out_buffer ? frame->out_buffer : frame->buffer, out_size);
616 
617     if (aligned_buffer) {
618       if (frame->out_buffer)
619         gst_buffer_unref (frame->out_buffer);
620       frame->out_buffer = aligned_buffer;
621     }
622   }
623 
624   /* Set the duration of the output buffer, or if none exists, of
625    * the input buffer. Do this after the process() call, since in
626    * case out_buffer is set, the subclass has created a new buffer.
627    * Instead of requiring subclasses to set the duration (which
628    * anyway must always be buffer_duration), let's do it here. */
629   if (frame->out_buffer != NULL)
630     GST_BUFFER_DURATION (frame->out_buffer) = buffer_duration;
631   else
632     GST_BUFFER_DURATION (frame->buffer) = buffer_duration;
633 
634   /* Access to the current config is not needed in subsequent
635    * operations, so the lock can be released */
636   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
637 
638   /* If any new caps have to be pushed downstrean, do so
639    * *before* the frame is finished */
640   if (G_UNLIKELY (new_caps_event != NULL)) {
641     gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse),
642         new_caps_event);
643     new_caps_event = NULL;
644   }
645 
646   flow_ret =
647       gst_base_parse_finish_frame (parse, frame, out_size + frame->overhead);
648 
649   return flow_ret;
650 
651 config_not_ready:
652   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
653   GST_ELEMENT_ERROR (parse, STREAM, FORMAT,
654       ("sink caps config is the current config, and it is not ready -"
655           "upstream may not have pushed a caps event yet"), (NULL));
656   flow_ret = GST_FLOW_ERROR;
657   goto error_end;
658 
659 process_error:
660   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
661   GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("could not process data"), (NULL));
662   flow_ret = GST_FLOW_ERROR;
663   goto error_end;
664 
665 error_locked:
666   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
667   goto error_end;
668 
669 error_end:
670   frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
671   if (new_caps_event != NULL)
672     gst_event_unref (new_caps_event);
673   return flow_ret;
674 }
675 
676 static gboolean
gst_raw_base_parse_convert(GstBaseParse * parse,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)677 gst_raw_base_parse_convert (GstBaseParse * parse, GstFormat src_format,
678     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
679 {
680   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse);
681   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse);
682   gboolean ret = TRUE;
683   gsize units_n, units_d;
684 
685   g_assert (klass->is_config_ready);
686   g_assert (klass->get_units_per_second);
687 
688   /* The operations below access the current config. Protect
689    * against race conditions by using the object lock. */
690   GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse);
691 
692   if (!klass->is_config_ready (raw_base_parse,
693           GST_RAW_BASE_PARSE_CONFIG_CURRENT)) {
694     if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) {
695       goto config_not_ready;
696     } else {
697       /* This should not be reached if the property config is active */
698       g_assert_not_reached ();
699     }
700   }
701 
702   if (G_UNLIKELY (src_format == dest_format)) {
703     *dest_value = src_value;
704   } else if ((src_format == GST_FORMAT_TIME || dest_format == GST_FORMAT_TIME)
705       && gst_raw_base_parse_is_gstformat_supported (raw_base_parse, src_format)
706       && gst_raw_base_parse_is_gstformat_supported (raw_base_parse, src_format)) {
707     /* Perform conversions here if either the src or dest format
708      * are GST_FORMAT_TIME and the other format is supported by
709      * the subclass. This is because we perform TIME<->non-TIME
710      * conversions here. Typically, subclasses only support
711      * BYTES and DEFAULT formats. */
712 
713     if (src_format == GST_FORMAT_TIME) {
714       /* The source format is time, so perform a TIME -> non-TIME conversion */
715       klass->get_units_per_second (raw_base_parse, dest_format,
716           GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d);
717       *dest_value = (units_n == 0
718           || units_d == 0) ? src_value : gst_util_uint64_scale (src_value,
719           units_n, GST_SECOND * units_d);
720     } else {
721       /* The dest format is time, so perform a non-TIME -> TIME conversion */
722       klass->get_units_per_second (raw_base_parse, src_format,
723           GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d);
724       *dest_value = (units_n == 0
725           || units_d == 0) ? src_value : gst_util_uint64_scale (src_value,
726           GST_SECOND * units_d, units_n);
727     }
728   } else {
729     /* Fallback for other conversions */
730     ret =
731         gst_base_parse_convert_default (parse, src_format, src_value,
732         dest_format, dest_value);
733   }
734 
735   GST_DEBUG_OBJECT (parse,
736       "converted %s -> %s  %" G_GINT64_FORMAT " -> %" GST_TIME_FORMAT,
737       gst_format_get_name (src_format), gst_format_get_name (dest_format),
738       src_value, GST_TIME_ARGS (*dest_value));
739 
740   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
741   return ret;
742 
743 config_not_ready:
744   GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse);
745   GST_ELEMENT_ERROR (parse, STREAM, FORMAT,
746       ("sink caps config is the current config, and it is not ready - "
747           "upstream may not have pushed a caps event yet"), (NULL));
748   return FALSE;
749 }
750 
751 static gboolean
gst_raw_base_parse_is_using_sink_caps(GstRawBaseParse * raw_base_parse)752 gst_raw_base_parse_is_using_sink_caps (GstRawBaseParse * raw_base_parse)
753 {
754   /* must be called with lock */
755   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (raw_base_parse);
756   g_assert (klass->get_current_config);
757   return klass->get_current_config (raw_base_parse) ==
758       GST_RAW_BASE_PARSE_CONFIG_SINKCAPS;
759 }
760 
761 static gboolean
gst_raw_base_parse_is_gstformat_supported(GstRawBaseParse * raw_base_parse,GstFormat format)762 gst_raw_base_parse_is_gstformat_supported (GstRawBaseParse * raw_base_parse,
763     GstFormat format)
764 {
765   /* must be called with lock */
766   GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (raw_base_parse);
767   g_assert (klass->is_unit_format_supported);
768   return klass->is_unit_format_supported (raw_base_parse, format);
769 }
770 
771 /**
772  * gst_raw_base_parse_invalidate_src_caps:
773  * @raw_base_parse: a #GstRawBaseParse instance
774  *
775  * Flags the current source caps as invalid. Before the next downstream
776  * buffer push, @get_caps_from_config is called, and the created caps are
777  * pushed downstream in a new caps event, This is used if for example the
778  * properties configuration is modified in the subclass.
779  *
780  * Note that this must be called with the parser lock held. Use the
781  * GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK() and GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK()
782  * macros for this purpose.
783  */
784 void
gst_raw_base_parse_invalidate_src_caps(GstRawBaseParse * raw_base_parse)785 gst_raw_base_parse_invalidate_src_caps (GstRawBaseParse * raw_base_parse)
786 {
787   /* must be called with lock */
788   g_assert (raw_base_parse != NULL);
789   raw_base_parse->src_caps_set = FALSE;
790 }
791