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