2 * Copyright (C) 2008 Nokia Corporation. All rights reserved.
3 * Contact: Stefan Kost <stefan.kost@nokia.com>
4 * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:gstbaseparse
24 * @short_description: Base class for stream parsers
25 * @see_also: #GstBaseTransform
27 * This base class is for parser elements that process data and splits it
28 * into separate audio/video/whatever frames.
32 * <listitem><para>One sinkpad and one srcpad</para></listitem>
33 * <listitem><para>Handles state changes</para></listitem>
34 * <listitem><para>Does flushing</para></listitem>
35 * <listitem><para>Push mode</para></listitem>
36 * <listitem><para>Pull mode</para></listitem>
37 * <listitem><para>Handles events (NEWSEGMENT/EOS/FLUSH)</para></listitem>
38 * <listitem><para>Handles seeking in both modes</para></listitem>
40 * Handles POSITION/DURATION/SEEKING/FORMAT/CONVERT queries
44 * The purpose of this base class is to provide a basic functionality of
45 * a parser and share a lot of rather complex code.
47 * Description of the parsing mechanism:
50 * <itemizedlist><title>Set-up phase</title>
52 * GstBaseParse class calls @set_sink_caps to inform the subclass about
53 * incoming sinkpad caps. Subclass should set the srcpad caps accordingly.
56 * GstBaseParse calls @start to inform subclass that data processing is
60 * At least in this point subclass needs to tell the GstBaseParse class
61 * how big data chunks it wants to receive (min_frame_size). It can do
62 * this with @gst_base_parse_set_min_frame_size.
65 * GstBaseParse class sets up appropriate data passing mode (pull/push)
66 * and starts to process the data.
72 * <title>Parsing phase</title>
74 * GstBaseParse gathers at least min_frame_size bytes of data either
75 * by pulling it from upstream or collecting buffers into internal
79 * A buffer of min_frame_size bytes is passed to subclass with
80 * @check_valid_frame. Subclass checks the contents and returns TRUE
81 * if the buffer contains a valid frame. It also needs to set the
82 * @framesize according to the detected frame size. If buffer didn't
83 * contain a valid frame, this call must return FALSE and optionally
84 * set the @skipsize value to inform base class that how many bytes
85 * it needs to skip in order to find a valid frame. The passed buffer
86 * is read-only. Note that @check_valid_frame might receive any small
87 * amount of input data when leftover data is being drained (e.g. at EOS).
90 * After valid frame is found, it will be passed again to subclass with
91 * @parse_frame call. Now subclass is responsible for parsing the
92 * frame contents and setting the buffer timestamp, duration and caps.
95 * Finally the buffer can be pushed downstream and parsing loop starts
99 * During the parsing process GstBaseParseClass will handle both srcpad and
100 * sinkpad events. They will be passed to subclass if @event or
101 * @src_event callbacks have been provided.
106 * <itemizedlist><title>Shutdown phase</title>
108 * GstBaseParse class calls @stop to inform the subclass that data
109 * parsing will be stopped.
115 * Subclass is responsible for providing pad template caps for
116 * source and sink pads. The pads need to be named "sink" and "src". It also
117 * needs to set the fixed caps on srcpad, when the format is ensured (e.g.
118 * when base class calls subclass' @set_sink_caps function).
120 * This base class uses GST_FORMAT_DEFAULT as a meaning of frames. So,
121 * subclass conversion routine needs to know that conversion from
122 * GST_FORMAT_TIME to GST_FORMAT_DEFAULT must return the
123 * frame number that can be found from the given byte position.
125 * GstBaseParse uses subclasses conversion methods also for seeking. If
126 * subclass doesn't provide @convert function, seeking will get disabled.
128 * Subclass @start and @stop functions will be called to inform the beginning
129 * and end of data processing.
131 * Things that subclass need to take care of:
133 * <listitem><para>Provide pad templates</para></listitem>
135 * Fixate the source pad caps when appropriate
138 * Inform base class how big data chunks should be retrieved. This is
139 * done with @gst_base_parse_set_min_frame_size function.
142 * Examine data chunks passed to subclass with @check_valid_frame
143 * and tell if they contain a valid frame
146 * Set the caps and timestamp to frame that is passed to subclass with
147 * @parse_frame function.
149 * <listitem><para>Provide conversion functions</para></listitem>
151 * Update the duration information with @gst_base_parse_set_duration
154 * Alternatively, parsing (or specs) might yield a frames per seconds rate
155 * which can be provided to GstBaseParse to enable it to cater for
156 * buffer time metadata (which will be taken from upstream as much as possible).
157 * Internally keeping track of frames and respective
158 * sizes that have been pushed provides GstBaseParse with a bytes per frame
159 * rate. A default @convert (used if not overriden) will then use these
160 * rates to perform obvious conversions. These rates are also used to update
161 * (estimated) duration at regular frame intervals.
162 * If no (fixed) frames per second rate applies, default conversion will be
163 * based on (estimated) bytes per second (but no default buffer metadata
164 * can be provided in this case).
171 * - Better segment handling:
172 * - NEWSEGMENT for gaps
173 * - Not NEWSEGMENT starting at 0 but at first frame timestamp
175 * - Seek table generation and subclass seek entry injection
177 * - In push mode provide a queue of adapter-"queued" buffers for upstream
179 * - Queue buffers/events until caps are set
180 * - Let subclass decide if frames outside the segment should be dropped
181 * - Send queries upstream
191 #include "gstbaseparse.h"
193 GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug);
194 #define GST_CAT_DEFAULT gst_base_parse_debug
196 /* Supported formats */
197 static GstFormat fmtlist[] = {
204 #define GST_BASE_PARSE_GET_PRIVATE(obj) \
205 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_PARSE, GstBaseParsePrivate))
207 struct _GstBaseParsePrivate
209 GstActivateMode pad_mode;
212 GstFormat duration_fmt;
213 gint64 estimated_duration;
215 guint min_frame_size;
216 gboolean passthrough;
217 guint fps_num, fps_den;
218 guint update_interval;
225 GstClockTime next_ts;
226 GstClockTime prev_ts;
227 GstClockTime frame_duration;
231 guint64 acc_duration;
233 GList *pending_events;
238 struct _GstBaseParseClassPrivate
243 static GstElementClass *parent_class = NULL;
245 static void gst_base_parse_base_init (gpointer g_class);
246 static void gst_base_parse_base_finalize (gpointer g_class);
247 static void gst_base_parse_class_init (GstBaseParseClass * klass);
248 static void gst_base_parse_init (GstBaseParse * parse,
249 GstBaseParseClass * klass);
252 gst_base_parse_get_type (void)
254 static GType base_parse_type = 0;
256 if (!base_parse_type) {
257 static const GTypeInfo base_parse_info = {
258 sizeof (GstBaseParseClass),
259 (GBaseInitFunc) gst_base_parse_base_init,
260 (GBaseFinalizeFunc) gst_base_parse_base_finalize,
261 (GClassInitFunc) gst_base_parse_class_init,
264 sizeof (GstBaseParse),
266 (GInstanceInitFunc) gst_base_parse_init,
269 base_parse_type = g_type_register_static (GST_TYPE_ELEMENT,
270 "GstBaseParse", &base_parse_info, G_TYPE_FLAG_ABSTRACT);
272 return base_parse_type;
275 static void gst_base_parse_finalize (GObject * object);
277 static gboolean gst_base_parse_sink_activate (GstPad * sinkpad);
278 static gboolean gst_base_parse_sink_activate_push (GstPad * pad,
280 static gboolean gst_base_parse_sink_activate_pull (GstPad * pad,
282 static gboolean gst_base_parse_handle_seek (GstBaseParse * parse,
285 static gboolean gst_base_parse_src_event (GstPad * pad, GstEvent * event);
286 static gboolean gst_base_parse_sink_event (GstPad * pad, GstEvent * event);
287 static gboolean gst_base_parse_query (GstPad * pad, GstQuery * query);
288 static gboolean gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps);
289 static const GstQueryType *gst_base_parse_get_querytypes (GstPad * pad);
291 static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer);
292 static void gst_base_parse_loop (GstPad * pad);
294 static gboolean gst_base_parse_check_frame (GstBaseParse * parse,
295 GstBuffer * buffer, guint * framesize, gint * skipsize);
297 static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse,
300 static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse,
303 static gboolean gst_base_parse_src_eventfunc (GstBaseParse * parse,
306 static gboolean gst_base_parse_is_seekable (GstBaseParse * parse);
308 gboolean gst_base_parse_convert (GstBaseParse * parse, GstFormat src_format,
309 gint64 src_value, GstFormat dest_format, gint64 * dest_value);
311 static void gst_base_parse_drain (GstBaseParse * parse);
314 gst_base_parse_base_init (gpointer g_class)
316 GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
317 GstBaseParseClassPrivate *priv;
319 GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "baseparse", 0,
320 "baseparse element");
322 /* TODO: Remove this once GObject supports class private data */
323 priv = g_slice_new0 (GstBaseParseClassPrivate);
325 memcpy (priv, klass->priv, sizeof (GstBaseParseClassPrivate));
330 gst_base_parse_base_finalize (gpointer g_class)
332 GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
334 g_slice_free (GstBaseParseClassPrivate, klass->priv);
339 gst_base_parse_finalize (GObject * object)
341 GstBaseParse *parse = GST_BASE_PARSE (object);
344 g_mutex_free (parse->parse_lock);
345 g_object_unref (parse->adapter);
347 if (parse->pending_segment) {
348 p_ev = &parse->pending_segment;
349 gst_event_replace (p_ev, NULL);
351 if (parse->close_segment) {
352 p_ev = &parse->close_segment;
353 gst_event_replace (p_ev, NULL);
356 if (parse->priv->cache) {
357 gst_buffer_unref (parse->priv->cache);
358 parse->priv->cache = NULL;
361 g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
363 g_list_free (parse->priv->pending_events);
364 parse->priv->pending_events = NULL;
366 G_OBJECT_CLASS (parent_class)->finalize (object);
370 gst_base_parse_class_init (GstBaseParseClass * klass)
372 GObjectClass *gobject_class;
374 gobject_class = G_OBJECT_CLASS (klass);
375 g_type_class_add_private (klass, sizeof (GstBaseParsePrivate));
376 parent_class = g_type_class_peek_parent (klass);
377 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_parse_finalize);
379 /* Default handlers */
380 klass->check_valid_frame = gst_base_parse_check_frame;
381 klass->parse_frame = gst_base_parse_parse_frame;
382 klass->event = gst_base_parse_sink_eventfunc;
383 klass->src_event = gst_base_parse_src_eventfunc;
384 klass->is_seekable = gst_base_parse_is_seekable;
385 klass->convert = gst_base_parse_convert;
389 gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
391 GstPadTemplate *pad_template;
393 GST_DEBUG_OBJECT (parse, "gst_base_parse_init");
395 parse->priv = GST_BASE_PARSE_GET_PRIVATE (parse);
398 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
399 g_return_if_fail (pad_template != NULL);
400 parse->sinkpad = gst_pad_new_from_template (pad_template, "sink");
401 gst_pad_set_event_function (parse->sinkpad,
402 GST_DEBUG_FUNCPTR (gst_base_parse_sink_event));
403 gst_pad_set_setcaps_function (parse->sinkpad,
404 GST_DEBUG_FUNCPTR (gst_base_parse_sink_setcaps));
405 gst_pad_set_chain_function (parse->sinkpad,
406 GST_DEBUG_FUNCPTR (gst_base_parse_chain));
407 gst_pad_set_activate_function (parse->sinkpad,
408 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate));
409 gst_pad_set_activatepush_function (parse->sinkpad,
410 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_push));
411 gst_pad_set_activatepull_function (parse->sinkpad,
412 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_pull));
413 gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
415 GST_DEBUG_OBJECT (parse, "sinkpad created");
418 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
419 g_return_if_fail (pad_template != NULL);
420 parse->srcpad = gst_pad_new_from_template (pad_template, "src");
421 gst_pad_set_event_function (parse->srcpad,
422 GST_DEBUG_FUNCPTR (gst_base_parse_src_event));
423 gst_pad_set_query_type_function (parse->srcpad,
424 GST_DEBUG_FUNCPTR (gst_base_parse_get_querytypes));
425 gst_pad_set_query_function (parse->srcpad,
426 GST_DEBUG_FUNCPTR (gst_base_parse_query));
427 gst_pad_use_fixed_caps (parse->srcpad);
428 gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
429 GST_DEBUG_OBJECT (parse, "src created");
431 parse->parse_lock = g_mutex_new ();
432 parse->adapter = gst_adapter_new ();
433 parse->pending_segment = NULL;
434 parse->close_segment = NULL;
436 parse->priv->pad_mode = GST_ACTIVATE_NONE;
437 parse->priv->duration = -1;
438 parse->priv->min_frame_size = 1;
439 parse->priv->passthrough = FALSE;
440 parse->priv->discont = FALSE;
441 parse->priv->flushing = FALSE;
442 parse->priv->offset = 0;
443 GST_DEBUG_OBJECT (parse, "init ok");
449 * gst_base_parse_check_frame:
450 * @parse: #GstBaseParse.
451 * @buffer: GstBuffer.
452 * @framesize: This will be set to tell the found frame size in bytes.
453 * @skipsize: Output parameter that tells how much data needs to be skipped
454 * in order to find the following frame header.
456 * Default callback for check_valid_frame.
458 * Returns: Always TRUE.
461 gst_base_parse_check_frame (GstBaseParse * parse,
462 GstBuffer * buffer, guint * framesize, gint * skipsize)
464 *framesize = GST_BUFFER_SIZE (buffer);
471 * gst_base_parse_parse_frame:
472 * @parse: #GstBaseParse.
473 * @buffer: #GstBuffer.
475 * Default callback for parse_frame.
478 gst_base_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
480 if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
481 GST_CLOCK_TIME_IS_VALID (parse->priv->next_ts)) {
482 GST_BUFFER_TIMESTAMP (buffer) = parse->priv->next_ts;
484 if (!GST_BUFFER_DURATION_IS_VALID (buffer) &&
485 GST_CLOCK_TIME_IS_VALID (parse->priv->frame_duration)) {
486 GST_BUFFER_DURATION (buffer) = parse->priv->frame_duration;
493 * gst_base_parse_bytepos_to_time:
494 * @parse: #GstBaseParse.
495 * @bytepos: Position (in bytes) to be converted.
496 * @pos_in_time: #GstClockTime pointer where the result is set.
498 * Convert given byte position into #GstClockTime format.
500 * Returns: TRUE if conversion succeeded.
503 gst_base_parse_bytepos_to_time (GstBaseParse * parse, gint64 bytepos,
504 GstClockTime * pos_in_time)
506 GstBaseParseClass *klass;
507 gboolean res = FALSE;
509 klass = GST_BASE_PARSE_GET_CLASS (parse);
511 if (klass->convert) {
512 res = klass->convert (parse, GST_FORMAT_BYTES, bytepos,
513 GST_FORMAT_TIME, (gint64 *) pos_in_time);
520 * gst_base_parse_sink_event:
521 * @pad: #GstPad that received the event.
522 * @event: #GstEvent to be handled.
524 * Handler for sink pad events.
526 * Returns: TRUE if the event was handled.
529 gst_base_parse_sink_event (GstPad * pad, GstEvent * event)
532 GstBaseParseClass *bclass;
533 gboolean handled = FALSE;
537 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
538 bclass = GST_BASE_PARSE_GET_CLASS (parse);
540 GST_DEBUG_OBJECT (parse, "handling event %d", GST_EVENT_TYPE (event));
542 /* Cache all events except EOS, NEWSEGMENT and FLUSH_STOP if we have a
544 if (parse->pending_segment && GST_EVENT_TYPE (event) != GST_EVENT_EOS
545 && GST_EVENT_TYPE (event) != GST_EVENT_NEWSEGMENT
546 && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_START
547 && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
548 parse->priv->pending_events =
549 g_list_append (parse->priv->pending_events, event);
554 handled = bclass->event (parse, event);
557 ret = gst_pad_event_default (pad, event);
560 gst_object_unref (parse);
561 GST_DEBUG_OBJECT (parse, "event handled");
567 * gst_base_parse_sink_eventfunc:
568 * @parse: #GstBaseParse.
569 * @event: #GstEvent to be handled.
571 * Element-level event handler function.
573 * Returns: TRUE if the event was handled and not need forwarding.
576 gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event)
578 gboolean handled = FALSE;
581 switch (GST_EVENT_TYPE (event)) {
582 case GST_EVENT_NEWSEGMENT:
584 gdouble rate, applied_rate;
586 gint64 start, stop, pos, offset = 0;
589 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
590 &format, &start, &stop, &pos);
593 if (format == GST_FORMAT_BYTES) {
594 GstClockTime seg_start, seg_stop, seg_pos;
596 /* stop time is allowed to be open-ended, but not start & pos */
597 seg_stop = GST_CLOCK_TIME_NONE;
600 if (gst_base_parse_bytepos_to_time (parse, start, &seg_start) &&
601 gst_base_parse_bytepos_to_time (parse, pos, &seg_pos)) {
602 gst_event_unref (event);
603 event = gst_event_new_new_segment_full (update, rate, applied_rate,
604 GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
605 format = GST_FORMAT_TIME;
606 GST_DEBUG_OBJECT (parse, "Converted incoming segment to TIME. "
607 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
608 ", pos = %" GST_TIME_FORMAT, GST_TIME_ARGS (seg_start),
609 GST_TIME_ARGS (seg_stop), GST_TIME_ARGS (seg_pos));
613 if (format != GST_FORMAT_TIME) {
614 /* Unknown incoming segment format. Output a default open-ended
616 gst_event_unref (event);
617 event = gst_event_new_new_segment_full (update, rate, applied_rate,
618 GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0);
621 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
622 &format, &start, &stop, &pos);
624 gst_segment_set_newsegment_full (&parse->segment, update, rate,
625 applied_rate, format, start, stop, pos);
627 GST_DEBUG_OBJECT (parse, "Created newseg rate %g, applied rate %g, "
628 "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
629 ", pos = %" GST_TIME_FORMAT, rate, applied_rate, format,
630 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (pos));
632 /* save the segment for later, right before we push a new buffer so that
633 * the caps are fixed and the next linked element can receive
635 eventp = &parse->pending_segment;
636 gst_event_replace (eventp, event);
637 gst_event_unref (event);
640 /* but finish the current segment */
641 GST_DEBUG_OBJECT (parse, "draining current segment");
642 gst_base_parse_drain (parse);
643 gst_adapter_clear (parse->adapter);
644 parse->priv->offset = offset;
645 parse->priv->next_ts = start;
649 case GST_EVENT_FLUSH_START:
650 parse->priv->flushing = TRUE;
651 handled = gst_pad_push_event (parse->srcpad, event);
652 /* Wait for _chain() to exit by taking the srcpad STREAM_LOCK */
653 GST_PAD_STREAM_LOCK (parse->srcpad);
654 GST_PAD_STREAM_UNLOCK (parse->srcpad);
658 case GST_EVENT_FLUSH_STOP:
659 gst_adapter_clear (parse->adapter);
660 parse->priv->flushing = FALSE;
661 parse->priv->discont = TRUE;
665 gst_base_parse_drain (parse);
677 * gst_base_parse_src_event:
678 * @pad: #GstPad that received the event.
679 * @event: #GstEvent that was received.
681 * Handler for source pad events.
683 * Returns: TRUE if the event was handled.
686 gst_base_parse_src_event (GstPad * pad, GstEvent * event)
689 GstBaseParseClass *bclass;
690 gboolean handled = FALSE;
693 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
694 bclass = GST_BASE_PARSE_GET_CLASS (parse);
696 GST_DEBUG_OBJECT (parse, "event %d, %s", GST_EVENT_TYPE (event),
697 GST_EVENT_TYPE_NAME (event));
699 if (bclass->src_event)
700 handled = bclass->src_event (parse, event);
703 ret = gst_pad_event_default (pad, event);
705 gst_object_unref (parse);
711 * gst_base_parse_src_eventfunc:
712 * @parse: #GstBaseParse.
713 * @event: #GstEvent that was received.
715 * Default srcpad event handler.
717 * Returns: TRUE if the event was handled and can be dropped.
720 gst_base_parse_src_eventfunc (GstBaseParse * parse, GstEvent * event)
722 gboolean handled = FALSE;
723 GstBaseParseClass *bclass;
725 bclass = GST_BASE_PARSE_GET_CLASS (parse);
727 switch (GST_EVENT_TYPE (event)) {
730 if (bclass->is_seekable (parse)) {
731 handled = gst_base_parse_handle_seek (parse, event);
732 gst_event_unref (event);
744 * gst_base_parse_is_seekable:
745 * @parse: #GstBaseParse.
747 * Default handler for is_seekable.
749 * Returns: Always TRUE.
752 gst_base_parse_is_seekable (GstBaseParse * parse)
758 * gst_base_parse_convert:
759 * @parse: #GstBaseParse.
760 * @src_format: #GstFormat describing the source format.
761 * @src_value: Source value to be converted.
762 * @dest_format: #GstFormat defining the converted format.
763 * @dest_value: Pointer where the conversion result will be put.
765 * Implementation of "convert" vmethod in #GstBaseParse class.
767 * Returns: TRUE if conversion was successful.
770 gst_base_parse_convert (GstBaseParse * parse,
771 GstFormat src_format,
772 gint64 src_value, GstFormat dest_format, gint64 * dest_value)
774 gboolean ret = FALSE;
775 guint64 bytes, duration;
777 if (G_UNLIKELY (src_format == dest_format)) {
778 *dest_value = src_value;
782 if (G_UNLIKELY (src_value == -1)) {
787 /* need at least some frames */
788 if (!parse->priv->framecount)
791 /* either frame info (having num means den also ok) or use average bitrate */
792 if (parse->priv->fps_num) {
793 duration = parse->priv->framecount * parse->priv->fps_den * 1000;
794 bytes = parse->priv->bytecount * parse->priv->fps_num;
796 duration = parse->priv->acc_duration / GST_MSECOND;
797 bytes = parse->priv->bytecount;
800 if (G_UNLIKELY (!duration || !bytes))
803 if (src_format == GST_FORMAT_BYTES) {
804 if (dest_format == GST_FORMAT_TIME) {
805 /* BYTES -> TIME conversion */
806 GST_DEBUG_OBJECT (parse, "converting bytes -> time");
808 *dest_value = gst_util_uint64_scale (src_value, duration, bytes);
809 *dest_value *= GST_MSECOND;
810 GST_DEBUG_OBJECT (parse, "conversion result: %" G_GINT64_FORMAT " ms",
811 *dest_value / GST_MSECOND);
814 } else if (src_format == GST_FORMAT_TIME) {
815 GST_DEBUG_OBJECT (parse, "converting time -> bytes");
816 if (dest_format == GST_FORMAT_BYTES) {
817 *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes,
819 GST_DEBUG_OBJECT (parse,
820 "time %" G_GINT64_FORMAT " ms in bytes = %" G_GINT64_FORMAT,
821 src_value / GST_MSECOND, *dest_value);
824 } else if (src_format == GST_FORMAT_DEFAULT) {
825 /* DEFAULT == frame-based */
826 if (dest_format == GST_FORMAT_TIME) {
827 if (parse->priv->fps_den) {
828 *dest_value = gst_util_uint64_scale (src_value,
829 GST_SECOND * parse->priv->fps_den, parse->priv->fps_num);
832 } else if (dest_format == GST_FORMAT_BYTES) {
840 * gst_base_parse_update_duration:
841 * @parse: #GstBaseParse.
845 gst_base_parse_update_duration (GstBaseParse * aacparse)
849 GstBaseParseClass *klass;
851 parse = GST_BASE_PARSE (aacparse);
852 klass = GST_BASE_PARSE_GET_CLASS (parse);
854 /* must be able to convert */
858 peer = gst_pad_get_peer (parse->sinkpad);
860 GstFormat pformat = GST_FORMAT_BYTES;
861 gboolean qres = FALSE;
862 gint64 ptot, dest_value;
864 qres = gst_pad_query_duration (peer, &pformat, &ptot);
865 gst_object_unref (GST_OBJECT (peer));
867 if (klass->convert (parse, pformat, ptot, GST_FORMAT_TIME, &dest_value))
868 parse->priv->estimated_duration = dest_value;
874 * gst_base_parse_handle_and_push_buffer:
875 * @parse: #GstBaseParse.
876 * @klass: #GstBaseParseClass.
877 * @buffer: #GstBuffer.
879 * Parses the frame from given buffer and pushes it forward. Also performs
880 * timestamp handling and checks the segment limits.
882 * This is called with srcpad STREAM_LOCK held.
884 * Returns: #GstFlowReturn
887 gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
888 GstBaseParseClass * klass, GstBuffer * buffer)
892 if (parse->priv->discont) {
893 GST_DEBUG_OBJECT (parse, "marking DISCONT");
894 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
895 parse->priv->discont = FALSE;
898 ret = klass->parse_frame (parse, buffer);
900 /* re-use default handler to add missing metadata as-much-as-possible */
901 gst_base_parse_parse_frame (parse, buffer);
902 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
903 GST_BUFFER_DURATION_IS_VALID (buffer)) {
904 parse->priv->next_ts =
905 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
907 /* we lost track, do not produce bogus time next time around
908 * (probably means parser subclass has given up on parsing as well) */
909 GST_DEBUG_OBJECT (parse, "no next fallback timestamp");
910 parse->priv->next_ts = GST_CLOCK_TIME_NONE;
913 /* First buffers are dropped, this means that the subclass needs more
914 * frames to decide on the format and queues them internally */
915 if (ret == GST_BASE_PARSE_FLOW_DROPPED && !GST_PAD_CAPS (parse->srcpad)) {
916 gst_buffer_unref (buffer);
920 /* convert internal flow to OK and mark discont for the next buffer. */
921 if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
922 parse->priv->discont = TRUE;
925 gst_buffer_unref (buffer);
928 } else if (ret != GST_FLOW_OK) {
932 return gst_base_parse_push_buffer (parse, buffer);
936 * gst_base_parse_push_buffer:
937 * @parse: #GstBaseParse.
938 * @buffer: #GstBuffer.
940 * Pushes the buffer downstream, sends any pending events and
941 * does some timestamp and segment handling.
943 * This must be called with srcpad STREAM_LOCK held.
945 * Returns: #GstFlowReturn
948 gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
950 GstFlowReturn ret = GST_FLOW_OK;
951 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
953 GST_LOG_OBJECT (parse,
954 "processing buffer of size %d with ts %" GST_TIME_FORMAT
955 ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
956 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
957 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
960 parse->priv->bytecount += GST_BUFFER_SIZE (buffer);
961 if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME)) {
962 parse->priv->framecount++;
963 if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
964 parse->priv->acc_duration += GST_BUFFER_DURATION (buffer);
967 GST_BUFFER_FLAG_UNSET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME);
968 if (parse->priv->update_interval &&
969 (parse->priv->framecount % parse->priv->update_interval) == 0)
970 gst_base_parse_update_duration (parse);
972 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
973 last_stop = GST_BUFFER_TIMESTAMP (buffer);
974 if (last_stop != GST_CLOCK_TIME_NONE && GST_BUFFER_DURATION_IS_VALID (buffer))
975 last_stop += GST_BUFFER_DURATION (buffer);
977 /* should have caps by now */
978 g_return_val_if_fail (GST_PAD_CAPS (parse->srcpad), GST_FLOW_ERROR);
980 gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
982 /* and should then also be linked downstream, so safe to send some events */
983 if (parse->priv->pad_mode == GST_ACTIVATE_PULL) {
984 if (G_UNLIKELY (parse->close_segment)) {
985 GST_DEBUG_OBJECT (parse, "loop sending close segment");
986 gst_pad_push_event (parse->srcpad, parse->close_segment);
987 parse->close_segment = NULL;
990 if (G_UNLIKELY (parse->pending_segment)) {
991 GST_DEBUG_OBJECT (parse, "loop push pending segment");
992 gst_pad_push_event (parse->srcpad, parse->pending_segment);
993 parse->pending_segment = NULL;
996 if (G_UNLIKELY (parse->pending_segment)) {
997 GST_DEBUG_OBJECT (parse, "chain pushing a pending segment");
998 gst_pad_push_event (parse->srcpad, parse->pending_segment);
999 parse->pending_segment = NULL;
1003 if (G_UNLIKELY (parse->priv->pending_events)) {
1006 for (l = parse->priv->pending_events; l != NULL; l = l->next) {
1007 gst_pad_push_event (parse->srcpad, GST_EVENT (l->data));
1009 g_list_free (parse->priv->pending_events);
1010 parse->priv->pending_events = NULL;
1013 /* TODO: Add to seek table */
1015 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
1016 GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
1017 GST_BUFFER_TIMESTAMP (buffer) > parse->segment.stop) {
1018 GST_LOG_OBJECT (parse, "Dropped frame, after segment");
1019 gst_buffer_unref (buffer);
1020 } else if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
1021 GST_BUFFER_DURATION_IS_VALID (buffer) &&
1022 GST_CLOCK_TIME_IS_VALID (parse->segment.start) &&
1023 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer)
1024 < parse->segment.start) {
1025 /* FIXME: subclass needs way to override the start as downstream might
1026 * need frames before for proper decoding */
1027 GST_LOG_OBJECT (parse, "Dropped frame, before segment");
1028 gst_buffer_unref (buffer);
1030 ret = gst_pad_push (parse->srcpad, buffer);
1031 GST_LOG_OBJECT (parse, "frame (%d bytes) pushed: %d",
1032 GST_BUFFER_SIZE (buffer), ret);
1035 /* Update current running segment position */
1036 if (ret == GST_FLOW_OK && last_stop != GST_CLOCK_TIME_NONE)
1037 gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop);
1044 * gst_base_parse_drain:
1045 * @parse: #GstBaseParse.
1047 * Drains the adapter until it is empty. It decreases the min_frame_size to
1048 * match the current adapter size and calls chain method until the adapter
1049 * is emptied or chain returns with error.
1052 gst_base_parse_drain (GstBaseParse * parse)
1056 GST_DEBUG_OBJECT (parse, "draining");
1057 parse->priv->drain = TRUE;
1060 avail = gst_adapter_available (parse->adapter);
1064 if (gst_base_parse_chain (parse->sinkpad, NULL) != GST_FLOW_OK) {
1068 /* nothing changed, maybe due to truncated frame; break infinite loop */
1069 if (avail == gst_adapter_available (parse->adapter)) {
1070 GST_DEBUG_OBJECT (parse, "no change during draining; flushing");
1071 gst_adapter_clear (parse->adapter);
1075 parse->priv->drain = FALSE;
1080 * gst_base_parse_chain:
1082 * @buffer: #GstBuffer.
1084 * Returns: #GstFlowReturn.
1086 static GstFlowReturn
1087 gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
1089 GstBaseParseClass *bclass;
1090 GstBaseParse *parse;
1091 GstFlowReturn ret = GST_FLOW_OK;
1092 GstBuffer *outbuf = NULL;
1093 GstBuffer *tmpbuf = NULL;
1098 GstClockTime timestamp;
1100 parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad));
1101 bclass = GST_BASE_PARSE_GET_CLASS (parse);
1103 if (G_LIKELY (buffer)) {
1104 GST_LOG_OBJECT (parse, "buffer size: %d, offset = %" G_GINT64_FORMAT,
1105 GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
1106 if (G_UNLIKELY (parse->priv->passthrough)) {
1107 buffer = gst_buffer_make_metadata_writable (buffer);
1108 return gst_base_parse_push_buffer (parse, buffer);
1110 gst_adapter_push (parse->adapter, buffer);
1113 /* Parse and push as many frames as possible */
1114 /* Stop either when adapter is empty or we are flushing */
1115 while (!parse->priv->flushing) {
1116 tmpbuf = gst_buffer_new ();
1118 /* Synchronization loop */
1120 GST_BASE_PARSE_LOCK (parse);
1121 min_size = parse->priv->min_frame_size;
1122 GST_BASE_PARSE_UNLOCK (parse);
1124 if (G_UNLIKELY (parse->priv->drain)) {
1125 min_size = gst_adapter_available (parse->adapter);
1126 GST_DEBUG_OBJECT (parse, "draining, data left: %d", min_size);
1127 if (G_UNLIKELY (!min_size)) {
1128 gst_buffer_unref (tmpbuf);
1133 /* Collect at least min_frame_size bytes */
1134 if (gst_adapter_available (parse->adapter) < min_size) {
1135 GST_DEBUG_OBJECT (parse, "not enough data available (only %d bytes)",
1136 gst_adapter_available (parse->adapter));
1137 gst_buffer_unref (tmpbuf);
1141 data = gst_adapter_peek (parse->adapter, min_size);
1142 GST_BUFFER_DATA (tmpbuf) = (guint8 *) data;
1143 GST_BUFFER_SIZE (tmpbuf) = min_size;
1144 GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset;
1145 GST_BUFFER_FLAG_SET (tmpbuf, GST_MINI_OBJECT_FLAG_READONLY);
1147 if (parse->priv->discont) {
1148 GST_DEBUG_OBJECT (parse, "marking DISCONT");
1149 GST_BUFFER_FLAG_SET (tmpbuf, GST_BUFFER_FLAG_DISCONT);
1153 if (bclass->check_valid_frame (parse, tmpbuf, &fsize, &skip)) {
1154 if (gst_adapter_available (parse->adapter) < fsize) {
1155 GST_DEBUG_OBJECT (parse,
1156 "found valid frame but not enough data available (only %d bytes)",
1157 gst_adapter_available (parse->adapter));
1158 gst_buffer_unref (tmpbuf);
1164 GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
1165 gst_adapter_flush (parse->adapter, skip);
1166 parse->priv->offset += skip;
1167 parse->priv->discont = TRUE;
1168 } else if (skip == -1) {
1169 /* subclass didn't touch this value. By default we skip 1 byte */
1170 GST_LOG_OBJECT (parse, "finding sync, skipping 1 byte");
1171 gst_adapter_flush (parse->adapter, 1);
1172 parse->priv->offset++;
1173 parse->priv->discont = TRUE;
1175 /* There is a possibility that subclass set the skip value to zero.
1176 This means that it has probably found a frame but wants to ask
1177 more data (by increasing the min_size) to be sure of this. */
1179 gst_buffer_unref (tmpbuf);
1183 /* Subclass found the sync, but still wants to skip some data */
1184 GST_LOG_OBJECT (parse, "skipping %d bytes", skip);
1185 gst_adapter_flush (parse->adapter, skip);
1186 parse->priv->offset += skip;
1189 /* Grab lock to prevent a race with FLUSH_START handler */
1190 GST_PAD_STREAM_LOCK (parse->srcpad);
1192 /* FLUSH_START event causes the "flushing" flag to be set. In this
1193 * case we can leave the frame pushing loop */
1194 if (parse->priv->flushing) {
1195 GST_PAD_STREAM_UNLOCK (parse->srcpad);
1199 /* FIXME: Would it be more efficient to make a subbuffer instead? */
1200 outbuf = gst_adapter_take_buffer (parse->adapter, fsize);
1201 outbuf = gst_buffer_make_metadata_writable (outbuf);
1203 /* Subclass may want to know the data offset */
1204 GST_BUFFER_OFFSET (outbuf) = parse->priv->offset;
1205 parse->priv->offset += fsize;
1207 /* move along with upstream timestamp (if any),
1208 * but interpolate in between */
1209 timestamp = gst_adapter_prev_timestamp (parse->adapter, NULL);
1210 if (GST_CLOCK_TIME_IS_VALID (timestamp) &&
1211 (parse->priv->prev_ts != timestamp)) {
1212 parse->priv->prev_ts = parse->priv->next_ts = timestamp;
1215 ret = gst_base_parse_handle_and_push_buffer (parse, bclass, outbuf);
1216 GST_PAD_STREAM_UNLOCK (parse->srcpad);
1218 if (ret != GST_FLOW_OK) {
1219 GST_LOG_OBJECT (parse, "push returned %d", ret);
1225 GST_LOG_OBJECT (parse, "chain leaving");
1229 /* pull @size bytes at current offset,
1230 * i.e. at least try to and possibly return a shorter buffer if near the end */
1231 static GstFlowReturn
1232 gst_base_parse_pull_range (GstBaseParse * parse, guint size,
1233 GstBuffer ** buffer)
1235 GstFlowReturn ret = GST_FLOW_OK;
1237 g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
1239 /* Caching here actually makes much less difference than one would expect.
1240 * We do it mainly to avoid pulling buffers of 1 byte all the time */
1241 if (parse->priv->cache) {
1242 guint64 cache_offset = GST_BUFFER_OFFSET (parse->priv->cache);
1243 guint cache_size = GST_BUFFER_SIZE (parse->priv->cache);
1245 if (cache_offset <= parse->priv->offset &&
1246 (parse->priv->offset + size) <= (cache_offset + cache_size)) {
1247 *buffer = gst_buffer_create_sub (parse->priv->cache,
1248 parse->priv->offset - cache_offset, size);
1249 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1252 /* not enough data in the cache, free cache and get a new one */
1253 gst_buffer_unref (parse->priv->cache);
1254 parse->priv->cache = NULL;
1257 /* refill the cache */
1259 gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size,
1260 64 * 1024), &parse->priv->cache);
1261 if (ret != GST_FLOW_OK) {
1262 parse->priv->cache = NULL;
1266 if (GST_BUFFER_SIZE (parse->priv->cache) >= size) {
1267 *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
1268 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1272 /* Not possible to get enough data, try a last time with
1273 * requesting exactly the size we need */
1274 gst_buffer_unref (parse->priv->cache);
1275 parse->priv->cache = NULL;
1277 ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, size,
1278 &parse->priv->cache);
1280 if (ret != GST_FLOW_OK) {
1281 GST_DEBUG_OBJECT (parse, "pull_range returned %d", ret);
1286 if (GST_BUFFER_SIZE (parse->priv->cache) < size) {
1287 GST_DEBUG_OBJECT (parse, "Returning short buffer at offset %"
1288 G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", parse->priv->offset,
1289 size, GST_BUFFER_SIZE (parse->priv->cache));
1291 *buffer = parse->priv->cache;
1292 parse->priv->cache = NULL;
1297 *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
1298 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1304 * gst_base_parse_loop:
1307 * Loop that is used in pull mode to retrieve data from upstream.
1310 gst_base_parse_loop (GstPad * pad)
1312 GstBaseParse *parse;
1313 GstBaseParseClass *klass;
1314 GstBuffer *buffer, *outbuf;
1315 gboolean ret = FALSE;
1316 guint fsize = 0, min_size;
1319 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
1320 klass = GST_BASE_PARSE_GET_CLASS (parse);
1322 /* TODO: Check if we reach segment stop limit */
1326 GST_BASE_PARSE_LOCK (parse);
1327 min_size = parse->priv->min_frame_size;
1328 GST_BASE_PARSE_UNLOCK (parse);
1330 ret = gst_base_parse_pull_range (parse, min_size, &buffer);
1332 if (ret == GST_FLOW_UNEXPECTED)
1334 else if (ret != GST_FLOW_OK)
1337 if (parse->priv->discont) {
1338 GST_DEBUG_OBJECT (parse, "marking DISCONT");
1339 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
1342 /* if we got a short read, inform subclass we are draining leftover
1343 * and no more is to be expected */
1344 if (GST_BUFFER_SIZE (buffer) < min_size)
1345 parse->priv->drain = TRUE;
1348 if (klass->check_valid_frame (parse, buffer, &fsize, &skip)) {
1349 parse->priv->drain = FALSE;
1352 parse->priv->drain = FALSE;
1354 GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
1355 parse->priv->offset += skip;
1356 parse->priv->discont = TRUE;
1357 } else if (skip == -1) {
1358 GST_LOG_OBJECT (parse, "finding sync, skipping 1 byte");
1359 parse->priv->offset++;
1360 parse->priv->discont = TRUE;
1362 GST_DEBUG_OBJECT (parse, "finding sync...");
1363 gst_buffer_unref (buffer);
1366 if (fsize <= GST_BUFFER_SIZE (buffer)) {
1367 outbuf = gst_buffer_create_sub (buffer, 0, fsize);
1368 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer);
1369 gst_buffer_unref (buffer);
1371 gst_buffer_unref (buffer);
1372 ret = gst_base_parse_pull_range (parse, fsize, &outbuf);
1374 if (ret == GST_FLOW_UNEXPECTED)
1376 else if (ret != GST_FLOW_OK)
1378 if (GST_BUFFER_SIZE (outbuf) < fsize)
1382 parse->priv->offset += fsize;
1384 /* Does the subclass want to skip too? */
1386 parse->priv->offset += skip;
1388 /* This always unrefs the outbuf, even if error occurs */
1389 ret = gst_base_parse_handle_and_push_buffer (parse, klass, outbuf);
1391 if (ret != GST_FLOW_OK) {
1392 GST_DEBUG_OBJECT (parse, "flow: %s", gst_flow_get_name (ret));
1393 if (GST_FLOW_IS_FATAL (ret)) {
1394 GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
1395 ("streaming task paused, reason: %s", gst_flow_get_name (ret)));
1396 gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1401 gst_object_unref (parse);
1406 GST_LOG_OBJECT (parse, "pausing task");
1407 gst_pad_pause_task (pad);
1408 gst_object_unref (parse);
1413 GST_LOG_OBJECT (parse, "pausing task %d", ret);
1414 gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1415 gst_pad_pause_task (pad);
1416 gst_object_unref (parse);
1423 * gst_base_parse_sink_activate:
1424 * @sinkpad: #GstPad to be activated.
1426 * Returns: TRUE if activation succeeded.
1429 gst_base_parse_sink_activate (GstPad * sinkpad)
1431 GstBaseParse *parse;
1432 gboolean result = TRUE;
1434 parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
1436 GST_DEBUG_OBJECT (parse, "sink activate");
1438 if (gst_pad_check_pull_range (sinkpad)) {
1439 GST_DEBUG_OBJECT (parse, "trying to activate in pull mode");
1440 result = gst_pad_activate_pull (sinkpad, TRUE);
1442 GST_DEBUG_OBJECT (parse, "trying to activate in push mode");
1443 result = gst_pad_activate_push (sinkpad, TRUE);
1446 GST_DEBUG_OBJECT (parse, "sink activate return %d", result);
1447 gst_object_unref (parse);
1453 * gst_base_parse_activate:
1454 * @parse: #GstBaseParse.
1455 * @active: TRUE if element will be activated, FALSE if disactivated.
1457 * Returns: TRUE if the operation succeeded.
1460 gst_base_parse_activate (GstBaseParse * parse, gboolean active)
1462 GstBaseParseClass *klass;
1463 gboolean result = FALSE;
1465 GST_DEBUG_OBJECT (parse, "activate");
1467 klass = GST_BASE_PARSE_GET_CLASS (parse);
1470 if (parse->priv->pad_mode == GST_ACTIVATE_NONE && klass->start)
1471 result = klass->start (parse);
1473 GST_OBJECT_LOCK (parse);
1474 gst_segment_init (&parse->segment, GST_FORMAT_TIME);
1475 parse->priv->duration = -1;
1476 parse->priv->discont = TRUE;
1477 parse->priv->flushing = FALSE;
1478 parse->priv->offset = 0;
1479 parse->priv->update_interval = 0;
1480 parse->priv->fps_num = parse->priv->fps_den = 0;
1481 parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
1482 parse->priv->framecount = 0;
1483 parse->priv->bytecount = 0;
1484 parse->priv->acc_duration = 0;
1485 parse->priv->estimated_duration = -1;
1486 parse->priv->next_ts = 0;
1487 parse->priv->passthrough = FALSE;
1489 if (parse->pending_segment)
1490 gst_event_unref (parse->pending_segment);
1492 parse->pending_segment =
1493 gst_event_new_new_segment (FALSE, parse->segment.rate,
1494 parse->segment.format,
1495 parse->segment.start, parse->segment.stop, parse->segment.last_stop);
1497 GST_OBJECT_UNLOCK (parse);
1499 /* We must make sure streaming has finished before resetting things
1500 * and calling the ::stop vfunc */
1501 GST_PAD_STREAM_LOCK (parse->sinkpad);
1502 GST_PAD_STREAM_UNLOCK (parse->sinkpad);
1504 if (parse->priv->pad_mode != GST_ACTIVATE_NONE && klass->stop)
1505 result = klass->stop (parse);
1507 g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
1509 g_list_free (parse->priv->pending_events);
1510 parse->priv->pending_events = NULL;
1512 if (parse->priv->cache) {
1513 gst_buffer_unref (parse->priv->cache);
1514 parse->priv->cache = NULL;
1517 parse->priv->pad_mode = GST_ACTIVATE_NONE;
1519 GST_DEBUG_OBJECT (parse, "activate: %d", result);
1525 * gst_base_parse_sink_activate_push:
1526 * @pad: #GstPad to be (de)activated.
1527 * @active: TRUE when activating, FALSE when deactivating.
1529 * Returns: TRUE if (de)activation succeeded.
1532 gst_base_parse_sink_activate_push (GstPad * pad, gboolean active)
1534 gboolean result = TRUE;
1535 GstBaseParse *parse;
1537 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
1539 GST_DEBUG_OBJECT (parse, "sink activate push");
1541 result = gst_base_parse_activate (parse, active);
1544 parse->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
1546 GST_DEBUG_OBJECT (parse, "sink activate push: %d", result);
1548 gst_object_unref (parse);
1554 * gst_base_parse_sink_activate_pull:
1555 * @sinkpad: #GstPad to be (de)activated.
1556 * @active: TRUE when activating, FALSE when deactivating.
1558 * Returns: TRUE if (de)activation succeeded.
1561 gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
1563 gboolean result = FALSE;
1564 GstBaseParse *parse;
1566 parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
1568 GST_DEBUG_OBJECT (parse, "activate pull");
1570 result = gst_base_parse_activate (parse, active);
1574 result &= gst_pad_start_task (sinkpad,
1575 (GstTaskFunction) gst_base_parse_loop, sinkpad);
1577 result &= gst_pad_stop_task (sinkpad);
1582 parse->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
1584 GST_DEBUG_OBJECT (parse, "sink activate pull: %d", result);
1586 gst_object_unref (parse);
1592 * gst_base_parse_set_duration:
1593 * @parse: #GstBaseParse.
1595 * @duration: duration value.
1597 * Sets the duration of the currently playing media. Subclass can use this
1598 * when it notices a change in the media duration.
1601 gst_base_parse_set_duration (GstBaseParse * parse,
1602 GstFormat fmt, gint64 duration)
1604 g_return_if_fail (parse != NULL);
1606 GST_BASE_PARSE_LOCK (parse);
1607 if (duration != parse->priv->duration) {
1610 m = gst_message_new_duration (GST_OBJECT (parse), fmt, duration);
1611 gst_element_post_message (GST_ELEMENT (parse), m);
1613 /* TODO: what about duration tag? */
1615 parse->priv->duration = duration;
1616 parse->priv->duration_fmt = fmt;
1617 GST_DEBUG_OBJECT (parse, "set duration: %" G_GINT64_FORMAT, duration);
1618 GST_BASE_PARSE_UNLOCK (parse);
1623 * gst_base_parse_set_min_frame_size:
1624 * @parse: #GstBaseParse.
1625 * @min_size: Minimum size of the data that this base class should give to
1628 * Subclass can use this function to tell the base class that it needs to
1629 * give at least #min_size buffers.
1632 gst_base_parse_set_min_frame_size (GstBaseParse * parse, guint min_size)
1634 g_return_if_fail (parse != NULL);
1636 GST_BASE_PARSE_LOCK (parse);
1637 parse->priv->min_frame_size = min_size;
1638 GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size);
1639 GST_BASE_PARSE_UNLOCK (parse);
1643 * gst_base_transform_set_passthrough:
1644 * @trans: the #GstBaseParse to set
1645 * @passthrough: boolean indicating passthrough mode.
1647 * Set passthrough mode for this parser. If operating in passthrough,
1648 * incoming buffers are pushed through unmodified.
1651 gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough)
1653 g_return_if_fail (parse != NULL);
1655 GST_BASE_PARSE_LOCK (parse);
1656 parse->priv->passthrough = passthrough;
1657 GST_LOG_OBJECT (parse, "set passthrough: %d", passthrough);
1658 GST_BASE_PARSE_UNLOCK (parse);
1662 * gst_base_transform_set_frame_props:
1663 * @parse: the #GstBaseParse to set
1664 * @fps_num: frames per second (numerator).
1665 * @fps_den: frames per second (denominator).
1666 * @interval: duration update interval in frames.
1668 * If frames per second is configured, parser can provide for default @convert
1669 * between GST_FORMAT_TIME and GST_FORMAT_BYTES, as well as buffer duration
1670 * and timestamping. However, even if this frame information is provided,
1671 * subclass can still choose to provide for a @convert and set buffer metadata.
1672 * If #interval is non-zero (default), then stream duration is determined
1673 * based on frame and byte counts, and updated every #interval frames.
1676 gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num,
1677 guint fps_den, gint interval)
1679 g_return_if_fail (parse != NULL);
1681 GST_BASE_PARSE_LOCK (parse);
1682 parse->priv->fps_num = fps_num;
1683 parse->priv->fps_den = fps_den;
1684 parse->priv->update_interval = interval;
1685 if (!fps_num || !fps_den) {
1686 GST_DEBUG_OBJECT (parse, "invalid fps (%d/%d), ignoring parameters",
1688 fps_num = fps_den = 0;
1690 parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
1692 parse->priv->frame_duration =
1693 gst_util_uint64_scale (GST_SECOND, parse->priv->fps_den,
1694 parse->priv->fps_num);
1696 GST_LOG_OBJECT (parse, "set fps: %d/%d => duration: %" G_GINT64_FORMAT " ms",
1697 fps_num, fps_den, parse->priv->frame_duration / GST_MSECOND);
1698 GST_LOG_OBJECT (parse, "set update interval: %d", interval);
1699 GST_BASE_PARSE_UNLOCK (parse);
1703 * gst_base_transform_get_sync:
1704 * @parse: the #GstBaseParse to query
1706 * Returns TRUE if parser is considered 'in sync'. That is, frames have been
1707 * continuously successfully parsed and pushed.
1710 gst_base_parse_get_sync (GstBaseParse * parse)
1714 g_return_val_if_fail (parse != NULL, FALSE);
1716 GST_BASE_PARSE_LOCK (parse);
1717 /* losing sync is pretty much a discont (and vice versa), no ? */
1718 ret = !parse->priv->discont;
1719 GST_BASE_PARSE_UNLOCK (parse);
1721 GST_DEBUG_OBJECT (parse, "sync: %d", ret);
1726 * gst_base_transform_get_drain:
1727 * @parse: the #GstBaseParse to query
1729 * Returns TRUE if parser is currently 'draining'. That is, leftover data
1730 * (e.g. in FLUSH or EOS situation) is being parsed.
1733 gst_base_parse_get_drain (GstBaseParse * parse)
1737 g_return_val_if_fail (parse != NULL, FALSE);
1739 GST_BASE_PARSE_LOCK (parse);
1740 /* losing sync is pretty much a discont (and vice versa), no ? */
1741 ret = parse->priv->drain;
1742 GST_BASE_PARSE_UNLOCK (parse);
1744 GST_DEBUG_OBJECT (parse, "drain: %d", ret);
1749 * gst_base_parse_get_querytypes:
1752 * Returns: A table of #GstQueryType items describing supported query types.
1754 static const GstQueryType *
1755 gst_base_parse_get_querytypes (GstPad * pad)
1757 static const GstQueryType list[] = {
1771 * gst_base_parse_query:
1773 * @query: #GstQuery.
1775 * Returns: TRUE on success.
1778 gst_base_parse_query (GstPad * pad, GstQuery * query)
1780 GstBaseParse *parse;
1781 GstBaseParseClass *klass;
1782 gboolean res = FALSE;
1784 parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
1785 klass = GST_BASE_PARSE_GET_CLASS (parse);
1787 /* If subclass doesn't provide conversion function we can't reply
1788 to the query either */
1789 if (!klass->convert) {
1793 switch (GST_QUERY_TYPE (query)) {
1794 case GST_QUERY_POSITION:
1799 GST_DEBUG_OBJECT (parse, "position query");
1801 gst_query_parse_position (query, &format, NULL);
1803 g_mutex_lock (parse->parse_lock);
1805 if (format == GST_FORMAT_BYTES) {
1806 dest_value = parse->priv->offset;
1808 } else if (format == parse->segment.format &&
1809 GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop)) {
1810 dest_value = parse->segment.last_stop;
1813 /* priv->offset is updated in both PUSH/PULL modes */
1814 res = klass->convert (parse, GST_FORMAT_BYTES, parse->priv->offset,
1815 format, &dest_value);
1817 g_mutex_unlock (parse->parse_lock);
1820 gst_query_set_position (query, format, dest_value);
1822 res = gst_pad_query_default (pad, query);
1826 case GST_QUERY_DURATION:
1831 GST_DEBUG_OBJECT (parse, "duration query");
1833 gst_query_parse_duration (query, &format, NULL);
1835 g_mutex_lock (parse->parse_lock);
1837 if (format == GST_FORMAT_BYTES) {
1838 res = gst_pad_query_peer_duration (parse->sinkpad, &format,
1840 } else if (parse->priv->duration != -1 &&
1841 format == parse->priv->duration_fmt) {
1842 dest_value = parse->priv->duration;
1844 } else if (parse->priv->duration != -1) {
1845 res = klass->convert (parse, parse->priv->duration_fmt,
1846 parse->priv->duration, format, &dest_value);
1847 } else if (parse->priv->estimated_duration != -1) {
1848 dest_value = parse->priv->estimated_duration;
1852 g_mutex_unlock (parse->parse_lock);
1855 gst_query_set_duration (query, format, dest_value);
1857 res = gst_pad_query_default (pad, query);
1860 case GST_QUERY_SEEKING:
1863 gboolean seekable = FALSE;
1865 GST_DEBUG_OBJECT (parse, "seeking query");
1867 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1869 if (fmt != GST_FORMAT_TIME) {
1870 return gst_pad_query_default (pad, query);
1873 seekable = klass->is_seekable (parse);
1875 /* TODO: could this duration be calculated/converted if subclass
1877 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
1878 (parse->priv->duration == -1) ?
1879 GST_CLOCK_TIME_NONE : parse->priv->duration);
1881 GST_DEBUG_OBJECT (parse, "seekable: %d", seekable);
1885 case GST_QUERY_FORMATS:
1886 gst_query_set_formatsv (query, 3, fmtlist);
1890 case GST_QUERY_CONVERT:
1892 GstFormat src_format, dest_format;
1893 gint64 src_value, dest_value;
1895 gst_query_parse_convert (query, &src_format, &src_value,
1896 &dest_format, &dest_value);
1898 /* FIXME: hm? doesn't make sense
1899 * We require all those values to be given
1900 if (src_format && src_value && dest_format && dest_value ) { */
1901 res = klass->convert (parse, src_format, src_value,
1902 dest_format, &dest_value);
1904 gst_query_set_convert (query, src_format, src_value,
1905 dest_format, dest_value);
1911 res = gst_pad_query_default (pad, query);
1919 * gst_base_parse_handle_seek:
1920 * @parse: #GstBaseParse.
1921 * @event: #GstEvent.
1923 * Returns: TRUE if seek succeeded.
1926 gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
1928 GstBaseParseClass *klass;
1932 GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
1933 gboolean flush, update, res = TRUE;
1934 gint64 cur, stop, seekpos;
1935 GstSegment seeksegment = { 0, };
1936 GstFormat dstformat;
1938 klass = GST_BASE_PARSE_GET_CLASS (parse);
1940 gst_event_parse_seek (event, &rate, &format, &flags,
1941 &cur_type, &cur, &stop_type, &stop);
1943 /* no negative rates yet */
1947 if (cur_type != GST_SEEK_TYPE_SET)
1950 /* For any format other than TIME, see if upstream handles
1951 * it directly or fail. For TIME, try upstream, but do it ourselves if
1952 * it fails upstream */
1953 if (format != GST_FORMAT_TIME) {
1954 return gst_pad_push_event (parse->sinkpad, event);
1956 gst_event_ref (event);
1957 if (gst_pad_push_event (parse->sinkpad, event)) {
1958 gst_event_unref (event);
1963 /* get flush flag */
1964 flush = flags & GST_SEEK_FLAG_FLUSH;
1966 dstformat = GST_FORMAT_BYTES;
1967 if (!gst_pad_query_convert (parse->srcpad, format, cur, &dstformat, &seekpos)) {
1968 GST_DEBUG_OBJECT (parse, "conversion failed");
1972 GST_DEBUG_OBJECT (parse,
1973 "seek position %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT, cur,
1976 if (parse->priv->pad_mode == GST_ACTIVATE_PULL) {
1979 GST_DEBUG_OBJECT (parse, "seek in PULL mode");
1982 if (parse->srcpad) {
1983 GST_DEBUG_OBJECT (parse, "sending flush start");
1984 gst_pad_push_event (parse->srcpad, gst_event_new_flush_start ());
1987 gst_pad_pause_task (parse->sinkpad);
1990 /* we should now be able to grab the streaming thread because we stopped it
1991 * with the above flush/pause code */
1992 GST_PAD_STREAM_LOCK (parse->sinkpad);
1994 /* save current position */
1995 last_stop = parse->segment.last_stop;
1996 GST_DEBUG_OBJECT (parse, "stopped streaming at %" G_GINT64_FORMAT,
1999 /* copy segment, we need this because we still need the old
2000 * segment when we close the current segment. */
2001 memcpy (&seeksegment, &parse->segment, sizeof (GstSegment));
2003 GST_DEBUG_OBJECT (parse, "configuring seek");
2004 gst_segment_set_seek (&seeksegment, rate, format, flags,
2005 cur_type, cur, stop_type, stop, &update);
2007 /* figure out the last position we need to play. If it's configured (stop !=
2008 * -1), use that, else we play until the total duration of the file */
2009 if ((stop = seeksegment.stop) == -1)
2010 stop = seeksegment.duration;
2012 parse->priv->offset = seekpos;
2014 /* prepare for streaming again */
2016 GST_DEBUG_OBJECT (parse, "sending flush stop");
2017 gst_pad_push_event (parse->srcpad, gst_event_new_flush_stop ());
2019 if (parse->close_segment)
2020 gst_event_unref (parse->close_segment);
2022 parse->close_segment = gst_event_new_new_segment (TRUE,
2023 parse->segment.rate, parse->segment.format,
2024 parse->segment.accum, parse->segment.last_stop, parse->segment.accum);
2026 /* keep track of our last_stop */
2027 seeksegment.accum = parse->segment.last_stop;
2029 GST_DEBUG_OBJECT (parse, "Created close seg format %d, "
2030 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
2031 ", pos = %" GST_TIME_FORMAT, format,
2032 GST_TIME_ARGS (parse->segment.accum),
2033 GST_TIME_ARGS (parse->segment.last_stop),
2034 GST_TIME_ARGS (parse->segment.accum));
2037 memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));
2039 /* store the newsegment event so it can be sent from the streaming thread. */
2040 if (parse->pending_segment)
2041 gst_event_unref (parse->pending_segment);
2043 /* This will be sent later in _loop() */
2044 parse->pending_segment =
2045 gst_event_new_new_segment (FALSE, parse->segment.rate,
2046 parse->segment.format,
2047 parse->segment.last_stop, stop, parse->segment.last_stop);
2049 GST_DEBUG_OBJECT (parse, "Created newseg format %d, "
2050 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
2051 ", pos = %" GST_TIME_FORMAT, format,
2052 GST_TIME_ARGS (parse->segment.last_stop),
2053 GST_TIME_ARGS (stop), GST_TIME_ARGS (parse->segment.last_stop));
2055 /* mark discont if we are going to stream from another position. */
2056 if (last_stop != parse->segment.last_stop) {
2057 GST_DEBUG_OBJECT (parse,
2058 "mark DISCONT, we did a seek to another position");
2059 parse->priv->discont = TRUE;
2060 parse->priv->next_ts = parse->segment.last_stop;
2063 /* Start streaming thread if paused */
2064 gst_pad_start_task (parse->sinkpad,
2065 (GstTaskFunction) gst_base_parse_loop, parse->sinkpad);
2067 GST_PAD_STREAM_UNLOCK (parse->sinkpad);
2069 GstEvent *new_event;
2070 /* The only thing we need to do in PUSH-mode is to send the
2071 seek event (in bytes) to upstream. Segment / flush handling happens
2072 in corresponding src event handlers */
2073 GST_DEBUG_OBJECT (parse, "seek in PUSH mode");
2074 new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flush,
2075 GST_SEEK_TYPE_SET, seekpos, stop_type, stop);
2077 res = gst_pad_push_event (parse->sinkpad, new_event);
2086 GST_DEBUG_OBJECT (parse, "negative playback rates are not supported yet.");
2092 GST_DEBUG_OBJECT (parse, "unsupported seek type.");
2100 * gst_base_parse_sink_setcaps:
2104 * Returns: TRUE if caps were accepted.
2107 gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
2109 GstBaseParse *parse;
2110 GstBaseParseClass *klass;
2111 gboolean res = TRUE;
2113 parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
2114 klass = GST_BASE_PARSE_GET_CLASS (parse);
2116 GST_DEBUG_OBJECT (parse, "caps: %" GST_PTR_FORMAT, caps);
2118 if (klass->set_sink_caps)
2119 res = klass->set_sink_caps (parse, caps);
2121 parse->negotiated = res;
2122 return res && gst_pad_set_caps (pad, caps);