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, ¶ms);
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