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
89 * After valid frame is found, it will be passed again to subclass with
90 * @parse_frame call. Now subclass is responsible for parsing the
91 * frame contents and setting the buffer timestamp, duration and caps.
94 * Finally the buffer can be pushed downstream and parsing loop starts
98 * During the parsing process GstBaseClass will handle both srcpad and
99 * sinkpad events. They will be passed to subclass if @event or
100 * @src_event callbacks have been provided.
105 * <itemizedlist><title>Shutdown phase</title>
107 * GstBaseParse class calls @stop to inform the subclass that data
108 * parsing will be stopped.
114 * Subclass is responsible for providing pad template caps for
115 * source and sink pads. The pads need to be named "sink" and "src". It also
116 * needs to set the fixed caps on srcpad, when the format is ensured (e.g.
117 * when base class calls subclass' @set_sink_caps function).
119 * This base class uses GST_FORMAT_DEFAULT as a meaning of frames. So,
120 * subclass conversion routine needs to know that conversion from
121 * GST_FORMAT_TIME to GST_FORMAT_DEFAULT must return the
122 * frame number that can be found from the given byte position.
124 * GstBaseParse uses subclasses conversion methods also for seeking. If
125 * subclass doesn't provide @convert function, seeking will get disabled.
127 * Subclass @start and @stop functions will be called to inform the beginning
128 * and end of data processing.
130 * Things that subclass need to take care of:
132 * <listitem><para>Provide pad templates</para></listitem>
134 * Fixate the source pad caps when appropriate
137 * Inform base class how big data chunks should be retrieved. This is
138 * done with @gst_base_parse_set_min_frame_size function.
141 * Examine data chunks passed to subclass with @check_valid_frame
142 * and tell if they contain a valid frame
145 * Set the caps and timestamp to frame that is passed to subclass with
146 * @parse_frame function.
148 * <listitem><para>Provide conversion functions</para></listitem>
150 * Update the duration information with @gst_base_parse_set_duration
157 * - Better segment handling:
158 * - NEWSEGMENT for gaps
159 * - Not NEWSEGMENT starting at 0 but at first frame timestamp
161 * - Seek table generation and subclass seek entry injection
163 * - In push mode provide a queue of adapter-"queued" buffers for upstream
165 * - Timestamp tracking and setting
166 * - Handle upstream timestamps
167 * - Queue buffers/events until caps are set
168 * - Bitrate tracking => inaccurate seeking, inaccurate duration calculation
169 * - Let subclass decide if frames outside the segment should be dropped
170 * - Send queries upstream
180 #include "gstbaseparse.h"
182 GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug);
183 #define GST_CAT_DEFAULT gst_base_parse_debug
185 /* Supported formats */
186 static GstFormat fmtlist[] = {
193 #define GST_BASE_PARSE_GET_PRIVATE(obj) \
194 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_PARSE, GstBaseParsePrivate))
196 struct _GstBaseParsePrivate
198 GstActivateMode pad_mode;
201 GstFormat duration_fmt;
203 guint min_frame_size;
210 GList *pending_events;
215 struct _GstBaseParseClassPrivate
220 static GstElementClass *parent_class = NULL;
222 static void gst_base_parse_base_init (gpointer g_class);
223 static void gst_base_parse_base_finalize (gpointer g_class);
224 static void gst_base_parse_class_init (GstBaseParseClass * klass);
225 static void gst_base_parse_init (GstBaseParse * parse,
226 GstBaseParseClass * klass);
229 gst_base_parse_get_type (void)
231 static GType base_parse_type = 0;
233 if (!base_parse_type) {
234 static const GTypeInfo base_parse_info = {
235 sizeof (GstBaseParseClass),
236 (GBaseInitFunc) gst_base_parse_base_init,
237 (GBaseFinalizeFunc) gst_base_parse_base_finalize,
238 (GClassInitFunc) gst_base_parse_class_init,
241 sizeof (GstBaseParse),
243 (GInstanceInitFunc) gst_base_parse_init,
246 base_parse_type = g_type_register_static (GST_TYPE_ELEMENT,
247 "GstAacBaseParse", &base_parse_info, G_TYPE_FLAG_ABSTRACT);
249 return base_parse_type;
252 static void gst_base_parse_finalize (GObject * object);
254 static gboolean gst_base_parse_sink_activate (GstPad * sinkpad);
255 static gboolean gst_base_parse_sink_activate_push (GstPad * pad,
257 static gboolean gst_base_parse_sink_activate_pull (GstPad * pad,
259 static gboolean gst_base_parse_handle_seek (GstBaseParse * parse,
262 static gboolean gst_base_parse_src_event (GstPad * pad, GstEvent * event);
263 static gboolean gst_base_parse_sink_event (GstPad * pad, GstEvent * event);
264 static gboolean gst_base_parse_query (GstPad * pad, GstQuery * query);
265 static gboolean gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps);
266 static const GstQueryType *gst_base_parse_get_querytypes (GstPad * pad);
268 static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer);
269 static void gst_base_parse_loop (GstPad * pad);
271 static gboolean gst_base_parse_check_frame (GstBaseParse * parse,
272 GstBuffer * buffer, guint * framesize, gint * skipsize);
274 static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse,
277 static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse,
280 static gboolean gst_base_parse_src_eventfunc (GstBaseParse * parse,
283 static gboolean gst_base_parse_is_seekable (GstBaseParse * parse);
285 static void gst_base_parse_drain (GstBaseParse * parse);
288 gst_base_parse_base_init (gpointer g_class)
290 GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
291 GstBaseParseClassPrivate *priv;
293 GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "aacbaseparse", 0,
294 "baseparse element");
296 /* TODO: Remove this once GObject supports class private data */
297 priv = g_slice_new0 (GstBaseParseClassPrivate);
299 memcpy (priv, klass->priv, sizeof (GstBaseParseClassPrivate));
304 gst_base_parse_base_finalize (gpointer g_class)
306 GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
308 g_slice_free (GstBaseParseClassPrivate, klass->priv);
313 gst_base_parse_finalize (GObject * object)
315 GstBaseParse *parse = GST_BASE_PARSE (object);
317 g_mutex_free (parse->parse_lock);
318 g_object_unref (parse->adapter);
320 if (parse->pending_segment) {
321 gst_event_replace (&parse->pending_segment, NULL);
323 if (parse->close_segment) {
324 gst_event_replace (&parse->close_segment, NULL);
327 if (parse->priv->cache) {
328 gst_buffer_unref (parse->priv->cache);
329 parse->priv->cache = NULL;
332 g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
334 g_list_free (parse->priv->pending_events);
335 parse->priv->pending_events = NULL;
337 G_OBJECT_CLASS (parent_class)->finalize (object);
341 gst_base_parse_class_init (GstBaseParseClass * klass)
343 GObjectClass *gobject_class;
345 gobject_class = G_OBJECT_CLASS (klass);
346 g_type_class_add_private (klass, sizeof (GstBaseParsePrivate));
347 parent_class = g_type_class_peek_parent (klass);
348 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_parse_finalize);
350 /* Default handlers */
351 klass->check_valid_frame = gst_base_parse_check_frame;
352 klass->parse_frame = gst_base_parse_parse_frame;
353 klass->event = gst_base_parse_sink_eventfunc;
354 klass->src_event = gst_base_parse_src_eventfunc;
355 klass->is_seekable = gst_base_parse_is_seekable;
359 gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
361 GstPadTemplate *pad_template;
363 GST_DEBUG_OBJECT (parse, "gst_base_parse_init");
365 parse->priv = GST_BASE_PARSE_GET_PRIVATE (parse);
368 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
369 g_return_if_fail (pad_template != NULL);
370 parse->sinkpad = gst_pad_new_from_template (pad_template, "sink");
371 gst_pad_set_event_function (parse->sinkpad,
372 GST_DEBUG_FUNCPTR (gst_base_parse_sink_event));
373 gst_pad_set_setcaps_function (parse->sinkpad,
374 GST_DEBUG_FUNCPTR (gst_base_parse_sink_setcaps));
375 gst_pad_set_chain_function (parse->sinkpad,
376 GST_DEBUG_FUNCPTR (gst_base_parse_chain));
377 gst_pad_set_activate_function (parse->sinkpad,
378 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate));
379 gst_pad_set_activatepush_function (parse->sinkpad,
380 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_push));
381 gst_pad_set_activatepull_function (parse->sinkpad,
382 GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_pull));
383 gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
385 GST_DEBUG_OBJECT (parse, "sinkpad created");
388 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
389 g_return_if_fail (pad_template != NULL);
390 parse->srcpad = gst_pad_new_from_template (pad_template, "src");
391 gst_pad_set_event_function (parse->srcpad,
392 GST_DEBUG_FUNCPTR (gst_base_parse_src_event));
393 gst_pad_set_query_type_function (parse->srcpad,
394 GST_DEBUG_FUNCPTR (gst_base_parse_get_querytypes));
395 gst_pad_set_query_function (parse->srcpad,
396 GST_DEBUG_FUNCPTR (gst_base_parse_query));
397 gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
398 GST_DEBUG_OBJECT (parse, "src created");
400 parse->parse_lock = g_mutex_new ();
401 parse->adapter = gst_adapter_new ();
402 parse->pending_segment = NULL;
403 parse->close_segment = NULL;
405 parse->priv->pad_mode = GST_ACTIVATE_NONE;
406 parse->priv->duration = -1;
407 parse->priv->min_frame_size = 1;
408 parse->priv->discont = FALSE;
409 parse->priv->flushing = FALSE;
410 parse->priv->offset = 0;
411 GST_DEBUG_OBJECT (parse, "init ok");
417 * gst_base_parse_check_frame:
418 * @parse: #GstBaseParse.
419 * @buffer: GstBuffer.
420 * @framesize: This will be set to tell the found frame size in bytes.
421 * @skipsize: Output parameter that tells how much data needs to be skipped
422 * in order to find the following frame header.
424 * Default callback for check_valid_frame.
426 * Returns: Always TRUE.
429 gst_base_parse_check_frame (GstBaseParse * parse,
430 GstBuffer * buffer, guint * framesize, gint * skipsize)
432 *framesize = GST_BUFFER_SIZE (buffer);
439 * gst_base_parse_parse_frame:
440 * @parse: #GstBaseParse.
441 * @buffer: #GstBuffer.
443 * Default callback for parse_frame.
446 gst_base_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
448 /* FIXME: Could we even _try_ to do something clever here? */
449 GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
450 GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
456 * gst_base_parse_bytepos_to_time:
457 * @parse: #GstBaseParse.
458 * @bytepos: Position (in bytes) to be converted.
459 * @pos_in_time: #GstClockTime pointer where the result is set.
461 * Convert given byte position into #GstClockTime format.
463 * Returns: TRUE if conversion succeeded.
466 gst_base_parse_bytepos_to_time (GstBaseParse * parse, gint64 bytepos,
467 GstClockTime * pos_in_time)
469 GstBaseParseClass *klass;
470 gboolean res = FALSE;
472 klass = GST_BASE_PARSE_GET_CLASS (parse);
474 if (klass->convert) {
475 res = klass->convert (parse, GST_FORMAT_BYTES, bytepos,
476 GST_FORMAT_TIME, (gint64 *) pos_in_time);
483 * gst_base_parse_sink_event:
484 * @pad: #GstPad that received the event.
485 * @event: #GstEvent to be handled.
487 * Handler for sink pad events.
489 * Returns: TRUE if the event was handled.
492 gst_base_parse_sink_event (GstPad * pad, GstEvent * event)
495 GstBaseParseClass *bclass;
496 gboolean handled = FALSE;
500 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
501 bclass = GST_BASE_PARSE_GET_CLASS (parse);
503 GST_DEBUG_OBJECT (parse, "handling event %d", GST_EVENT_TYPE (event));
505 /* Cache all events except EOS, NEWSEGMENT and FLUSH_STOP if we have a
507 if (parse->pending_segment && GST_EVENT_TYPE (event) != GST_EVENT_EOS
508 && GST_EVENT_TYPE (event) != GST_EVENT_NEWSEGMENT
509 && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_START
510 && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
511 parse->priv->pending_events =
512 g_list_append (parse->priv->pending_events, event);
517 handled = bclass->event (parse, event);
520 ret = gst_pad_event_default (pad, event);
523 gst_object_unref (parse);
524 GST_DEBUG_OBJECT (parse, "event handled");
530 * gst_base_parse_sink_eventfunc:
531 * @parse: #GstBaseParse.
532 * @event: #GstEvent to be handled.
534 * Element-level event handler function.
536 * Returns: TRUE if the event was handled and not need forwarding.
539 gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event)
541 gboolean handled = FALSE;
544 switch (GST_EVENT_TYPE (event)) {
545 case GST_EVENT_NEWSEGMENT:
547 gdouble rate, applied_rate;
549 gint64 start, stop, pos, offset = 0;
552 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
553 &format, &start, &stop, &pos);
556 if (format == GST_FORMAT_BYTES) {
557 GstClockTime seg_start, seg_stop, seg_pos;
559 /* stop time is allowed to be open-ended, but not start & pos */
560 seg_stop = GST_CLOCK_TIME_NONE;
563 if (gst_base_parse_bytepos_to_time (parse, start, &seg_start) &&
564 gst_base_parse_bytepos_to_time (parse, pos, &seg_pos)) {
565 gst_event_unref (event);
566 event = gst_event_new_new_segment_full (update, rate, applied_rate,
567 GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
568 format = GST_FORMAT_TIME;
569 GST_DEBUG_OBJECT (parse, "Converted incoming segment to TIME. "
570 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
571 ", pos = %" GST_TIME_FORMAT, GST_TIME_ARGS (seg_start),
572 GST_TIME_ARGS (seg_stop), GST_TIME_ARGS (seg_pos));
576 if (format != GST_FORMAT_TIME) {
577 /* Unknown incoming segment format. Output a default open-ended
579 gst_event_unref (event);
580 event = gst_event_new_new_segment_full (update, rate, applied_rate,
581 GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0);
584 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
585 &format, &start, &stop, &pos);
587 gst_segment_set_newsegment_full (&parse->segment, update, rate,
588 applied_rate, format, start, stop, pos);
590 GST_DEBUG_OBJECT (parse, "Created newseg rate %g, applied rate %g, "
591 "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
592 ", pos = %" GST_TIME_FORMAT, rate, applied_rate, format,
593 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (pos));
595 /* save the segment for later, right before we push a new buffer so that
596 * the caps are fixed and the next linked element can receive
598 eventp = &parse->pending_segment;
599 gst_event_replace (eventp, event);
600 gst_event_unref (event);
603 /* but finish the current segment */
604 GST_DEBUG_OBJECT (parse, "draining current segment");
605 gst_base_parse_drain (parse);
606 gst_adapter_clear (parse->adapter);
607 parse->priv->offset = offset;
611 case GST_EVENT_FLUSH_START:
612 parse->priv->flushing = TRUE;
613 handled = gst_pad_push_event (parse->srcpad, event);
614 /* Wait for _chain() to exit by taking the srcpad STREAM_LOCK */
615 GST_PAD_STREAM_LOCK (parse->srcpad);
616 GST_PAD_STREAM_UNLOCK (parse->srcpad);
620 case GST_EVENT_FLUSH_STOP:
621 gst_adapter_clear (parse->adapter);
622 parse->priv->flushing = FALSE;
623 parse->priv->discont = TRUE;
627 gst_base_parse_drain (parse);
639 * gst_base_parse_src_event:
640 * @pad: #GstPad that received the event.
641 * @event: #GstEvent that was received.
643 * Handler for source pad events.
645 * Returns: TRUE if the event was handled.
648 gst_base_parse_src_event (GstPad * pad, GstEvent * event)
651 GstBaseParseClass *bclass;
652 gboolean handled = FALSE;
655 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
656 bclass = GST_BASE_PARSE_GET_CLASS (parse);
658 GST_DEBUG_OBJECT (parse, "event %d, %s", GST_EVENT_TYPE (event),
659 GST_EVENT_TYPE_NAME (event));
661 if (bclass->src_event)
662 handled = bclass->src_event (parse, event);
665 ret = gst_pad_event_default (pad, event);
667 gst_object_unref (parse);
673 * gst_base_parse_src_eventfunc:
674 * @parse: #GstBaseParse.
675 * @event: #GstEvent that was received.
677 * Default srcpad event handler.
679 * Returns: TRUE if the event was handled and can be dropped.
682 gst_base_parse_src_eventfunc (GstBaseParse * parse, GstEvent * event)
684 gboolean handled = FALSE;
685 GstBaseParseClass *bclass;
687 bclass = GST_BASE_PARSE_GET_CLASS (parse);
689 switch (GST_EVENT_TYPE (event)) {
692 if (bclass->is_seekable (parse)) {
693 handled = gst_base_parse_handle_seek (parse, event);
694 gst_event_unref (event);
706 * gst_base_parse_is_seekable:
707 * @parse: #GstBaseParse.
709 * Default handler for is_seekable.
711 * Returns: Always TRUE.
714 gst_base_parse_is_seekable (GstBaseParse * parse)
721 * gst_base_parse_handle_and_push_buffer:
722 * @parse: #GstBaseParse.
723 * @klass: #GstBaseParseClass.
724 * @buffer: #GstBuffer.
726 * Parses the frame from given buffer and pushes it forward. Also performs
727 * timestamp handling and checks the segment limits.
729 * This is called with srcpad STREAM_LOCK held.
731 * Returns: #GstFlowReturn
734 gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
735 GstBaseParseClass * klass, GstBuffer * buffer)
738 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
740 if (parse->priv->discont) {
741 GST_DEBUG_OBJECT (parse, "marking DISCONT");
742 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
743 parse->priv->discont = FALSE;
746 ret = klass->parse_frame (parse, buffer);
748 /* FIXME: Check the output buffer for any missing metadata,
749 * keep track of timestamp and calculate everything possible
750 * if not set already */
752 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
753 last_stop = GST_BUFFER_TIMESTAMP (buffer);
754 if (last_stop != GST_CLOCK_TIME_NONE && GST_BUFFER_DURATION_IS_VALID (buffer))
755 last_stop += GST_BUFFER_DURATION (buffer);
757 /* should have caps by now */
758 g_return_val_if_fail (GST_PAD_CAPS (parse->srcpad), GST_FLOW_ERROR);
760 gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
762 /* and should then also be linked downstream, so safe to send some events */
763 if (parse->priv->pad_mode == GST_ACTIVATE_PULL) {
764 if (G_UNLIKELY (parse->close_segment)) {
765 GST_DEBUG_OBJECT (parse, "loop sending close segment");
766 gst_pad_push_event (parse->srcpad, parse->close_segment);
767 parse->close_segment = NULL;
770 if (G_UNLIKELY (parse->pending_segment)) {
771 GST_DEBUG_OBJECT (parse, "loop push pending segment");
772 gst_pad_push_event (parse->srcpad, parse->pending_segment);
773 parse->pending_segment = NULL;
776 if (G_UNLIKELY (parse->pending_segment)) {
777 GST_DEBUG_OBJECT (parse, "chain pushing a pending segment");
778 gst_pad_push_event (parse->srcpad, parse->pending_segment);
779 parse->pending_segment = NULL;
783 if (G_UNLIKELY (parse->priv->pending_events)) {
786 for (l = parse->priv->pending_events; l != NULL; l = l->next) {
787 gst_pad_push_event (parse->srcpad, GST_EVENT (l->data));
789 g_list_free (parse->priv->pending_events);
790 parse->priv->pending_events = NULL;
793 /* TODO: Add to seek table */
795 if (ret == GST_FLOW_OK) {
796 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
797 GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
798 GST_BUFFER_TIMESTAMP (buffer) > parse->segment.stop) {
799 GST_LOG_OBJECT (parse, "Dropped frame, after segment");
800 gst_buffer_unref (buffer);
801 } else if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
802 GST_BUFFER_DURATION_IS_VALID (buffer) &&
803 GST_CLOCK_TIME_IS_VALID (parse->segment.start) &&
804 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer)
805 < parse->segment.start) {
806 /* FIXME: subclass needs way to override the start as downstream might
807 * need frames before for proper decoding */
808 GST_LOG_OBJECT (parse, "Dropped frame, before segment");
809 gst_buffer_unref (buffer);
811 ret = gst_pad_push (parse->srcpad, buffer);
812 GST_LOG_OBJECT (parse, "frame (%d bytes) pushed: %d",
813 GST_BUFFER_SIZE (buffer), ret);
816 gst_buffer_unref (buffer);
819 /* Update current running segment position */
820 if (ret == GST_FLOW_OK && last_stop != GST_CLOCK_TIME_NONE)
821 gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop);
823 /* convert internal flow to OK and mark discont for the next buffer. */
824 if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
825 parse->priv->discont = TRUE;
833 * gst_base_parse_drain:
834 * @parse: #GstBaseParse.
836 * Drains the adapter until it is empty. It decreases the min_frame_size to
837 * match the current adapter size and calls chain method until the adapter
838 * is emptied or chain returns with error.
841 gst_base_parse_drain (GstBaseParse * parse)
846 avail = gst_adapter_available (parse->adapter);
850 gst_base_parse_set_min_frame_size (parse, avail);
851 if (gst_base_parse_chain (parse->sinkpad, NULL) != GST_FLOW_OK) {
859 * gst_base_parse_chain:
861 * @buffer: #GstBuffer.
863 * Returns: #GstFlowReturn.
866 gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
868 GstBaseParseClass *bclass;
870 GstFlowReturn ret = GST_FLOW_OK;
871 GstBuffer *outbuf = NULL;
872 GstBuffer *tmpbuf = NULL;
878 parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad));
879 bclass = GST_BASE_PARSE_GET_CLASS (parse);
881 if (G_LIKELY (buffer)) {
882 GST_LOG_OBJECT (parse, "buffer size: %d, offset = %lld",
883 GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
884 gst_adapter_push (parse->adapter, buffer);
887 /* Parse and push as many frames as possible */
888 /* Stop either when adapter is empty or we are flushing */
889 while (!parse->priv->flushing) {
890 tmpbuf = gst_buffer_new ();
892 /* Synchronization loop */
894 GST_BASE_PARSE_LOCK (parse);
895 min_size = parse->priv->min_frame_size;
896 GST_BASE_PARSE_UNLOCK (parse);
898 /* Collect at least min_frame_size bytes */
899 if (gst_adapter_available (parse->adapter) < min_size) {
900 GST_DEBUG_OBJECT (parse, "not enough data available (only %d bytes)",
901 gst_adapter_available (parse->adapter));
902 gst_buffer_unref (tmpbuf);
906 data = gst_adapter_peek (parse->adapter, min_size);
907 GST_BUFFER_DATA (tmpbuf) = (guint8 *) data;
908 GST_BUFFER_SIZE (tmpbuf) = min_size;
909 GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset;
910 GST_BUFFER_FLAG_SET (tmpbuf, GST_MINI_OBJECT_FLAG_READONLY);
912 if (parse->priv->discont) {
913 GST_DEBUG_OBJECT (parse, "marking DISCONT");
914 GST_BUFFER_FLAG_SET (tmpbuf, GST_BUFFER_FLAG_DISCONT);
918 if (bclass->check_valid_frame (parse, tmpbuf, &fsize, &skip)) {
919 if (gst_adapter_available (parse->adapter) < fsize) {
920 GST_DEBUG_OBJECT (parse,
921 "found valid frame but not enough data available (only %d bytes)",
922 gst_adapter_available (parse->adapter));
928 GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
929 gst_adapter_flush (parse->adapter, skip);
930 parse->priv->offset += skip;
931 } else if (skip == -1) {
932 /* subclass didn't touch this value. By default we skip 1 byte */
933 GST_LOG_OBJECT (parse, "finding sync, skipping 1 byte");
934 gst_adapter_flush (parse->adapter, 1);
935 parse->priv->offset++;
937 /* There is a possibility that subclass set the skip value to zero.
938 This means that it has probably found a frame but wants to ask
939 more data (by increasing the min_size) to be sure of this. */
941 gst_buffer_unref (tmpbuf);
945 /* Subclass found the sync, but still wants to skip some data */
946 GST_LOG_OBJECT (parse, "skipping %d bytes", skip);
947 gst_adapter_flush (parse->adapter, skip);
948 parse->priv->offset += skip;
951 /* Grab lock to prevent a race with FLUSH_START handler */
952 GST_PAD_STREAM_LOCK (parse->srcpad);
954 /* FLUSH_START event causes the "flushing" flag to be set. In this
955 * case we can leave the frame pushing loop */
956 if (parse->priv->flushing) {
957 GST_PAD_STREAM_UNLOCK (parse->srcpad);
961 /* FIXME: Would it be more efficient to make a subbuffer instead? */
962 outbuf = gst_adapter_take_buffer (parse->adapter, fsize);
964 /* Subclass may want to know the data offset */
965 GST_BUFFER_OFFSET (outbuf) = parse->priv->offset;
966 parse->priv->offset += fsize;
968 ret = gst_base_parse_handle_and_push_buffer (parse, bclass, outbuf);
969 GST_PAD_STREAM_UNLOCK (parse->srcpad);
971 if (ret != GST_FLOW_OK) {
972 GST_LOG_OBJECT (parse, "push returned %d", ret);
978 GST_LOG_OBJECT (parse, "chain leaving");
983 gst_base_parse_pull_range (GstBaseParse * parse, guint size,
986 GstFlowReturn ret = GST_FLOW_OK;
988 g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
990 /* Caching here actually makes much less difference than one would expect.
991 * We do it mainly to avoid pulling buffers of 1 byte all the time */
992 if (parse->priv->cache) {
993 guint64 cache_offset = GST_BUFFER_OFFSET (parse->priv->cache);
994 guint cache_size = GST_BUFFER_SIZE (parse->priv->cache);
996 if (cache_offset <= parse->priv->offset &&
997 (parse->priv->offset + size) < (cache_offset + cache_size)) {
998 *buffer = gst_buffer_create_sub (parse->priv->cache,
999 parse->priv->offset - cache_offset, size);
1000 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1003 /* not enough data in the cache, free cache and get a new one */
1004 gst_buffer_unref (parse->priv->cache);
1005 parse->priv->cache = NULL;
1008 /* refill the cache */
1010 gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size,
1011 64 * 1024), &parse->priv->cache);
1012 if (ret != GST_FLOW_OK) {
1013 parse->priv->cache = NULL;
1017 if (GST_BUFFER_SIZE (parse->priv->cache) >= size) {
1018 *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
1019 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1023 /* Not possible to get enough data, try a last time with
1024 * requesting exactly the size we need */
1025 gst_buffer_unref (parse->priv->cache);
1026 parse->priv->cache = NULL;
1028 ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, size,
1029 &parse->priv->cache);
1031 if (ret != GST_FLOW_OK) {
1032 GST_DEBUG_OBJECT (parse, "pull_range returned %d", ret);
1037 if (GST_BUFFER_SIZE (parse->priv->cache) < size) {
1038 GST_WARNING_OBJECT (parse, "Dropping short buffer at offset %"
1039 G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", parse->priv->offset,
1040 size, GST_BUFFER_SIZE (parse->priv->cache));
1042 gst_buffer_unref (parse->priv->cache);
1043 parse->priv->cache = NULL;
1046 return GST_FLOW_UNEXPECTED;
1049 *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
1050 GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
1056 * gst_base_parse_loop:
1059 * Loop that is used in pull mode to retrieve data from upstream.
1062 gst_base_parse_loop (GstPad * pad)
1064 GstBaseParse *parse;
1065 GstBaseParseClass *klass;
1066 GstBuffer *buffer, *outbuf;
1067 gboolean ret = FALSE;
1068 guint fsize = 0, min_size;
1071 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
1072 klass = GST_BASE_PARSE_GET_CLASS (parse);
1074 /* TODO: Check if we reach segment stop limit */
1078 GST_BASE_PARSE_LOCK (parse);
1079 min_size = parse->priv->min_frame_size;
1080 GST_BASE_PARSE_UNLOCK (parse);
1082 ret = gst_base_parse_pull_range (parse, min_size, &buffer);
1084 if (ret == GST_FLOW_UNEXPECTED)
1086 else if (ret != GST_FLOW_OK)
1089 if (parse->priv->discont) {
1090 GST_DEBUG_OBJECT (parse, "marking DISCONT");
1091 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
1095 if (klass->check_valid_frame (parse, buffer, &fsize, &skip)) {
1099 GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
1100 parse->priv->offset += skip;
1101 } else if (skip == -1) {
1102 GST_LOG_OBJECT (parse, "finding sync, skipping 1 byte");
1103 parse->priv->offset++;
1105 GST_DEBUG_OBJECT (parse, "finding sync...");
1106 gst_buffer_unref (buffer);
1109 if (fsize <= GST_BUFFER_SIZE (buffer)) {
1110 outbuf = gst_buffer_create_sub (buffer, 0, fsize);
1111 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer);
1112 gst_buffer_unref (buffer);
1114 gst_buffer_unref (buffer);
1115 ret = gst_base_parse_pull_range (parse, fsize, &outbuf);
1117 if (ret == GST_FLOW_UNEXPECTED)
1119 else if (ret != GST_FLOW_OK)
1123 parse->priv->offset += fsize;
1125 /* Does the subclass want to skip too? */
1127 parse->priv->offset += skip;
1129 /* This always unrefs the outbuf, even if error occurs */
1130 ret = gst_base_parse_handle_and_push_buffer (parse, klass, outbuf);
1132 if (ret != GST_FLOW_OK) {
1133 GST_DEBUG_OBJECT (parse, "flow: %s", gst_flow_get_name (ret));
1134 if (GST_FLOW_IS_FATAL (ret)) {
1135 GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
1136 ("streaming task paused, reason: %s", gst_flow_get_name (ret)));
1137 gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1142 gst_object_unref (parse);
1147 GST_LOG_OBJECT (parse, "pausing task");
1148 gst_pad_pause_task (pad);
1149 gst_object_unref (parse);
1154 GST_LOG_OBJECT (parse, "pausing task %d", ret);
1155 gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1156 gst_pad_pause_task (pad);
1157 gst_object_unref (parse);
1164 * gst_base_parse_sink_activate:
1165 * @sinkpad: #GstPad to be activated.
1167 * Returns: TRUE if activation succeeded.
1170 gst_base_parse_sink_activate (GstPad * sinkpad)
1172 GstBaseParse *parse;
1173 gboolean result = TRUE;
1175 parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
1177 GST_DEBUG_OBJECT (parse, "sink activate");
1179 if (gst_pad_check_pull_range (sinkpad)) {
1180 GST_DEBUG_OBJECT (parse, "trying to activate in pull mode");
1181 result = gst_pad_activate_pull (sinkpad, TRUE);
1183 GST_DEBUG_OBJECT (parse, "trying to activate in push mode");
1184 result = gst_pad_activate_push (sinkpad, TRUE);
1187 GST_DEBUG_OBJECT (parse, "sink activate return %d", result);
1188 gst_object_unref (parse);
1194 * gst_base_parse_activate:
1195 * @parse: #GstBaseParse.
1196 * @active: TRUE if element will be activated, FALSE if disactivated.
1198 * Returns: TRUE if the operation succeeded.
1201 gst_base_parse_activate (GstBaseParse * parse, gboolean active)
1203 GstBaseParseClass *klass;
1204 gboolean result = FALSE;
1206 GST_DEBUG_OBJECT (parse, "activate");
1208 klass = GST_BASE_PARSE_GET_CLASS (parse);
1211 if (parse->priv->pad_mode == GST_ACTIVATE_NONE && klass->start)
1212 result = klass->start (parse);
1214 GST_OBJECT_LOCK (parse);
1215 gst_segment_init (&parse->segment, GST_FORMAT_TIME);
1216 parse->priv->duration = -1;
1217 parse->priv->discont = FALSE;
1218 parse->priv->flushing = FALSE;
1219 parse->priv->offset = 0;
1221 if (parse->pending_segment)
1222 gst_event_unref (parse->pending_segment);
1224 parse->pending_segment =
1225 gst_event_new_new_segment (FALSE, parse->segment.rate,
1226 parse->segment.format,
1227 parse->segment.start, parse->segment.stop, parse->segment.last_stop);
1229 GST_OBJECT_UNLOCK (parse);
1231 /* We must make sure streaming has finished before resetting things
1232 * and calling the ::stop vfunc */
1233 GST_PAD_STREAM_LOCK (parse->sinkpad);
1234 GST_PAD_STREAM_UNLOCK (parse->sinkpad);
1236 if (parse->priv->pad_mode != GST_ACTIVATE_NONE && klass->stop)
1237 result = klass->stop (parse);
1239 g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
1241 g_list_free (parse->priv->pending_events);
1242 parse->priv->pending_events = NULL;
1244 if (parse->priv->cache) {
1245 gst_buffer_unref (parse->priv->cache);
1246 parse->priv->cache = NULL;
1249 parse->priv->pad_mode = GST_ACTIVATE_NONE;
1251 GST_DEBUG_OBJECT (parse, "activate: %d", result);
1257 * gst_base_parse_sink_activate_push:
1258 * @pad: #GstPad to be (de)activated.
1259 * @active: TRUE when activating, FALSE when deactivating.
1261 * Returns: TRUE if (de)activation succeeded.
1264 gst_base_parse_sink_activate_push (GstPad * pad, gboolean active)
1266 gboolean result = TRUE;
1267 GstBaseParse *parse;
1269 parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
1271 GST_DEBUG_OBJECT (parse, "sink activate push");
1273 result = gst_base_parse_activate (parse, active);
1276 parse->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
1278 GST_DEBUG_OBJECT (parse, "sink activate push: %d", result);
1280 gst_object_unref (parse);
1286 * gst_base_parse_sink_activate_pull:
1287 * @sinkpad: #GstPad to be (de)activated.
1288 * @active: TRUE when activating, FALSE when deactivating.
1290 * Returns: TRUE if (de)activation succeeded.
1293 gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
1295 gboolean result = FALSE;
1296 GstBaseParse *parse;
1298 parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
1300 GST_DEBUG_OBJECT (parse, "activate pull");
1302 result = gst_base_parse_activate (parse, active);
1306 result &= gst_pad_start_task (sinkpad,
1307 (GstTaskFunction) gst_base_parse_loop, sinkpad);
1309 result &= gst_pad_stop_task (sinkpad);
1314 parse->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
1316 GST_DEBUG_OBJECT (parse, "sink activate pull: %d", result);
1318 gst_object_unref (parse);
1324 * gst_base_parse_set_duration:
1325 * @parse: #GstBaseParse.
1327 * @duration: duration value.
1329 * Sets the duration of the currently playing media. Subclass can use this
1330 * when it notices a change in the media duration.
1333 gst_base_parse_set_duration (GstBaseParse * parse,
1334 GstFormat fmt, gint64 duration)
1336 g_return_if_fail (parse != NULL);
1338 GST_BASE_PARSE_LOCK (parse);
1339 if (duration != parse->priv->duration) {
1342 m = gst_message_new_duration (GST_OBJECT (parse), fmt, duration);
1343 gst_element_post_message (GST_ELEMENT (parse), m);
1345 /* TODO: what about duration tag? */
1347 parse->priv->duration = duration;
1348 parse->priv->duration_fmt = fmt;
1349 GST_DEBUG_OBJECT (parse, "set duration: %lld", duration);
1350 GST_BASE_PARSE_UNLOCK (parse);
1355 * gst_base_parse_set_min_frame_size:
1356 * @parse: #GstBaseParse.
1357 * @min_size: Minimum size of the data that this base class should give to
1360 * Subclass can use this function to tell the base class that it needs to
1361 * give at least #min_size buffers.
1364 gst_base_parse_set_min_frame_size (GstBaseParse * parse, guint min_size)
1366 g_return_if_fail (parse != NULL);
1368 GST_BASE_PARSE_LOCK (parse);
1369 parse->priv->min_frame_size = min_size;
1370 GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size);
1371 GST_BASE_PARSE_UNLOCK (parse);
1376 * gst_base_parse_get_querytypes:
1379 * Returns: A table of #GstQueryType items describing supported query types.
1381 static const GstQueryType *
1382 gst_base_parse_get_querytypes (GstPad * pad)
1384 static const GstQueryType list[] = {
1398 * gst_base_parse_query:
1400 * @query: #GstQuery.
1402 * Returns: TRUE on success.
1405 gst_base_parse_query (GstPad * pad, GstQuery * query)
1407 GstBaseParse *parse;
1408 GstBaseParseClass *klass;
1409 gboolean res = FALSE;
1411 parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
1412 klass = GST_BASE_PARSE_GET_CLASS (parse);
1414 /* If subclass doesn't provide conversion function we can't reply
1415 to the query either */
1416 if (!klass->convert) {
1420 switch (GST_QUERY_TYPE (query)) {
1421 case GST_QUERY_POSITION:
1426 GST_DEBUG_OBJECT (parse, "position query");
1428 gst_query_parse_position (query, &format, NULL);
1430 g_mutex_lock (parse->parse_lock);
1432 if (format == GST_FORMAT_BYTES) {
1433 dest_value = parse->priv->offset;
1435 } else if (format == parse->segment.format &&
1436 GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop)) {
1437 dest_value = parse->segment.last_stop;
1440 /* priv->offset is updated in both PUSH/PULL modes */
1441 res = klass->convert (parse, GST_FORMAT_BYTES, parse->priv->offset,
1442 format, &dest_value);
1444 g_mutex_unlock (parse->parse_lock);
1447 gst_query_set_position (query, format, dest_value);
1449 res = gst_pad_query_default (pad, query);
1453 case GST_QUERY_DURATION:
1458 GST_DEBUG_OBJECT (parse, "duration query");
1460 gst_query_parse_duration (query, &format, NULL);
1462 g_mutex_lock (parse->parse_lock);
1464 if (format == GST_FORMAT_BYTES) {
1465 res = gst_pad_query_peer_duration (parse->sinkpad, &format,
1467 } else if (parse->priv->duration != -1 &&
1468 format == parse->priv->duration_fmt) {
1469 dest_value = parse->priv->duration;
1471 } else if (parse->priv->duration != -1) {
1472 res = klass->convert (parse, parse->priv->duration_fmt,
1473 parse->priv->duration, format, &dest_value);
1476 g_mutex_unlock (parse->parse_lock);
1479 gst_query_set_duration (query, format, dest_value);
1481 res = gst_pad_query_default (pad, query);
1484 case GST_QUERY_SEEKING:
1487 gboolean seekable = FALSE;
1489 GST_DEBUG_OBJECT (parse, "seeking query");
1491 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1493 if (fmt != GST_FORMAT_TIME) {
1494 return gst_pad_query_default (pad, query);
1497 seekable = klass->is_seekable (parse);
1499 /* TODO: could this duration be calculated/converted if subclass
1501 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
1502 (parse->priv->duration == -1) ?
1503 GST_CLOCK_TIME_NONE : parse->priv->duration);
1505 GST_DEBUG_OBJECT (parse, "seekable: %d", seekable);
1509 case GST_QUERY_FORMATS:
1510 gst_query_set_formatsv (query, 3, fmtlist);
1514 case GST_QUERY_CONVERT:
1516 GstFormat src_format, dest_format;
1517 gint64 src_value, dest_value;
1519 gst_query_parse_convert (query, &src_format, &src_value,
1520 &dest_format, &dest_value);
1522 /* FIXME: hm? doesn't make sense
1523 * We require all those values to be given
1524 if (src_format && src_value && dest_format && dest_value ) { */
1525 res = klass->convert (parse, src_format, src_value,
1526 dest_format, &dest_value);
1528 gst_query_set_convert (query, src_format, src_value,
1529 dest_format, dest_value);
1535 res = gst_pad_query_default (pad, query);
1543 * gst_base_parse_handle_seek:
1544 * @parse: #GstBaseParse.
1545 * @event: #GstEvent.
1547 * Returns: TRUE if seek succeeded.
1550 gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
1552 GstBaseParseClass *klass;
1556 GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
1557 gboolean flush, update, res = TRUE;
1558 gint64 cur, stop, seekpos;
1559 GstSegment seeksegment = { 0, };
1560 GstFormat dstformat;
1562 klass = GST_BASE_PARSE_GET_CLASS (parse);
1564 gst_event_parse_seek (event, &rate, &format, &flags,
1565 &cur_type, &cur, &stop_type, &stop);
1567 /* no negative rates yet */
1571 if (cur_type != GST_SEEK_TYPE_SET)
1574 /* For any format other than TIME, see if upstream handles
1575 * it directly or fail. For TIME, try upstream, but do it ourselves if
1576 * it fails upstream */
1577 if (format != GST_FORMAT_TIME) {
1578 gst_event_ref (event);
1579 return gst_pad_push_event (parse->sinkpad, event);
1581 gst_event_ref (event);
1582 if (gst_pad_push_event (parse->sinkpad, event))
1586 /* get flush flag */
1587 flush = flags & GST_SEEK_FLAG_FLUSH;
1589 dstformat = GST_FORMAT_BYTES;
1590 if (!gst_pad_query_convert (parse->srcpad, format, cur, &dstformat, &seekpos)) {
1591 GST_DEBUG_OBJECT (parse, "conversion failed");
1595 GST_DEBUG_OBJECT (parse, "seek position %lld in bytes: %lld", cur, seekpos);
1597 if (parse->priv->pad_mode == GST_ACTIVATE_PULL) {
1600 GST_DEBUG_OBJECT (parse, "seek in PULL mode");
1603 if (parse->srcpad) {
1604 GST_DEBUG_OBJECT (parse, "sending flush start");
1605 gst_pad_push_event (parse->srcpad, gst_event_new_flush_start ());
1608 gst_pad_pause_task (parse->sinkpad);
1611 /* we should now be able to grab the streaming thread because we stopped it
1612 * with the above flush/pause code */
1613 GST_PAD_STREAM_LOCK (parse->sinkpad);
1615 /* save current position */
1616 last_stop = parse->segment.last_stop;
1617 GST_DEBUG_OBJECT (parse, "stopped streaming at %" G_GINT64_FORMAT,
1620 /* copy segment, we need this because we still need the old
1621 * segment when we close the current segment. */
1622 memcpy (&seeksegment, &parse->segment, sizeof (GstSegment));
1624 GST_DEBUG_OBJECT (parse, "configuring seek");
1625 gst_segment_set_seek (&seeksegment, rate, format, flags,
1626 cur_type, cur, stop_type, stop, &update);
1628 /* figure out the last position we need to play. If it's configured (stop !=
1629 * -1), use that, else we play until the total duration of the file */
1630 if ((stop = seeksegment.stop) == -1)
1631 stop = seeksegment.duration;
1633 parse->priv->offset = seekpos;
1635 /* prepare for streaming again */
1637 GST_DEBUG_OBJECT (parse, "sending flush stop");
1638 gst_pad_push_event (parse->srcpad, gst_event_new_flush_stop ());
1640 if (parse->close_segment)
1641 gst_event_unref (parse->close_segment);
1643 parse->close_segment = gst_event_new_new_segment (TRUE,
1644 parse->segment.rate, parse->segment.format,
1645 parse->segment.accum, parse->segment.last_stop, parse->segment.accum);
1647 /* keep track of our last_stop */
1648 seeksegment.accum = parse->segment.last_stop;
1650 GST_DEBUG_OBJECT (parse, "Created close seg format %d, "
1651 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
1652 ", pos = %" GST_TIME_FORMAT, format,
1653 GST_TIME_ARGS (parse->segment.accum),
1654 GST_TIME_ARGS (parse->segment.last_stop),
1655 GST_TIME_ARGS (parse->segment.accum));
1658 memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));
1660 /* store the newsegment event so it can be sent from the streaming thread. */
1661 if (parse->pending_segment)
1662 gst_event_unref (parse->pending_segment);
1664 /* This will be sent later in _loop() */
1665 parse->pending_segment =
1666 gst_event_new_new_segment (FALSE, parse->segment.rate,
1667 parse->segment.format,
1668 parse->segment.last_stop, stop, parse->segment.last_stop);
1670 GST_DEBUG_OBJECT (parse, "Created newseg format %d, "
1671 "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
1672 ", pos = %" GST_TIME_FORMAT, format,
1673 GST_TIME_ARGS (parse->segment.last_stop),
1674 GST_TIME_ARGS (stop), GST_TIME_ARGS (parse->segment.last_stop));
1676 /* mark discont if we are going to stream from another position. */
1677 if (last_stop != parse->segment.last_stop) {
1678 GST_DEBUG_OBJECT (parse,
1679 "mark DISCONT, we did a seek to another position");
1680 parse->priv->discont = TRUE;
1683 /* Start streaming thread if paused */
1684 gst_pad_start_task (parse->sinkpad,
1685 (GstTaskFunction) gst_base_parse_loop, parse->sinkpad);
1687 GST_PAD_STREAM_UNLOCK (parse->sinkpad);
1689 GstEvent *new_event;
1690 /* The only thing we need to do in PUSH-mode is to send the
1691 seek event (in bytes) to upstream. Segment / flush handling happens
1692 in corresponding src event handlers */
1693 GST_DEBUG_OBJECT (parse, "seek in PUSH mode");
1694 new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flush,
1695 GST_SEEK_TYPE_SET, seekpos, stop_type, stop);
1697 res = gst_pad_push_event (parse->sinkpad, new_event);
1706 GST_DEBUG_OBJECT (parse, "negative playback rates are not supported yet.");
1712 GST_DEBUG_OBJECT (parse, "unsupported seek type.");
1720 * gst_base_parse_sink_setcaps:
1724 * Returns: TRUE if caps were accepted.
1727 gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
1729 GstBaseParse *parse;
1730 GstBaseParseClass *klass;
1731 gboolean res = TRUE;
1733 parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
1734 klass = GST_BASE_PARSE_GET_CLASS (parse);
1736 GST_DEBUG_OBJECT (parse, "caps: %" GST_PTR_FORMAT, caps);
1738 if (klass->set_sink_caps)
1739 res = klass->set_sink_caps (parse, caps);
1741 parse->negotiated = res;
1742 return res && gst_pad_set_caps (pad, caps);