baseparse: Fix 'self-comparison always evaluates to true'
[platform/upstream/gstreamer.git] / libs / gst / base / gstbaseparse.c
1 /* GStreamer
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>.
5  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
6  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gstbaseparse
26  * @short_description: Base class for stream parsers
27  * @see_also: #GstBaseTransform
28  *
29  * This base class is for parser elements that process data and splits it
30  * into separate audio/video/whatever frames.
31  *
32  * It provides for:
33  * <itemizedlist>
34  *   <listitem><para>provides one sink pad and one source pad</para></listitem>
35  *   <listitem><para>handles state changes</para></listitem>
36  *   <listitem><para>can operate in pull mode or push mode</para></listitem>
37  *   <listitem><para>handles seeking in both modes</para></listitem>
38  *   <listitem><para>handles events (NEWSEGMENT/EOS/FLUSH)</para></listitem>
39  *   <listitem><para>
40  *        handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT)
41  *   </para></listitem>
42  *   <listitem><para>handles flushing</para></listitem>
43  * </itemizedlist>
44  *
45  * The purpose of this base class is to provide the basic functionality of
46  * a parser and share a lot of rather complex code.
47  *
48  * Description of the parsing mechanism:
49  * <orderedlist>
50  * <listitem>
51  *   <itemizedlist><title>Set-up phase</title>
52  *   <listitem><para>
53  *     GstBaseParse class calls @set_sink_caps to inform the subclass about
54  *     incoming sinkpad caps. Subclass should set the srcpad caps accordingly.
55  *   </para></listitem>
56  *   <listitem><para>
57  *     GstBaseParse calls @start to inform subclass that data processing is
58  *     about to start now.
59  *   </para></listitem>
60  *   <listitem><para>
61  *      At least at this point subclass needs to tell the GstBaseParse class
62  *      how big data chunks it wants to receive (min_frame_size). It can do
63  *      this with gst_base_parse_set_min_frame_size().
64  *   </para></listitem>
65  *   <listitem><para>
66  *      GstBaseParse class sets up appropriate data passing mode (pull/push)
67  *      and starts to process the data.
68  *   </para></listitem>
69  *   </itemizedlist>
70  * </listitem>
71  * <listitem>
72  *   <itemizedlist>
73  *   <title>Parsing phase</title>
74  *     <listitem><para>
75  *       GstBaseParse gathers at least min_frame_size bytes of data either
76  *       by pulling it from upstream or collecting buffers in an internal
77  *       #GstAdapter.
78  *     </para></listitem>
79  *     <listitem><para>
80  *       A buffer of (at least) min_frame_size bytes is passed to subclass with
81  *       @check_valid_frame. Subclass checks the contents and returns TRUE
82  *       if the buffer contains a valid frame. It also needs to set the
83  *       @framesize according to the detected frame size. If buffer didn't
84  *       contain a valid frame, this call must return FALSE and optionally
85  *       set the @skipsize value to inform base class that how many bytes
86  *       it needs to skip in order to find a valid frame. @framesize can always
87  *       indicate a new minimum for current frame parsing.  Indicating G_MAXUINT
88  *       for requested amount means subclass simply needs best available
89  *       subsequent data.  In push mode this amounts to an additional input buffer
90  *       (thus minimal additional latency), in pull mode this amounts to some
91  *       arbitrary reasonable buffer size increase.  The passed buffer
92  *       is read-only.  Note that @check_valid_frame might receive any small
93  *       amount of input data when leftover data is being drained (e.g. at EOS).
94  *     </para></listitem>
95  *     <listitem><para>
96  *       After valid frame is found, it will be passed again to subclass with
97  *       @parse_frame call. Now subclass is responsible for parsing the
98  *       frame contents and setting the caps, and buffer metadata (e.g.
99  *       buffer timestamp and duration, or keyframe if applicable).
100  *       (although the latter can also be done by GstBaseParse if it is
101  *       appropriately configured, see below).  Frame is provided with
102  *       timestamp derived from upstream (as much as generally possible),
103  *       duration obtained from configuration (see below), and offset
104  *       if meaningful (in pull mode).
105  *     </para></listitem>
106  *     <listitem><para>
107  *       Finally the buffer can be pushed downstream and the parsing loop starts
108  *       over again.  Just prior to actually pushing the buffer in question,
109  *       it is passed to @pre_push_frame which gives subclass yet one
110  *       last chance to examine buffer metadata, or to send some custom (tag)
111  *       events, or to perform custom (segment) filtering.
112  *     </para></listitem>
113  *     <listitem><para>
114  *       During the parsing process GstBaseParseClass will handle both srcpad
115  *       and sinkpad events. They will be passed to subclass if @event or
116  *       @src_event callbacks have been provided.
117  *     </para></listitem>
118  *   </itemizedlist>
119  * </listitem>
120  * <listitem>
121  *   <itemizedlist><title>Shutdown phase</title>
122  *   <listitem><para>
123  *     GstBaseParse class calls @stop to inform the subclass that data
124  *     parsing will be stopped.
125  *   </para></listitem>
126  *   </itemizedlist>
127  * </listitem>
128  * </orderedlist>
129  *
130  * Subclass is responsible for providing pad template caps for
131  * source and sink pads. The pads need to be named "sink" and "src". It also
132  * needs to set the fixed caps on srcpad, when the format is ensured (e.g.
133  * when base class calls subclass' @set_sink_caps function).
134  *
135  * This base class uses #GST_FORMAT_DEFAULT as a meaning of frames. So,
136  * subclass conversion routine needs to know that conversion from
137  * #GST_FORMAT_TIME to #GST_FORMAT_DEFAULT must return the
138  * frame number that can be found from the given byte position.
139  *
140  * GstBaseParse uses subclasses conversion methods also for seeking (or
141  * otherwise uses its own default one, see also below).
142  *
143  * Subclass @start and @stop functions will be called to inform the beginning
144  * and end of data processing.
145  *
146  * Things that subclass need to take care of:
147  * <itemizedlist>
148  *   <listitem><para>Provide pad templates</para></listitem>
149  *   <listitem><para>
150  *      Fixate the source pad caps when appropriate
151  *   </para></listitem>
152  *   <listitem><para>
153  *      Inform base class how big data chunks should be retrieved. This is
154  *      done with gst_base_parse_set_min_frame_size() function.
155  *   </para></listitem>
156  *   <listitem><para>
157  *      Examine data chunks passed to subclass with @check_valid_frame
158  *      and tell if they contain a valid frame
159  *   </para></listitem>
160  *   <listitem><para>
161  *      Set the caps and timestamp to frame that is passed to subclass with
162  *      @parse_frame function.
163  *   </para></listitem>
164  *   <listitem><para>Provide conversion functions</para></listitem>
165  *   <listitem><para>
166  *      Update the duration information with gst_base_parse_set_duration()
167  *   </para></listitem>
168  *   <listitem><para>
169  *      Optionally passthrough using gst_base_parse_set_passthrough()
170  *   </para></listitem>
171  *   <listitem><para>
172  *      Configure various baseparse parameters using
173  *      gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable()
174  *      and gst_base_parse_set_frame_rate().
175  *   </para></listitem>
176  *   <listitem><para>
177  *      In particular, if subclass is unable to determine a duration, but
178  *      parsing (or specs) yields a frames per seconds rate, then this can be
179  *      provided to GstBaseParse to enable it to cater for
180  *      buffer time metadata (which will be taken from upstream as much as
181  *      possible). Internally keeping track of frame durations and respective
182  *      sizes that have been pushed provides GstBaseParse with an estimated
183  *      bitrate. A default @convert (used if not overriden) will then use these
184  *      rates to perform obvious conversions.  These rates are also used to
185  *      update (estimated) duration at regular frame intervals.
186  *   </para></listitem>
187  * </itemizedlist>
188  *
189  */
190
191 /* TODO:
192  *  - In push mode provide a queue of adapter-"queued" buffers for upstream
193  *    buffer metadata
194  *  - Queue buffers/events until caps are set
195  */
196
197 #ifdef HAVE_CONFIG_H
198 #  include "config.h"
199 #endif
200
201 #include <stdlib.h>
202 #include <string.h>
203
204 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
205  * with newer GLib versions (>= 2.31.0) */
206 #define GLIB_DISABLE_DEPRECATION_WARNINGS
207 #include <gst/base/gstadapter.h>
208
209 #include "gstbaseparse.h"
210
211 #define GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC  (1 << 0)
212
213 #define MIN_FRAMES_TO_POST_BITRATE 10
214 #define TARGET_DIFFERENCE          (20 * GST_SECOND)
215
216 GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug);
217 #define GST_CAT_DEFAULT gst_base_parse_debug
218
219 /* Supported formats */
220 static const GstFormat fmtlist[] = {
221   GST_FORMAT_DEFAULT,
222   GST_FORMAT_BYTES,
223   GST_FORMAT_TIME,
224   GST_FORMAT_UNDEFINED
225 };
226
227 #define GST_BASE_PARSE_GET_PRIVATE(obj)  \
228     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_PARSE, GstBaseParsePrivate))
229
230 struct _GstBaseParsePrivate
231 {
232   GstActivateMode pad_mode;
233
234   GstAdapter *adapter;
235
236   gint64 duration;
237   GstFormat duration_fmt;
238   gint64 estimated_duration;
239   gint64 estimated_drift;
240
241   guint min_frame_size;
242   gboolean passthrough;
243   gboolean syncable;
244   gboolean has_timing_info;
245   guint fps_num, fps_den;
246   gint update_interval;
247   guint bitrate;
248   guint lead_in, lead_out;
249   GstClockTime lead_in_ts, lead_out_ts;
250   GstClockTime min_latency, max_latency;
251
252   gboolean discont;
253   gboolean flushing;
254   gboolean drain;
255
256   gint64 offset;
257   gint64 sync_offset;
258   GstClockTime next_ts;
259   GstClockTime prev_ts;
260   GstClockTime frame_duration;
261   gboolean seen_keyframe;
262   gboolean is_video;
263
264   guint64 framecount;
265   guint64 bytecount;
266   guint64 data_bytecount;
267   guint64 acc_duration;
268   GstClockTime first_frame_ts;
269   gint64 first_frame_offset;
270
271   gboolean post_min_bitrate;
272   gboolean post_avg_bitrate;
273   gboolean post_max_bitrate;
274   guint min_bitrate;
275   guint avg_bitrate;
276   guint max_bitrate;
277   guint posted_avg_bitrate;
278
279   /* frames/buffers that are queued and ready to go on OK */
280   GQueue queued_frames;
281
282   GstBuffer *cache;
283
284   /* index entry storage, either ours or provided */
285   GstIndex *index;
286   gint index_id;
287   gboolean own_index;
288 #if !GLIB_CHECK_VERSION (2, 31, 0)
289   GStaticMutex index_lock;
290 #else
291   GMutex index_lock;
292 #endif
293
294   /* seek table entries only maintained if upstream is BYTE seekable */
295   gboolean upstream_seekable;
296   gboolean upstream_has_duration;
297   gint64 upstream_size;
298   /* minimum distance between two index entries */
299   GstClockTimeDiff idx_interval;
300   /* ts and offset of last entry added */
301   GstClockTime index_last_ts;
302   gint64 index_last_offset;
303   gboolean index_last_valid;
304
305   /* timestamps currently produced are accurate, e.g. started from 0 onwards */
306   gboolean exact_position;
307   /* seek events are temporarily kept to match them with newsegments */
308   GSList *pending_seeks;
309
310   /* reverse playback */
311   GSList *buffers_pending;
312   GSList *buffers_queued;
313   GSList *buffers_send;
314   GstClockTime last_ts;
315   gint64 last_offset;
316
317   /* Pending serialized events */
318   GList *pending_events;
319   /* Newsegment event to be sent after SEEK */
320   gboolean pending_segment;
321   /* Segment event that closes the running segment prior to SEEK */
322   GstEvent *close_segment;
323
324   /* push mode helper frame */
325   GstBaseParseFrame frame;
326
327   /* TRUE if we're still detecting the format, i.e.
328    * if ::detect() is still called for future buffers */
329   gboolean detecting;
330   GList *detect_buffers;
331   guint detect_buffers_size;
332 };
333
334 typedef struct _GstBaseParseSeek
335 {
336   GstSegment segment;
337   gboolean accurate;
338   gint64 offset;
339   GstClockTime start_ts;
340 } GstBaseParseSeek;
341
342 #if !GLIB_CHECK_VERSION (2, 31, 0)
343 #define GST_BASE_PARSE_INDEX_LOCK(parse) \
344   g_static_mutex_lock (&parse->priv->index_lock);
345 #define GST_BASE_PARSE_INDEX_UNLOCK(parse) \
346   g_static_mutex_unlock (&parse->priv->index_lock);
347 #else
348 #define GST_BASE_PARSE_INDEX_LOCK(parse) \
349   g_mutex_lock (&parse->priv->index_lock);
350 #define GST_BASE_PARSE_INDEX_UNLOCK(parse) \
351   g_mutex_unlock (&parse->priv->index_lock);
352 #endif
353
354 static GstElementClass *parent_class = NULL;
355
356 static void gst_base_parse_class_init (GstBaseParseClass * klass);
357 static void gst_base_parse_init (GstBaseParse * parse,
358     GstBaseParseClass * klass);
359
360 GType
361 gst_base_parse_get_type (void)
362 {
363   static volatile gsize base_parse_type = 0;
364
365   if (g_once_init_enter (&base_parse_type)) {
366     static const GTypeInfo base_parse_info = {
367       sizeof (GstBaseParseClass),
368       (GBaseInitFunc) NULL,
369       (GBaseFinalizeFunc) NULL,
370       (GClassInitFunc) gst_base_parse_class_init,
371       NULL,
372       NULL,
373       sizeof (GstBaseParse),
374       0,
375       (GInstanceInitFunc) gst_base_parse_init,
376     };
377     GType _type;
378
379     _type = g_type_register_static (GST_TYPE_ELEMENT,
380         "GstBaseParse", &base_parse_info, G_TYPE_FLAG_ABSTRACT);
381     g_once_init_leave (&base_parse_type, _type);
382   }
383   return (GType) base_parse_type;
384 }
385
386 static void gst_base_parse_finalize (GObject * object);
387
388 static GstStateChangeReturn gst_base_parse_change_state (GstElement * element,
389     GstStateChange transition);
390 static void gst_base_parse_reset (GstBaseParse * parse);
391
392 static void gst_base_parse_set_index (GstElement * element, GstIndex * index);
393 static GstIndex *gst_base_parse_get_index (GstElement * element);
394
395 static gboolean gst_base_parse_sink_activate (GstPad * sinkpad);
396 static gboolean gst_base_parse_sink_activate_push (GstPad * pad,
397     gboolean active);
398 static gboolean gst_base_parse_sink_activate_pull (GstPad * pad,
399     gboolean active);
400 static gboolean gst_base_parse_handle_seek (GstBaseParse * parse,
401     GstEvent * event);
402 static void gst_base_parse_handle_tag (GstBaseParse * parse, GstEvent * event);
403
404 static gboolean gst_base_parse_src_event (GstPad * pad, GstEvent * event);
405 static gboolean gst_base_parse_sink_event (GstPad * pad, GstEvent * event);
406 static gboolean gst_base_parse_query (GstPad * pad, GstQuery * query);
407 static gboolean gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps);
408 static GstCaps *gst_base_parse_sink_getcaps (GstPad * pad);
409 static const GstQueryType *gst_base_parse_get_querytypes (GstPad * pad);
410
411 static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer);
412 static void gst_base_parse_loop (GstPad * pad);
413
414 static gboolean gst_base_parse_check_frame (GstBaseParse * parse,
415     GstBaseParseFrame * frame, guint * framesize, gint * skipsize);
416 static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse,
417     GstBaseParseFrame * frame);
418
419 static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse,
420     GstEvent * event);
421
422 static gboolean gst_base_parse_src_eventfunc (GstBaseParse * parse,
423     GstEvent * event);
424
425 static void gst_base_parse_drain (GstBaseParse * parse);
426
427 static void gst_base_parse_post_bitrates (GstBaseParse * parse,
428     gboolean post_min, gboolean post_avg, gboolean post_max);
429
430 static gint64 gst_base_parse_find_offset (GstBaseParse * parse,
431     GstClockTime time, gboolean before, GstClockTime * _ts);
432 static GstFlowReturn gst_base_parse_locate_time (GstBaseParse * parse,
433     GstClockTime * _time, gint64 * _offset);
434
435 static GstFlowReturn gst_base_parse_process_fragment (GstBaseParse * parse,
436     gboolean push_only);
437
438 static gboolean gst_base_parse_is_seekable (GstBaseParse * parse);
439
440 static void
441 gst_base_parse_clear_queues (GstBaseParse * parse)
442 {
443   g_slist_foreach (parse->priv->buffers_queued, (GFunc) gst_buffer_unref, NULL);
444   g_slist_free (parse->priv->buffers_queued);
445   parse->priv->buffers_queued = NULL;
446   g_slist_foreach (parse->priv->buffers_pending, (GFunc) gst_buffer_unref,
447       NULL);
448   g_slist_free (parse->priv->buffers_pending);
449   parse->priv->buffers_pending = NULL;
450   g_slist_foreach (parse->priv->buffers_send, (GFunc) gst_buffer_unref, NULL);
451   g_slist_free (parse->priv->buffers_send);
452   parse->priv->buffers_send = NULL;
453
454   g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref, NULL);
455   g_list_free (parse->priv->detect_buffers);
456   parse->priv->detect_buffers = NULL;
457   parse->priv->detect_buffers_size = 0;
458
459   g_queue_foreach (&parse->priv->queued_frames,
460       (GFunc) gst_base_parse_frame_free, NULL);
461   g_queue_clear (&parse->priv->queued_frames);
462
463   gst_buffer_replace (&parse->priv->cache, NULL);
464
465   g_list_foreach (parse->priv->pending_events, (GFunc) gst_event_unref, NULL);
466   g_list_free (parse->priv->pending_events);
467   parse->priv->pending_events = NULL;
468   parse->priv->pending_segment = FALSE;
469
470   gst_event_replace (&parse->priv->close_segment, NULL);
471 }
472
473 static void
474 gst_base_parse_finalize (GObject * object)
475 {
476   GstBaseParse *parse = GST_BASE_PARSE (object);
477   GstEvent **p_ev;
478
479   g_object_unref (parse->priv->adapter);
480
481   if (parse->priv->close_segment) {
482     p_ev = &parse->priv->close_segment;
483     gst_event_replace (p_ev, NULL);
484   }
485
486   if (parse->priv->cache) {
487     gst_buffer_unref (parse->priv->cache);
488     parse->priv->cache = NULL;
489   }
490
491   g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
492       NULL);
493   g_list_free (parse->priv->pending_events);
494   parse->priv->pending_events = NULL;
495   parse->priv->pending_segment = FALSE;
496
497   if (parse->priv->index) {
498     gst_object_unref (parse->priv->index);
499     parse->priv->index = NULL;
500   }
501 #if !GLIB_CHECK_VERSION (2, 31, 0)
502   g_static_mutex_free (&parse->priv->index_lock);
503 #else
504   g_mutex_clear (&parse->priv->index_lock);
505 #endif
506
507   gst_base_parse_clear_queues (parse);
508
509   G_OBJECT_CLASS (parent_class)->finalize (object);
510 }
511
512 static void
513 gst_base_parse_class_init (GstBaseParseClass * klass)
514 {
515   GObjectClass *gobject_class;
516   GstElementClass *gstelement_class;
517
518   gobject_class = G_OBJECT_CLASS (klass);
519   g_type_class_add_private (klass, sizeof (GstBaseParsePrivate));
520   parent_class = g_type_class_peek_parent (klass);
521   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_parse_finalize);
522
523   gstelement_class = (GstElementClass *) klass;
524   gstelement_class->change_state =
525       GST_DEBUG_FUNCPTR (gst_base_parse_change_state);
526   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_base_parse_set_index);
527   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_base_parse_get_index);
528
529   /* Default handlers */
530   klass->check_valid_frame = gst_base_parse_check_frame;
531   klass->parse_frame = gst_base_parse_parse_frame;
532   klass->src_event = gst_base_parse_src_eventfunc;
533   klass->convert = gst_base_parse_convert_default;
534
535   GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "baseparse", 0,
536       "baseparse element");
537 }
538
539 static void
540 gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
541 {
542   GstPadTemplate *pad_template;
543
544   GST_DEBUG_OBJECT (parse, "gst_base_parse_init");
545
546   parse->priv = GST_BASE_PARSE_GET_PRIVATE (parse);
547
548   pad_template =
549       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
550   g_return_if_fail (pad_template != NULL);
551   parse->sinkpad = gst_pad_new_from_template (pad_template, "sink");
552   gst_pad_set_event_function (parse->sinkpad,
553       GST_DEBUG_FUNCPTR (gst_base_parse_sink_event));
554   gst_pad_set_setcaps_function (parse->sinkpad,
555       GST_DEBUG_FUNCPTR (gst_base_parse_sink_setcaps));
556   gst_pad_set_getcaps_function (parse->sinkpad,
557       GST_DEBUG_FUNCPTR (gst_base_parse_sink_getcaps));
558   gst_pad_set_chain_function (parse->sinkpad,
559       GST_DEBUG_FUNCPTR (gst_base_parse_chain));
560   gst_pad_set_activate_function (parse->sinkpad,
561       GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate));
562   gst_pad_set_activatepush_function (parse->sinkpad,
563       GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_push));
564   gst_pad_set_activatepull_function (parse->sinkpad,
565       GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_pull));
566   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
567
568   GST_DEBUG_OBJECT (parse, "sinkpad created");
569
570   pad_template =
571       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
572   g_return_if_fail (pad_template != NULL);
573   parse->srcpad = gst_pad_new_from_template (pad_template, "src");
574   gst_pad_set_event_function (parse->srcpad,
575       GST_DEBUG_FUNCPTR (gst_base_parse_src_event));
576   gst_pad_set_query_type_function (parse->srcpad,
577       GST_DEBUG_FUNCPTR (gst_base_parse_get_querytypes));
578   gst_pad_set_query_function (parse->srcpad,
579       GST_DEBUG_FUNCPTR (gst_base_parse_query));
580   gst_pad_use_fixed_caps (parse->srcpad);
581   gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
582   GST_DEBUG_OBJECT (parse, "src created");
583
584   g_queue_init (&parse->priv->queued_frames);
585
586   parse->priv->adapter = gst_adapter_new ();
587
588   parse->priv->pad_mode = GST_ACTIVATE_NONE;
589
590 #if !GLIB_CHECK_VERSION (2, 31, 0)
591   g_static_mutex_init (&parse->priv->index_lock);
592 #else
593   g_mutex_init (&parse->priv->index_lock);
594 #endif
595
596   /* init state */
597   gst_base_parse_reset (parse);
598   GST_DEBUG_OBJECT (parse, "init ok");
599 }
600
601 static GstBaseParseFrame *
602 gst_base_parse_frame_copy (GstBaseParseFrame * frame)
603 {
604   GstBaseParseFrame *copy;
605
606   copy = g_slice_dup (GstBaseParseFrame, frame);
607   copy->buffer = gst_buffer_ref (frame->buffer);
608   copy->_private_flags &= ~GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
609
610   GST_TRACE ("copied frame %p -> %p", frame, copy);
611
612   return copy;
613 }
614
615 void
616 gst_base_parse_frame_free (GstBaseParseFrame * frame)
617 {
618   GST_TRACE ("freeing frame %p", frame);
619
620   if (frame->buffer) {
621     gst_buffer_unref (frame->buffer);
622     frame->buffer = NULL;
623   }
624
625   if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) {
626     g_slice_free (GstBaseParseFrame, frame);
627   } else {
628     memset (frame, 0, sizeof (*frame));
629   }
630 }
631
632 GType
633 gst_base_parse_frame_get_type (void)
634 {
635   static volatile gsize frame_type = 0;
636
637   if (g_once_init_enter (&frame_type)) {
638     GType _type;
639
640     _type = g_boxed_type_register_static ("GstBaseParseFrame",
641         (GBoxedCopyFunc) gst_base_parse_frame_copy,
642         (GBoxedFreeFunc) gst_base_parse_frame_free);
643     g_once_init_leave (&frame_type, _type);
644   }
645   return (GType) frame_type;
646 }
647
648 /**
649  * gst_base_parse_frame_init:
650  * @frame: #GstBaseParseFrame.
651  *
652  * Sets a #GstBaseParseFrame to initial state.  Currently this means
653  * all public fields are zero-ed and a private flag is set to make
654  * sure gst_base_parse_frame_free() only frees the contents but not
655  * the actual frame. Use this function to initialise a #GstBaseParseFrame
656  * allocated on the stack.
657  *
658  * Since: 0.10.33
659  */
660 void
661 gst_base_parse_frame_init (GstBaseParseFrame * frame)
662 {
663   memset (frame, 0, sizeof (GstBaseParseFrame));
664   frame->_private_flags = GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
665   GST_TRACE ("inited frame %p", frame);
666 }
667
668 /**
669  * gst_base_parse_frame_new:
670  * @buffer: (transfer none): a #GstBuffer
671  * @flags: the flags
672  * @overhead: number of bytes in this frame which should be counted as
673  *     metadata overhead, ie. not used to calculate the average bitrate.
674  *     Set to -1 to mark the entire frame as metadata. If in doubt, set to 0.
675  *
676  * Allocates a new #GstBaseParseFrame. This function is mainly for bindings,
677  * elements written in C should usually allocate the frame on the stack and
678  * then use gst_base_parse_frame_init() to initialise it.
679  *
680  * Returns: a newly-allocated #GstBaseParseFrame. Free with
681  *     gst_base_parse_frame_free() when no longer needed, unless you gave
682  *     away ownership to gst_base_parse_push_frame().
683  *
684  * Since: 0.10.33
685  */
686 GstBaseParseFrame *
687 gst_base_parse_frame_new (GstBuffer * buffer, GstBaseParseFrameFlags flags,
688     gint overhead)
689 {
690   GstBaseParseFrame *frame;
691
692   frame = g_slice_new0 (GstBaseParseFrame);
693   frame->buffer = gst_buffer_ref (buffer);
694
695   GST_TRACE ("created frame %p", frame);
696   return frame;
697 }
698
699 static inline void
700 gst_base_parse_frame_update (GstBaseParse * parse, GstBaseParseFrame * frame,
701     GstBuffer * buf)
702 {
703   gst_buffer_replace (&frame->buffer, buf);
704
705   parse->flags = 0;
706
707   /* set flags one by one for clarity */
708   if (G_UNLIKELY (parse->priv->drain))
709     parse->flags |= GST_BASE_PARSE_FLAG_DRAINING;
710
711   /* losing sync is pretty much a discont (and vice versa), no ? */
712   if (G_UNLIKELY (parse->priv->discont))
713     parse->flags |= GST_BASE_PARSE_FLAG_LOST_SYNC;
714 }
715
716 static void
717 gst_base_parse_reset (GstBaseParse * parse)
718 {
719   GST_OBJECT_LOCK (parse);
720   gst_segment_init (&parse->segment, GST_FORMAT_TIME);
721   parse->priv->duration = -1;
722   parse->priv->min_frame_size = 1;
723   parse->priv->discont = TRUE;
724   parse->priv->flushing = FALSE;
725   parse->priv->offset = 0;
726   parse->priv->sync_offset = 0;
727   parse->priv->update_interval = -1;
728   parse->priv->fps_num = parse->priv->fps_den = 0;
729   parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
730   parse->priv->lead_in = parse->priv->lead_out = 0;
731   parse->priv->lead_in_ts = parse->priv->lead_out_ts = 0;
732   parse->priv->bitrate = 0;
733   parse->priv->framecount = 0;
734   parse->priv->bytecount = 0;
735   parse->priv->acc_duration = 0;
736   parse->priv->first_frame_ts = GST_CLOCK_TIME_NONE;
737   parse->priv->first_frame_offset = -1;
738   parse->priv->estimated_duration = -1;
739   parse->priv->estimated_drift = 0;
740   parse->priv->next_ts = 0;
741   parse->priv->syncable = TRUE;
742   parse->priv->passthrough = FALSE;
743   parse->priv->has_timing_info = FALSE;
744   parse->priv->post_min_bitrate = TRUE;
745   parse->priv->post_avg_bitrate = TRUE;
746   parse->priv->post_max_bitrate = TRUE;
747   parse->priv->min_bitrate = G_MAXUINT;
748   parse->priv->max_bitrate = 0;
749   parse->priv->avg_bitrate = 0;
750   parse->priv->posted_avg_bitrate = 0;
751
752   parse->priv->index_last_ts = GST_CLOCK_TIME_NONE;
753   parse->priv->index_last_offset = -1;
754   parse->priv->index_last_valid = TRUE;
755   parse->priv->upstream_seekable = FALSE;
756   parse->priv->upstream_size = 0;
757   parse->priv->upstream_has_duration = FALSE;
758   parse->priv->idx_interval = 0;
759   parse->priv->exact_position = TRUE;
760   parse->priv->seen_keyframe = FALSE;
761
762   parse->priv->last_ts = GST_CLOCK_TIME_NONE;
763   parse->priv->last_offset = 0;
764
765   g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
766       NULL);
767   g_list_free (parse->priv->pending_events);
768   parse->priv->pending_events = NULL;
769   parse->priv->pending_segment = FALSE;
770
771   gst_event_replace (&parse->priv->close_segment, NULL);
772
773   if (parse->priv->cache) {
774     gst_buffer_unref (parse->priv->cache);
775     parse->priv->cache = NULL;
776   }
777
778   g_slist_foreach (parse->priv->pending_seeks, (GFunc) g_free, NULL);
779   g_slist_free (parse->priv->pending_seeks);
780   parse->priv->pending_seeks = NULL;
781
782   if (parse->priv->adapter)
783     gst_adapter_clear (parse->priv->adapter);
784
785   /* we know it is not alloc'ed, but maybe other stuff to free, some day ... */
786   parse->priv->frame._private_flags |=
787       GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
788   gst_base_parse_frame_free (&parse->priv->frame);
789
790   g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref, NULL);
791   g_list_free (parse->priv->detect_buffers);
792   parse->priv->detect_buffers = NULL;
793   parse->priv->detect_buffers_size = 0;
794   GST_OBJECT_UNLOCK (parse);
795 }
796
797 /* gst_base_parse_check_frame:
798  * @parse: #GstBaseParse.
799  * @buffer: GstBuffer.
800  * @framesize: This will be set to tell the found frame size in bytes.
801  * @skipsize: Output parameter that tells how much data needs to be skipped
802  *            in order to find the following frame header.
803  *
804  * Default callback for check_valid_frame.
805  *
806  * Returns: Always TRUE.
807  */
808 static gboolean
809 gst_base_parse_check_frame (GstBaseParse * parse,
810     GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
811 {
812   *framesize = GST_BUFFER_SIZE (frame->buffer);
813   *skipsize = 0;
814   return TRUE;
815 }
816
817
818 /* gst_base_parse_parse_frame:
819  * @parse: #GstBaseParse.
820  * @buffer: #GstBuffer.
821  *
822  * Default callback for parse_frame.
823  */
824 static GstFlowReturn
825 gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
826 {
827   GstBuffer *buffer = frame->buffer;
828
829   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
830       GST_CLOCK_TIME_IS_VALID (parse->priv->next_ts)) {
831     GST_BUFFER_TIMESTAMP (buffer) = parse->priv->next_ts;
832   }
833   if (!GST_BUFFER_DURATION_IS_VALID (buffer) &&
834       GST_CLOCK_TIME_IS_VALID (parse->priv->frame_duration)) {
835     GST_BUFFER_DURATION (buffer) = parse->priv->frame_duration;
836   }
837   return GST_FLOW_OK;
838 }
839
840 /* gst_base_parse_convert:
841  * @parse: #GstBaseParse.
842  * @src_format: #GstFormat describing the source format.
843  * @src_value: Source value to be converted.
844  * @dest_format: #GstFormat defining the converted format.
845  * @dest_value: Pointer where the conversion result will be put.
846  *
847  * Converts using configured "convert" vmethod in #GstBaseParse class.
848  *
849  * Returns: TRUE if conversion was successful.
850  */
851 static gboolean
852 gst_base_parse_convert (GstBaseParse * parse,
853     GstFormat src_format,
854     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
855 {
856   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
857   gboolean ret;
858
859   g_return_val_if_fail (dest_value != NULL, FALSE);
860
861   if (!klass->convert)
862     return FALSE;
863
864   ret = klass->convert (parse, src_format, src_value, dest_format, dest_value);
865
866 #ifndef GST_DISABLE_GST_DEBUG
867   {
868     if (ret) {
869       if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
870         GST_LOG_OBJECT (parse,
871             "TIME -> BYTES: %" GST_TIME_FORMAT " -> %" G_GINT64_FORMAT,
872             GST_TIME_ARGS (src_value), *dest_value);
873       } else if (dest_format == GST_FORMAT_TIME &&
874           src_format == GST_FORMAT_BYTES) {
875         GST_LOG_OBJECT (parse,
876             "BYTES -> TIME: %" G_GINT64_FORMAT " -> %" GST_TIME_FORMAT,
877             src_value, GST_TIME_ARGS (*dest_value));
878       } else {
879         GST_LOG_OBJECT (parse,
880             "%s -> %s: %" G_GINT64_FORMAT " -> %" G_GINT64_FORMAT,
881             GST_STR_NULL (gst_format_get_name (src_format)),
882             GST_STR_NULL (gst_format_get_name (dest_format)),
883             src_value, *dest_value);
884       }
885     } else {
886       GST_DEBUG_OBJECT (parse, "conversion failed");
887     }
888   }
889 #endif
890
891   return ret;
892 }
893
894 /* gst_base_parse_sink_event:
895  * @pad: #GstPad that received the event.
896  * @event: #GstEvent to be handled.
897  *
898  * Handler for sink pad events.
899  *
900  * Returns: TRUE if the event was handled.
901  */
902 static gboolean
903 gst_base_parse_sink_event (GstPad * pad, GstEvent * event)
904 {
905   GstBaseParse *parse;
906   GstBaseParseClass *bclass;
907   gboolean handled = FALSE;
908   gboolean ret = TRUE;
909
910   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
911   bclass = GST_BASE_PARSE_GET_CLASS (parse);
912
913   GST_DEBUG_OBJECT (parse, "handling event %d, %s", GST_EVENT_TYPE (event),
914       GST_EVENT_TYPE_NAME (event));
915
916   /* Cache all serialized events except EOS, NEWSEGMENT and FLUSH_STOP if we have a
917    * pending segment */
918   if (parse->priv->pending_segment && GST_EVENT_IS_SERIALIZED (event)
919       && GST_EVENT_TYPE (event) != GST_EVENT_EOS
920       && GST_EVENT_TYPE (event) != GST_EVENT_NEWSEGMENT
921       && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_START
922       && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
923
924     if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
925       /* See if any bitrate tags were posted */
926       gst_base_parse_handle_tag (parse, event);
927
928     parse->priv->pending_events =
929         g_list_append (parse->priv->pending_events, event);
930     ret = TRUE;
931   } else {
932     if (GST_EVENT_TYPE (event) == GST_EVENT_EOS &&
933         parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE)
934       /* We've not posted bitrate tags yet - do so now */
935       gst_base_parse_post_bitrates (parse, TRUE, TRUE, TRUE);
936
937     if (bclass->event)
938       handled = bclass->event (parse, event);
939
940     if (!handled)
941       handled = gst_base_parse_sink_eventfunc (parse, event);
942
943     if (!handled)
944       ret = gst_pad_event_default (pad, event);
945   }
946
947   gst_object_unref (parse);
948   GST_DEBUG_OBJECT (parse, "event handled");
949   return ret;
950 }
951
952
953 /* gst_base_parse_sink_eventfunc:
954  * @parse: #GstBaseParse.
955  * @event: #GstEvent to be handled.
956  *
957  * Element-level event handler function.
958  *
959  * The event will be unreffed only if it has been handled and this
960  * function returns %TRUE
961  *
962  * Returns: %TRUE if the event was handled and not need forwarding.
963  */
964 static gboolean
965 gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event)
966 {
967   gboolean handled = FALSE;
968
969   switch (GST_EVENT_TYPE (event)) {
970     case GST_EVENT_NEWSEGMENT:
971     {
972       gdouble rate, applied_rate;
973       GstFormat format;
974       gint64 start, stop, pos, next_ts, offset = 0;
975       gboolean update;
976
977       gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
978           &format, &start, &stop, &pos);
979
980       GST_DEBUG_OBJECT (parse, "newseg rate %g, applied rate %g, "
981           "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
982           ", pos = %" GST_TIME_FORMAT, rate, applied_rate, format,
983           GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (pos));
984
985       if (format == GST_FORMAT_BYTES) {
986         GstClockTime seg_start, seg_stop;
987         GstBaseParseSeek *seek = NULL;
988         GSList *node;
989
990         /* stop time is allowed to be open-ended, but not start & pos */
991         seg_stop = GST_CLOCK_TIME_NONE;
992         seg_start = 0;
993         offset = pos;
994
995         GST_OBJECT_LOCK (parse);
996         for (node = parse->priv->pending_seeks; node; node = node->next) {
997           GstBaseParseSeek *tmp = node->data;
998
999           if (tmp->offset == pos) {
1000             seek = tmp;
1001             break;
1002           }
1003         }
1004         parse->priv->pending_seeks =
1005             g_slist_remove (parse->priv->pending_seeks, seek);
1006         GST_OBJECT_UNLOCK (parse);
1007
1008         if (seek) {
1009           GST_DEBUG_OBJECT (parse,
1010               "Matched newsegment to%s seek: %" GST_SEGMENT_FORMAT,
1011               seek->accurate ? " accurate" : "", &seek->segment);
1012           seg_start = seek->segment.start;
1013           seg_stop = seek->segment.stop;
1014           next_ts = seek->start_ts;
1015           parse->priv->exact_position = seek->accurate;
1016           g_free (seek);
1017         } else {
1018           /* best attempt convert */
1019           /* as these are only estimates, stop is kept open-ended to avoid
1020            * premature cutting */
1021           gst_base_parse_convert (parse, GST_FORMAT_BYTES, start,
1022               GST_FORMAT_TIME, (gint64 *) & seg_start);
1023           parse->priv->exact_position = (start == 0);
1024           next_ts = seg_start;
1025         }
1026
1027         gst_event_unref (event);
1028         event = gst_event_new_new_segment_full (update, rate, applied_rate,
1029             GST_FORMAT_TIME, seg_start, seg_stop, seg_start);
1030         format = GST_FORMAT_TIME;
1031         start = seg_start;
1032         stop = seg_stop;
1033         GST_DEBUG_OBJECT (parse, "Converted incoming segment to TIME. "
1034             "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT,
1035             GST_TIME_ARGS (seg_start), GST_TIME_ARGS (seg_stop));
1036       } else if (format != GST_FORMAT_TIME) {
1037         /* Unknown incoming segment format. Output a default open-ended
1038          * TIME segment */
1039         gst_event_unref (event);
1040         event = gst_event_new_new_segment_full (update, rate, applied_rate,
1041             GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0);
1042         format = GST_FORMAT_TIME;
1043         next_ts = start = 0;
1044         stop = GST_CLOCK_TIME_NONE;
1045       } else {
1046         /* not considered BYTE seekable if it is talking to us in TIME,
1047          * whatever else it might claim */
1048         parse->priv->upstream_seekable = FALSE;
1049         next_ts = start;
1050       }
1051
1052       gst_segment_set_newsegment_full (&parse->segment, update, rate,
1053           applied_rate, format, start, stop, start);
1054
1055       /* save the segment for later, right before we push a new buffer so that
1056        * the caps are fixed and the next linked element can receive
1057        * the segment. */
1058       parse->priv->pending_events =
1059           g_list_append (parse->priv->pending_events, event);
1060       parse->priv->pending_segment = TRUE;
1061       handled = TRUE;
1062
1063       /* but finish the current segment */
1064       GST_DEBUG_OBJECT (parse, "draining current segment");
1065       if (parse->segment.rate > 0.0)
1066         gst_base_parse_drain (parse);
1067       else
1068         gst_base_parse_process_fragment (parse, FALSE);
1069       gst_adapter_clear (parse->priv->adapter);
1070       parse->priv->offset = offset;
1071       parse->priv->sync_offset = offset;
1072       parse->priv->next_ts = next_ts;
1073       parse->priv->last_ts = GST_CLOCK_TIME_NONE;
1074       parse->priv->discont = TRUE;
1075       parse->priv->seen_keyframe = FALSE;
1076       break;
1077     }
1078
1079     case GST_EVENT_FLUSH_START:
1080       parse->priv->flushing = TRUE;
1081       handled = gst_pad_push_event (parse->srcpad, gst_event_ref (event));
1082       if (handled)
1083         gst_event_unref (event);
1084       /* Wait for _chain() to exit by taking the srcpad STREAM_LOCK */
1085       GST_PAD_STREAM_LOCK (parse->srcpad);
1086       GST_PAD_STREAM_UNLOCK (parse->srcpad);
1087
1088       break;
1089
1090     case GST_EVENT_FLUSH_STOP:
1091       gst_adapter_clear (parse->priv->adapter);
1092       gst_base_parse_clear_queues (parse);
1093       parse->priv->flushing = FALSE;
1094       parse->priv->discont = TRUE;
1095       parse->priv->last_ts = GST_CLOCK_TIME_NONE;
1096       parse->priv->frame._private_flags |=
1097           GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
1098       gst_base_parse_frame_free (&parse->priv->frame);
1099       break;
1100
1101     case GST_EVENT_EOS:
1102       if (parse->segment.rate > 0.0)
1103         gst_base_parse_drain (parse);
1104       else
1105         gst_base_parse_process_fragment (parse, FALSE);
1106
1107       /* If we STILL have zero frames processed, fire an error */
1108       if (parse->priv->framecount == 0) {
1109         GST_ELEMENT_ERROR (parse, STREAM, WRONG_TYPE,
1110             ("No valid frames found before end of stream"), (NULL));
1111       }
1112       /* newsegment and other serialized events before eos */
1113       if (G_UNLIKELY (parse->priv->pending_events)) {
1114         GList *l;
1115
1116         for (l = parse->priv->pending_events; l != NULL; l = l->next) {
1117           gst_pad_push_event (parse->srcpad, GST_EVENT (l->data));
1118         }
1119         g_list_free (parse->priv->pending_events);
1120         parse->priv->pending_events = NULL;
1121         parse->priv->pending_segment = FALSE;
1122       }
1123       break;
1124
1125     default:
1126       break;
1127   }
1128
1129   return handled;
1130 }
1131
1132
1133 /* gst_base_parse_src_event:
1134  * @pad: #GstPad that received the event.
1135  * @event: #GstEvent that was received.
1136  *
1137  * Handler for source pad events.
1138  *
1139  * Returns: TRUE if the event was handled.
1140  */
1141 static gboolean
1142 gst_base_parse_src_event (GstPad * pad, GstEvent * event)
1143 {
1144   GstBaseParse *parse;
1145   GstBaseParseClass *bclass;
1146   gboolean handled = FALSE;
1147   gboolean ret = TRUE;
1148
1149   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
1150   bclass = GST_BASE_PARSE_GET_CLASS (parse);
1151
1152   GST_DEBUG_OBJECT (parse, "event %d, %s", GST_EVENT_TYPE (event),
1153       GST_EVENT_TYPE_NAME (event));
1154
1155   if (bclass->src_event)
1156     handled = bclass->src_event (parse, event);
1157
1158   if (!handled)
1159     ret = gst_pad_event_default (pad, event);
1160
1161   gst_object_unref (parse);
1162   return ret;
1163 }
1164
1165 static gboolean
1166 gst_base_parse_is_seekable (GstBaseParse * parse)
1167 {
1168   /* FIXME: could do more here, e.g. check index or just send data from 0
1169    * in pull mode and let decoder/sink clip */
1170   return parse->priv->syncable;
1171 }
1172
1173 /* gst_base_parse_src_eventfunc:
1174  * @parse: #GstBaseParse.
1175  * @event: #GstEvent that was received.
1176  *
1177  * Default srcpad event handler.
1178  *
1179  * Returns: TRUE if the event was handled and can be dropped.
1180  */
1181 static gboolean
1182 gst_base_parse_src_eventfunc (GstBaseParse * parse, GstEvent * event)
1183 {
1184   gboolean handled = FALSE;
1185
1186   switch (GST_EVENT_TYPE (event)) {
1187     case GST_EVENT_SEEK:
1188     {
1189       if (gst_base_parse_is_seekable (parse)) {
1190         handled = gst_base_parse_handle_seek (parse, event);
1191       }
1192       break;
1193     }
1194     default:
1195       break;
1196   }
1197   return handled;
1198 }
1199
1200
1201 /**
1202  * gst_base_parse_convert_default:
1203  * @parse: #GstBaseParse.
1204  * @src_format: #GstFormat describing the source format.
1205  * @src_value: Source value to be converted.
1206  * @dest_format: #GstFormat defining the converted format.
1207  * @dest_value: Pointer where the conversion result will be put.
1208  *
1209  * Default implementation of "convert" vmethod in #GstBaseParse class.
1210  *
1211  * Returns: TRUE if conversion was successful.
1212  *
1213  * Since: 0.10.33
1214  */
1215 gboolean
1216 gst_base_parse_convert_default (GstBaseParse * parse,
1217     GstFormat src_format,
1218     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
1219 {
1220   gboolean ret = FALSE;
1221   guint64 bytes, duration;
1222
1223   if (G_UNLIKELY (src_format == dest_format)) {
1224     *dest_value = src_value;
1225     return TRUE;
1226   }
1227
1228   if (G_UNLIKELY (src_value == -1)) {
1229     *dest_value = -1;
1230     return TRUE;
1231   }
1232
1233   if (G_UNLIKELY (src_value == 0)) {
1234     *dest_value = 0;
1235     return TRUE;
1236   }
1237
1238   /* need at least some frames */
1239   if (!parse->priv->framecount)
1240     return FALSE;
1241
1242   duration = parse->priv->acc_duration / GST_MSECOND;
1243   bytes = parse->priv->bytecount;
1244
1245   if (G_UNLIKELY (!duration || !bytes))
1246     return FALSE;
1247
1248   if (src_format == GST_FORMAT_BYTES) {
1249     if (dest_format == GST_FORMAT_TIME) {
1250       /* BYTES -> TIME conversion */
1251       GST_DEBUG_OBJECT (parse, "converting bytes -> time");
1252       *dest_value = gst_util_uint64_scale (src_value, duration, bytes);
1253       *dest_value *= GST_MSECOND;
1254       GST_DEBUG_OBJECT (parse, "conversion result: %" G_GINT64_FORMAT " ms",
1255           *dest_value / GST_MSECOND);
1256       ret = TRUE;
1257     }
1258   } else if (src_format == GST_FORMAT_TIME) {
1259     if (dest_format == GST_FORMAT_BYTES) {
1260       GST_DEBUG_OBJECT (parse, "converting time -> bytes");
1261       *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes,
1262           duration);
1263       GST_DEBUG_OBJECT (parse,
1264           "time %" G_GINT64_FORMAT " ms in bytes = %" G_GINT64_FORMAT,
1265           src_value / GST_MSECOND, *dest_value);
1266       ret = TRUE;
1267     }
1268   } else if (src_format == GST_FORMAT_DEFAULT) {
1269     /* DEFAULT == frame-based */
1270     if (dest_format == GST_FORMAT_TIME) {
1271       if (parse->priv->fps_den) {
1272         *dest_value = gst_util_uint64_scale (src_value,
1273             GST_SECOND * parse->priv->fps_den, parse->priv->fps_num);
1274         ret = TRUE;
1275       }
1276     } else if (dest_format == GST_FORMAT_BYTES) {
1277     }
1278   }
1279
1280   return ret;
1281 }
1282
1283 static void
1284 gst_base_parse_update_duration (GstBaseParse * baseparse)
1285 {
1286   GstPad *peer;
1287   GstBaseParse *parse;
1288
1289   parse = GST_BASE_PARSE (baseparse);
1290
1291   peer = gst_pad_get_peer (parse->sinkpad);
1292   if (peer) {
1293     GstFormat pformat = GST_FORMAT_BYTES;
1294     gboolean qres = FALSE;
1295     gint64 ptot, dest_value;
1296
1297     qres = gst_pad_query_duration (peer, &pformat, &ptot);
1298     gst_object_unref (GST_OBJECT (peer));
1299     if (qres) {
1300       if (gst_base_parse_convert (parse, pformat, ptot,
1301               GST_FORMAT_TIME, &dest_value)) {
1302
1303         /* inform if duration changed, but try to avoid spamming */
1304         parse->priv->estimated_drift +=
1305             dest_value - parse->priv->estimated_duration;
1306         if (parse->priv->estimated_drift > GST_SECOND ||
1307             parse->priv->estimated_drift < -GST_SECOND) {
1308           gst_element_post_message (GST_ELEMENT (parse),
1309               gst_message_new_duration (GST_OBJECT (parse),
1310                   GST_FORMAT_TIME, dest_value));
1311           parse->priv->estimated_drift = 0;
1312         }
1313         parse->priv->estimated_duration = dest_value;
1314         GST_LOG_OBJECT (parse,
1315             "updated estimated duration to %" GST_TIME_FORMAT,
1316             GST_TIME_ARGS (dest_value));
1317       }
1318     }
1319   }
1320 }
1321
1322 static void
1323 gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min,
1324     gboolean post_avg, gboolean post_max)
1325 {
1326   GstTagList *taglist = NULL;
1327
1328   if (post_min && parse->priv->post_min_bitrate) {
1329     taglist = gst_tag_list_new ();
1330
1331     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
1332         GST_TAG_MINIMUM_BITRATE, parse->priv->min_bitrate, NULL);
1333   }
1334
1335   if (post_avg && parse->priv->post_avg_bitrate) {
1336     if (taglist == NULL)
1337       taglist = gst_tag_list_new ();
1338
1339     parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate;
1340     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
1341         parse->priv->avg_bitrate, NULL);
1342   }
1343
1344   if (post_max && parse->priv->post_max_bitrate) {
1345     if (taglist == NULL)
1346       taglist = gst_tag_list_new ();
1347
1348     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
1349         GST_TAG_MAXIMUM_BITRATE, parse->priv->max_bitrate, NULL);
1350   }
1351
1352   GST_DEBUG_OBJECT (parse, "Updated bitrates. Min: %u, Avg: %u, Max: %u",
1353       parse->priv->min_bitrate, parse->priv->avg_bitrate,
1354       parse->priv->max_bitrate);
1355
1356   if (taglist != NULL) {
1357     gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse), parse->srcpad,
1358         taglist);
1359   }
1360 }
1361
1362 /* gst_base_parse_update_bitrates:
1363  * @parse: #GstBaseParse.
1364  * @buffer: Current frame as a #GstBuffer
1365  *
1366  * Keeps track of the minimum and maximum bitrates, and also maintains a
1367  * running average bitrate of the stream so far.
1368  */
1369 static void
1370 gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
1371 {
1372   /* Only update the tag on a 10 kbps delta */
1373   static const gint update_threshold = 10000;
1374
1375   guint64 data_len, frame_dur;
1376   gint overhead, frame_bitrate, old_avg_bitrate;
1377   gboolean update_min = FALSE, update_avg = FALSE, update_max = FALSE;
1378   GstBuffer *buffer = frame->buffer;
1379
1380   overhead = frame->overhead;
1381   if (overhead == -1)
1382     return;
1383
1384   data_len = GST_BUFFER_SIZE (buffer) - overhead;
1385   parse->priv->data_bytecount += data_len;
1386
1387   /* duration should be valid by now,
1388    * either set by subclass or maybe based on fps settings */
1389   if (GST_BUFFER_DURATION_IS_VALID (buffer) && parse->priv->acc_duration != 0) {
1390     /* Calculate duration of a frame from buffer properties */
1391     frame_dur = GST_BUFFER_DURATION (buffer);
1392     parse->priv->avg_bitrate = (8 * parse->priv->data_bytecount * GST_SECOND) /
1393         parse->priv->acc_duration;
1394
1395   } else {
1396     /* No way to figure out frame duration (is this even possible?) */
1397     return;
1398   }
1399
1400   /* override if subclass provided bitrate, e.g. metadata based */
1401   if (parse->priv->bitrate) {
1402     parse->priv->avg_bitrate = parse->priv->bitrate;
1403     /* spread this (confirmed) info ASAP */
1404     if (parse->priv->posted_avg_bitrate != parse->priv->avg_bitrate)
1405       gst_base_parse_post_bitrates (parse, FALSE, TRUE, FALSE);
1406   }
1407
1408   if (frame_dur)
1409     frame_bitrate = (8 * data_len * GST_SECOND) / frame_dur;
1410   else
1411     return;
1412
1413   GST_LOG_OBJECT (parse, "frame bitrate %u, avg bitrate %u", frame_bitrate,
1414       parse->priv->avg_bitrate);
1415
1416   if (parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE) {
1417     goto exit;
1418   } else if (parse->priv->framecount == MIN_FRAMES_TO_POST_BITRATE) {
1419     /* always post all at threshold time */
1420     update_min = update_max = update_avg = TRUE;
1421   }
1422
1423   if (G_LIKELY (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE)) {
1424     if (frame_bitrate < parse->priv->min_bitrate) {
1425       parse->priv->min_bitrate = frame_bitrate;
1426       update_min = TRUE;
1427     }
1428
1429     if (frame_bitrate > parse->priv->max_bitrate) {
1430       parse->priv->max_bitrate = frame_bitrate;
1431       update_max = TRUE;
1432     }
1433
1434     old_avg_bitrate = parse->priv->posted_avg_bitrate;
1435     if ((gint) (old_avg_bitrate - parse->priv->avg_bitrate) > update_threshold
1436         || (gint) (parse->priv->avg_bitrate - old_avg_bitrate) >
1437         update_threshold)
1438       update_avg = TRUE;
1439   }
1440
1441   if ((update_min || update_avg || update_max))
1442     gst_base_parse_post_bitrates (parse, update_min, update_avg, update_max);
1443
1444 exit:
1445   return;
1446 }
1447
1448 /**
1449  * gst_base_parse_add_index_entry:
1450  * @parse: #GstBaseParse.
1451  * @offset: offset of entry
1452  * @ts: timestamp associated with offset
1453  * @key: whether entry refers to keyframe
1454  * @force: add entry disregarding sanity checks
1455  *
1456  * Adds an entry to the index associating @offset to @ts.  It is recommended
1457  * to only add keyframe entries.  @force allows to bypass checks, such as
1458  * whether the stream is (upstream) seekable, another entry is already "close"
1459  * to the new entry, etc.
1460  *
1461  * Returns: #gboolean indicating whether entry was added
1462  *
1463  * Since: 0.10.33
1464  */
1465 gboolean
1466 gst_base_parse_add_index_entry (GstBaseParse * parse, guint64 offset,
1467     GstClockTime ts, gboolean key, gboolean force)
1468 {
1469   gboolean ret = FALSE;
1470   GstIndexAssociation associations[2];
1471
1472   GST_LOG_OBJECT (parse, "Adding key=%d index entry %" GST_TIME_FORMAT
1473       " @ offset 0x%08" G_GINT64_MODIFIER "x", key, GST_TIME_ARGS (ts), offset);
1474
1475   if (G_LIKELY (!force)) {
1476
1477     if (!parse->priv->upstream_seekable) {
1478       GST_DEBUG_OBJECT (parse, "upstream not seekable; discarding");
1479       goto exit;
1480     }
1481
1482     /* FIXME need better helper data structure that handles these issues
1483      * related to ongoing collecting of index entries */
1484     if (parse->priv->index_last_offset >= (gint64) offset) {
1485       GST_DEBUG_OBJECT (parse, "already have entries up to offset "
1486           "0x%08" G_GINT64_MODIFIER "x", parse->priv->index_last_offset);
1487       goto exit;
1488     }
1489
1490     if (GST_CLOCK_TIME_IS_VALID (parse->priv->index_last_ts) &&
1491         GST_CLOCK_DIFF (parse->priv->index_last_ts, ts) <
1492         parse->priv->idx_interval) {
1493       GST_DEBUG_OBJECT (parse, "entry too close to last time %" GST_TIME_FORMAT,
1494           GST_TIME_ARGS (parse->priv->index_last_ts));
1495       goto exit;
1496     }
1497
1498     /* if last is not really the last one */
1499     if (!parse->priv->index_last_valid) {
1500       GstClockTime prev_ts;
1501
1502       gst_base_parse_find_offset (parse, ts, TRUE, &prev_ts);
1503       if (GST_CLOCK_DIFF (prev_ts, ts) < parse->priv->idx_interval) {
1504         GST_DEBUG_OBJECT (parse,
1505             "entry too close to existing entry %" GST_TIME_FORMAT,
1506             GST_TIME_ARGS (prev_ts));
1507         parse->priv->index_last_offset = offset;
1508         parse->priv->index_last_ts = ts;
1509         goto exit;
1510       }
1511     }
1512   }
1513
1514   associations[0].format = GST_FORMAT_TIME;
1515   associations[0].value = ts;
1516   associations[1].format = GST_FORMAT_BYTES;
1517   associations[1].value = offset;
1518
1519   /* index might change on-the-fly, although that would be nutty app ... */
1520   GST_BASE_PARSE_INDEX_LOCK (parse);
1521   gst_index_add_associationv (parse->priv->index, parse->priv->index_id,
1522       (key) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_DELTA_UNIT,
1523       2, (const GstIndexAssociation *) &associations);
1524   GST_BASE_PARSE_INDEX_UNLOCK (parse);
1525
1526   if (key) {
1527     parse->priv->index_last_offset = offset;
1528     parse->priv->index_last_ts = ts;
1529   }
1530
1531   ret = TRUE;
1532
1533 exit:
1534   return ret;
1535 }
1536
1537 /* check for seekable upstream, above and beyond a mere query */
1538 static void
1539 gst_base_parse_check_seekability (GstBaseParse * parse)
1540 {
1541   GstQuery *query;
1542   gboolean seekable = FALSE;
1543   gint64 start = -1, stop = -1;
1544   guint idx_interval = 0;
1545
1546   query = gst_query_new_seeking (GST_FORMAT_BYTES);
1547   if (!gst_pad_peer_query (parse->sinkpad, query)) {
1548     GST_DEBUG_OBJECT (parse, "seeking query failed");
1549     goto done;
1550   }
1551
1552   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
1553
1554   /* try harder to query upstream size if we didn't get it the first time */
1555   if (seekable && stop == -1) {
1556     GstFormat fmt = GST_FORMAT_BYTES;
1557
1558     GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop");
1559     gst_pad_query_peer_duration (parse->sinkpad, &fmt, &stop);
1560   }
1561
1562   /* if upstream doesn't know the size, it's likely that it's not seekable in
1563    * practice even if it technically may be seekable */
1564   if (seekable && (start != 0 || stop <= start)) {
1565     GST_DEBUG_OBJECT (parse, "seekable but unknown start/stop -> disable");
1566     seekable = FALSE;
1567   }
1568
1569   /* let's not put every single frame into our index */
1570   if (seekable) {
1571     if (stop < 10 * 1024 * 1024)
1572       idx_interval = 100;
1573     else if (stop < 100 * 1024 * 1024)
1574       idx_interval = 500;
1575     else
1576       idx_interval = 1000;
1577   }
1578
1579 done:
1580   gst_query_unref (query);
1581
1582   GST_DEBUG_OBJECT (parse, "seekable: %d (%" G_GUINT64_FORMAT " - %"
1583       G_GUINT64_FORMAT ")", seekable, start, stop);
1584   parse->priv->upstream_seekable = seekable;
1585   parse->priv->upstream_size = seekable ? stop : 0;
1586
1587   GST_DEBUG_OBJECT (parse, "idx_interval: %ums", idx_interval);
1588   parse->priv->idx_interval = idx_interval * GST_MSECOND;
1589 }
1590
1591 /* some misc checks on upstream */
1592 static void
1593 gst_base_parse_check_upstream (GstBaseParse * parse)
1594 {
1595   GstFormat fmt = GST_FORMAT_TIME;
1596   gint64 stop;
1597
1598   if (gst_pad_query_peer_duration (parse->sinkpad, &fmt, &stop))
1599     if (GST_CLOCK_TIME_IS_VALID (stop) && stop) {
1600       /* upstream has one, accept it also, and no further updates */
1601       gst_base_parse_set_duration (parse, GST_FORMAT_TIME, stop, 0);
1602       parse->priv->upstream_has_duration = TRUE;
1603     }
1604
1605   GST_DEBUG_OBJECT (parse, "upstream_has_duration: %d",
1606       parse->priv->upstream_has_duration);
1607 }
1608
1609 /* checks src caps to determine if dealing with audio or video */
1610 /* TODO maybe forego automagic stuff and let subclass configure it ? */
1611 static void
1612 gst_base_parse_check_media (GstBaseParse * parse)
1613 {
1614   GstCaps *caps;
1615   GstStructure *s;
1616
1617   caps = GST_PAD_CAPS (parse->srcpad);
1618   if (G_LIKELY (caps) && (s = gst_caps_get_structure (caps, 0))) {
1619     parse->priv->is_video =
1620         g_str_has_prefix (gst_structure_get_name (s), "video");
1621   } else {
1622     /* historical default */
1623     parse->priv->is_video = FALSE;
1624   }
1625
1626   GST_DEBUG_OBJECT (parse, "media is video: %d", parse->priv->is_video);
1627 }
1628
1629 /* takes ownership of frame */
1630 static void
1631 gst_base_parse_queue_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1632 {
1633   if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) {
1634     /* frame allocated on the heap, we can just take ownership */
1635     g_queue_push_tail (&parse->priv->queued_frames, frame);
1636     GST_TRACE ("queued frame %p", frame);
1637   } else {
1638     GstBaseParseFrame *copy;
1639
1640     /* probably allocated on the stack, must make a proper copy */
1641     copy = gst_base_parse_frame_copy (frame);
1642     g_queue_push_tail (&parse->priv->queued_frames, copy);
1643     GST_TRACE ("queued frame %p (copy of %p)", copy, frame);
1644     gst_base_parse_frame_free (frame);
1645   }
1646 }
1647
1648 /* gst_base_parse_handle_and_push_buffer:
1649  * @parse: #GstBaseParse.
1650  * @klass: #GstBaseParseClass.
1651  * @frame: (transfer full): a #GstBaseParseFrame
1652  *
1653  * Parses the frame from given buffer and pushes it forward. Also performs
1654  * timestamp handling and checks the segment limits.
1655  *
1656  * This is called with srcpad STREAM_LOCK held.
1657  *
1658  * Returns: #GstFlowReturn
1659  */
1660 static GstFlowReturn
1661 gst_base_parse_handle_and_push_frame (GstBaseParse * parse,
1662     GstBaseParseClass * klass, GstBaseParseFrame * frame)
1663 {
1664   GstFlowReturn ret;
1665   gint64 offset;
1666   GstBuffer *buffer;
1667
1668   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
1669
1670   buffer = frame->buffer;
1671
1672   if (parse->priv->discont) {
1673     GST_DEBUG_OBJECT (parse, "marking DISCONT");
1674     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
1675     parse->priv->discont = FALSE;
1676   }
1677
1678   /* some one-time start-up */
1679   if (G_UNLIKELY (!parse->priv->framecount)) {
1680     gst_base_parse_check_seekability (parse);
1681     gst_base_parse_check_upstream (parse);
1682   }
1683
1684   GST_LOG_OBJECT (parse,
1685       "parsing frame at offset %" G_GUINT64_FORMAT
1686       " (%#" G_GINT64_MODIFIER "x) of size %d",
1687       GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer),
1688       GST_BUFFER_SIZE (buffer));
1689
1690   /* use default handler to provide initial (upstream) metadata */
1691   gst_base_parse_parse_frame (parse, frame);
1692
1693   /* store offset as it might get overwritten */
1694   offset = GST_BUFFER_OFFSET (buffer);
1695   ret = klass->parse_frame (parse, frame);
1696   /* sync */
1697   buffer = frame->buffer;
1698   /* subclass must play nice */
1699   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
1700
1701   /* check if subclass/format can provide ts.
1702    * If so, that allows and enables extra seek and duration determining options */
1703   if (G_UNLIKELY (parse->priv->first_frame_offset < 0 && ret == GST_FLOW_OK)) {
1704     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && parse->priv->has_timing_info
1705         && parse->priv->pad_mode == GST_ACTIVATE_PULL) {
1706       parse->priv->first_frame_offset = offset;
1707       parse->priv->first_frame_ts = GST_BUFFER_TIMESTAMP (buffer);
1708       GST_DEBUG_OBJECT (parse, "subclass provided ts %" GST_TIME_FORMAT
1709           " for first frame at offset %" G_GINT64_FORMAT,
1710           GST_TIME_ARGS (parse->priv->first_frame_ts),
1711           parse->priv->first_frame_offset);
1712       if (!GST_CLOCK_TIME_IS_VALID (parse->priv->duration)) {
1713         gint64 off;
1714         GstClockTime last_ts = G_MAXINT64;
1715
1716         GST_DEBUG_OBJECT (parse, "no duration; trying scan to determine");
1717         gst_base_parse_locate_time (parse, &last_ts, &off);
1718         if (GST_CLOCK_TIME_IS_VALID (last_ts))
1719           gst_base_parse_set_duration (parse, GST_FORMAT_TIME, last_ts, 0);
1720       }
1721     } else {
1722       /* disable further checks */
1723       parse->priv->first_frame_offset = 0;
1724     }
1725   }
1726
1727   /* again use default handler to add missing metadata;
1728    * we may have new information on frame properties */
1729   gst_base_parse_parse_frame (parse, frame);
1730   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
1731       GST_BUFFER_DURATION_IS_VALID (buffer)) {
1732     parse->priv->next_ts =
1733         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1734   } else {
1735     /* we lost track, do not produce bogus time next time around
1736      * (probably means parser subclass has given up on parsing as well) */
1737     GST_DEBUG_OBJECT (parse, "no next fallback timestamp");
1738     parse->priv->next_ts = GST_CLOCK_TIME_NONE;
1739   }
1740
1741   if (parse->priv->upstream_seekable && parse->priv->exact_position &&
1742       GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
1743     gst_base_parse_add_index_entry (parse, offset,
1744         GST_BUFFER_TIMESTAMP (buffer),
1745         !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE);
1746
1747   /* First buffers are dropped, this means that the subclass needs more
1748    * frames to decide on the format and queues them internally */
1749   /* convert internal flow to OK and mark discont for the next buffer. */
1750   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
1751     gst_base_parse_frame_free (frame);
1752     return GST_FLOW_OK;
1753   } else if (ret == GST_BASE_PARSE_FLOW_QUEUED) {
1754     gst_base_parse_queue_frame (parse, frame);
1755     return GST_FLOW_OK;
1756   } else if (ret != GST_FLOW_OK) {
1757     return ret;
1758   }
1759
1760   /* All OK, push queued frames if there are any */
1761   if (G_UNLIKELY (!g_queue_is_empty (&parse->priv->queued_frames))) {
1762     GstBaseParseFrame *queued_frame;
1763
1764     while ((queued_frame = g_queue_pop_head (&parse->priv->queued_frames))) {
1765       queued_frame->buffer =
1766           gst_buffer_make_metadata_writable (queued_frame->buffer);
1767       gst_buffer_set_caps (queued_frame->buffer,
1768           GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (parse)));
1769       gst_base_parse_push_frame (parse, queued_frame);
1770     }
1771   }
1772
1773   return gst_base_parse_push_frame (parse, frame);
1774 }
1775
1776 /**
1777  * gst_base_parse_push_frame:
1778  * @parse: #GstBaseParse.
1779  * @frame: (transfer full): a #GstBaseParseFrame
1780  *
1781  * Pushes the frame downstream, sends any pending events and
1782  * does some timestamp and segment handling. Takes ownership
1783  * of @frame and will clear it (if it was initialised with
1784  * gst_base_parse_frame_init()) or free it.
1785  *
1786  * This must be called with sinkpad STREAM_LOCK held.
1787  *
1788  * Returns: #GstFlowReturn
1789  *
1790  * Since: 0.10.33
1791  */
1792 GstFlowReturn
1793 gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1794 {
1795   GstFlowReturn ret = GST_FLOW_OK;
1796   GstClockTime last_start = GST_CLOCK_TIME_NONE;
1797   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
1798   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
1799   GstBuffer *buffer;
1800
1801   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
1802   g_return_val_if_fail (frame->buffer != NULL, GST_FLOW_ERROR);
1803
1804   GST_TRACE_OBJECT (parse, "pushing frame %p", frame);
1805
1806   buffer = frame->buffer;
1807
1808   GST_LOG_OBJECT (parse,
1809       "processing buffer of size %d with ts %" GST_TIME_FORMAT
1810       ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buffer),
1811       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1812       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
1813
1814   /* update stats */
1815   parse->priv->bytecount += GST_BUFFER_SIZE (buffer);
1816   if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) {
1817     parse->priv->framecount++;
1818     if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
1819       parse->priv->acc_duration += GST_BUFFER_DURATION (buffer);
1820     }
1821   }
1822   /* 0 means disabled */
1823   if (parse->priv->update_interval < 0)
1824     parse->priv->update_interval = 50;
1825   else if (parse->priv->update_interval > 0 &&
1826       (parse->priv->framecount % parse->priv->update_interval) == 0)
1827     gst_base_parse_update_duration (parse);
1828
1829   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
1830     last_start = last_stop = GST_BUFFER_TIMESTAMP (buffer);
1831   if (last_start != GST_CLOCK_TIME_NONE
1832       && GST_BUFFER_DURATION_IS_VALID (buffer))
1833     last_stop = last_start + GST_BUFFER_DURATION (buffer);
1834
1835   /* should have caps by now */
1836   g_return_val_if_fail (GST_PAD_CAPS (parse->srcpad), GST_FLOW_ERROR);
1837
1838   if (G_UNLIKELY (parse->priv->pending_segment)) {
1839     /* have caps; check identity */
1840     gst_base_parse_check_media (parse);
1841   }
1842
1843   /* and should then also be linked downstream, so safe to send some events */
1844   if (G_UNLIKELY (parse->priv->close_segment)) {
1845     /* only set up by loop */
1846     GST_DEBUG_OBJECT (parse, "loop sending close segment");
1847     gst_pad_push_event (parse->srcpad, parse->priv->close_segment);
1848     parse->priv->close_segment = NULL;
1849   }
1850
1851   /* Push pending events, including NEWSEGMENT events */
1852   if (G_UNLIKELY (parse->priv->pending_events)) {
1853     GList *l;
1854
1855     for (l = parse->priv->pending_events; l != NULL; l = l->next) {
1856       gst_pad_push_event (parse->srcpad, GST_EVENT (l->data));
1857     }
1858     g_list_free (parse->priv->pending_events);
1859     parse->priv->pending_events = NULL;
1860     parse->priv->pending_segment = FALSE;
1861   }
1862
1863   /* segment adjustment magic; only if we are running the whole show */
1864   if (!parse->priv->passthrough && parse->segment.rate > 0.0 &&
1865       (parse->priv->pad_mode == GST_ACTIVATE_PULL ||
1866           parse->priv->upstream_seekable)) {
1867     /* handle gaps */
1868     if (GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop) &&
1869         GST_CLOCK_TIME_IS_VALID (last_start)) {
1870       GstClockTimeDiff diff;
1871
1872       /* only send newsegments with increasing start times,
1873        * otherwise if these go back and forth downstream (sinks) increase
1874        * accumulated time and running_time */
1875       diff = GST_CLOCK_DIFF (parse->segment.last_stop, last_start);
1876       if (G_UNLIKELY (diff > 2 * GST_SECOND
1877               && last_start > parse->segment.start
1878               && (!GST_CLOCK_TIME_IS_VALID (parse->segment.stop)
1879                   || last_start < parse->segment.stop))) {
1880         GST_DEBUG_OBJECT (parse,
1881             "Gap of %" G_GINT64_FORMAT " ns detected in stream " "(%"
1882             GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "). "
1883             "Sending updated NEWSEGMENT events", diff,
1884             GST_TIME_ARGS (parse->segment.last_stop),
1885             GST_TIME_ARGS (last_start));
1886
1887         /* send newsegment events such that the gap is not accounted in
1888          * accum time, hence running_time */
1889         /* close ahead of gap */
1890         gst_pad_push_event (parse->srcpad,
1891             gst_event_new_new_segment (TRUE, parse->segment.rate,
1892                 parse->segment.format, parse->segment.last_stop,
1893                 parse->segment.last_stop, parse->segment.last_stop));
1894         /* skip gap */
1895         gst_pad_push_event (parse->srcpad,
1896             gst_event_new_new_segment (FALSE, parse->segment.rate,
1897                 parse->segment.format, last_start,
1898                 parse->segment.stop, last_start));
1899
1900         /* align segment view with downstream,
1901          * prevents double-counting accum when closing segment */
1902         gst_segment_set_newsegment (&parse->segment, FALSE,
1903             parse->segment.rate, parse->segment.format, last_start,
1904             parse->segment.stop, last_start);
1905         parse->segment.last_stop = last_start;
1906       }
1907     }
1908   }
1909
1910   /* update bitrates and optionally post corresponding tags
1911    * (following newsegment) */
1912   gst_base_parse_update_bitrates (parse, frame);
1913
1914   if (klass->pre_push_frame) {
1915     ret = klass->pre_push_frame (parse, frame);
1916   } else {
1917     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
1918   }
1919
1920   /* take final ownership of frame buffer */
1921   buffer = frame->buffer;
1922   frame->buffer = NULL;
1923
1924   /* subclass must play nice */
1925   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
1926
1927   /* decorate */
1928   buffer = gst_buffer_make_metadata_writable (buffer);
1929   gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
1930
1931   parse->priv->seen_keyframe |= parse->priv->is_video &&
1932       !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1933
1934   if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_CLIP) {
1935     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
1936         GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
1937         GST_BUFFER_TIMESTAMP (buffer) >
1938         parse->segment.stop + parse->priv->lead_out_ts) {
1939       GST_LOG_OBJECT (parse, "Dropped frame, after segment");
1940       ret = GST_FLOW_UNEXPECTED;
1941     } else if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
1942         GST_BUFFER_DURATION_IS_VALID (buffer) &&
1943         GST_CLOCK_TIME_IS_VALID (parse->segment.start) &&
1944         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) +
1945         parse->priv->lead_in_ts < parse->segment.start) {
1946       if (parse->priv->seen_keyframe) {
1947         GST_LOG_OBJECT (parse, "Frame before segment, after keyframe");
1948         ret = GST_FLOW_OK;
1949       } else {
1950         GST_LOG_OBJECT (parse, "Dropped frame, before segment");
1951         ret = GST_BASE_PARSE_FLOW_DROPPED;
1952       }
1953     } else {
1954       ret = GST_FLOW_OK;
1955     }
1956   }
1957
1958   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
1959     GST_LOG_OBJECT (parse, "frame (%d bytes) dropped",
1960         GST_BUFFER_SIZE (buffer));
1961     gst_buffer_unref (buffer);
1962     ret = GST_FLOW_OK;
1963   } else if (ret == GST_FLOW_OK) {
1964     if (parse->segment.rate > 0.0) {
1965       GST_LOG_OBJECT (parse, "pushing frame (%d bytes) now..",
1966           GST_BUFFER_SIZE (buffer));
1967       ret = gst_pad_push (parse->srcpad, buffer);
1968       GST_LOG_OBJECT (parse, "frame pushed, flow %s", gst_flow_get_name (ret));
1969     } else {
1970       GST_LOG_OBJECT (parse, "frame (%d bytes) queued for now",
1971           GST_BUFFER_SIZE (buffer));
1972       parse->priv->buffers_queued =
1973           g_slist_prepend (parse->priv->buffers_queued, buffer);
1974       ret = GST_FLOW_OK;
1975     }
1976   } else {
1977     GST_LOG_OBJECT (parse, "frame (%d bytes) not pushed: %s",
1978         GST_BUFFER_SIZE (buffer), gst_flow_get_name (ret));
1979     gst_buffer_unref (buffer);
1980     /* if we are not sufficiently in control, let upstream decide on EOS */
1981     if (ret == GST_FLOW_UNEXPECTED &&
1982         (parse->priv->passthrough ||
1983             (parse->priv->pad_mode == GST_ACTIVATE_PUSH &&
1984                 !parse->priv->upstream_seekable)))
1985       ret = GST_FLOW_OK;
1986   }
1987
1988   /* Update current running segment position */
1989   if (ret == GST_FLOW_OK && last_stop != GST_CLOCK_TIME_NONE &&
1990       parse->segment.last_stop < last_stop)
1991     gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop);
1992
1993   gst_base_parse_frame_free (frame);
1994
1995   return ret;
1996 }
1997
1998
1999 /* gst_base_parse_drain:
2000  *
2001  * Drains the adapter until it is empty. It decreases the min_frame_size to
2002  * match the current adapter size and calls chain method until the adapter
2003  * is emptied or chain returns with error.
2004  */
2005 static void
2006 gst_base_parse_drain (GstBaseParse * parse)
2007 {
2008   guint avail;
2009
2010   GST_DEBUG_OBJECT (parse, "draining");
2011   parse->priv->drain = TRUE;
2012
2013   for (;;) {
2014     avail = gst_adapter_available (parse->priv->adapter);
2015     if (!avail)
2016       break;
2017
2018     if (gst_base_parse_chain (parse->sinkpad, NULL) != GST_FLOW_OK) {
2019       break;
2020     }
2021
2022     /* nothing changed, maybe due to truncated frame; break infinite loop */
2023     if (avail == gst_adapter_available (parse->priv->adapter)) {
2024       GST_DEBUG_OBJECT (parse, "no change during draining; flushing");
2025       gst_adapter_clear (parse->priv->adapter);
2026     }
2027   }
2028
2029   parse->priv->drain = FALSE;
2030 }
2031
2032 /* gst_base_parse_send_buffers
2033  *
2034  * Sends buffers collected in send_buffers downstream, and ensures that list
2035  * is empty at the end (errors or not).
2036  */
2037 static GstFlowReturn
2038 gst_base_parse_send_buffers (GstBaseParse * parse)
2039 {
2040   GSList *send = NULL;
2041   GstBuffer *buf;
2042   GstFlowReturn ret = GST_FLOW_OK;
2043
2044   send = parse->priv->buffers_send;
2045
2046   /* send buffers */
2047   while (send) {
2048     buf = GST_BUFFER_CAST (send->data);
2049     GST_LOG_OBJECT (parse, "pushing buffer %p, timestamp %"
2050         GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
2051         ", offset %" G_GINT64_FORMAT, buf,
2052         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2053         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf));
2054
2055     /* iterate output queue an push downstream */
2056     ret = gst_pad_push (parse->srcpad, buf);
2057     send = g_slist_delete_link (send, send);
2058
2059     /* clear any leftover if error */
2060     if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2061       while (send) {
2062         buf = GST_BUFFER_CAST (send->data);
2063         gst_buffer_unref (buf);
2064         send = g_slist_delete_link (send, send);
2065       }
2066     }
2067   }
2068
2069   parse->priv->buffers_send = send;
2070
2071   return ret;
2072 }
2073
2074 /* gst_base_parse_process_fragment:
2075  *
2076  * Processes a reverse playback (forward) fragment:
2077  * - append head of last fragment that was skipped to current fragment data
2078  * - drain the resulting current fragment data (i.e. repeated chain)
2079  * - add time/duration (if needed) to frames queued by chain
2080  * - push queued data
2081  */
2082 static GstFlowReturn
2083 gst_base_parse_process_fragment (GstBaseParse * parse, gboolean push_only)
2084 {
2085   GstBuffer *buf;
2086   GstFlowReturn ret = GST_FLOW_OK;
2087   gboolean seen_key = FALSE, seen_delta = FALSE;
2088
2089   if (push_only)
2090     goto push;
2091
2092   /* restore order */
2093   parse->priv->buffers_pending = g_slist_reverse (parse->priv->buffers_pending);
2094   while (parse->priv->buffers_pending) {
2095     buf = GST_BUFFER_CAST (parse->priv->buffers_pending->data);
2096     GST_LOG_OBJECT (parse, "adding pending buffer (size %d)",
2097         GST_BUFFER_SIZE (buf));
2098     gst_adapter_push (parse->priv->adapter, buf);
2099     parse->priv->buffers_pending =
2100         g_slist_delete_link (parse->priv->buffers_pending,
2101         parse->priv->buffers_pending);
2102   }
2103
2104   /* invalidate so no fall-back timestamping is performed;
2105    * ok if taken from subclass or upstream */
2106   parse->priv->next_ts = GST_CLOCK_TIME_NONE;
2107   /* prevent it hanging around stop all the time */
2108   parse->segment.last_stop = GST_CLOCK_TIME_NONE;
2109   /* mark next run */
2110   parse->priv->discont = TRUE;
2111
2112   /* chain looks for frames and queues resulting ones (in stead of pushing) */
2113   /* initial skipped data is added to buffers_pending */
2114   gst_base_parse_drain (parse);
2115
2116 push:
2117   if (parse->priv->buffers_send) {
2118     buf = GST_BUFFER_CAST (parse->priv->buffers_send->data);
2119     seen_key |= !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2120   }
2121
2122   /* add metadata (if needed to queued buffers */
2123   GST_LOG_OBJECT (parse, "last timestamp: %" GST_TIME_FORMAT,
2124       GST_TIME_ARGS (parse->priv->last_ts));
2125   while (parse->priv->buffers_queued) {
2126     buf = GST_BUFFER_CAST (parse->priv->buffers_queued->data);
2127
2128     /* no touching if upstream or parsing provided time */
2129     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2130       GST_LOG_OBJECT (parse, "buffer has time %" GST_TIME_FORMAT,
2131           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2132     } else if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_ts) &&
2133         GST_BUFFER_DURATION_IS_VALID (buf)) {
2134       if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_ts))
2135         parse->priv->last_ts -= GST_BUFFER_DURATION (buf);
2136       else
2137         parse->priv->last_ts = 0;
2138       GST_BUFFER_TIMESTAMP (buf) = parse->priv->last_ts;
2139       GST_LOG_OBJECT (parse, "applied time %" GST_TIME_FORMAT,
2140           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2141     } else {
2142       /* no idea, very bad */
2143       GST_WARNING_OBJECT (parse, "could not determine time for buffer");
2144     }
2145
2146     parse->priv->last_ts = GST_BUFFER_TIMESTAMP (buf);
2147
2148     /* reverse order for ascending sending */
2149     /* send downstream at keyframe not preceded by a keyframe
2150      * (e.g. that should identify start of collection of IDR nals) */
2151     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2152       if (seen_key) {
2153         ret = gst_base_parse_send_buffers (parse);
2154         /* if a problem, throw all to sending */
2155         if (ret != GST_FLOW_OK) {
2156           parse->priv->buffers_send =
2157               g_slist_reverse (parse->priv->buffers_queued);
2158           parse->priv->buffers_queued = NULL;
2159           break;
2160         }
2161         seen_key = FALSE;
2162       }
2163       seen_delta = TRUE;
2164     } else {
2165       seen_key = TRUE;
2166     }
2167
2168     parse->priv->buffers_send =
2169         g_slist_prepend (parse->priv->buffers_send, buf);
2170     parse->priv->buffers_queued =
2171         g_slist_delete_link (parse->priv->buffers_queued,
2172         parse->priv->buffers_queued);
2173   }
2174
2175   /* audio may have all marked as keyframe, so arrange to send here */
2176   if (!seen_delta)
2177     ret = gst_base_parse_send_buffers (parse);
2178
2179   /* any trailing unused no longer usable (ideally none) */
2180   if (G_UNLIKELY (gst_adapter_available (parse->priv->adapter))) {
2181     GST_DEBUG_OBJECT (parse, "discarding %d trailing bytes",
2182         gst_adapter_available (parse->priv->adapter));
2183     gst_adapter_clear (parse->priv->adapter);
2184   }
2185
2186   return ret;
2187 }
2188
2189 /* small helper that checks whether we have been trying to resync too long */
2190 static inline GstFlowReturn
2191 gst_base_parse_check_sync (GstBaseParse * parse)
2192 {
2193   if (G_UNLIKELY (parse->priv->discont &&
2194           parse->priv->offset - parse->priv->sync_offset > 2 * 1024 * 1024)) {
2195     GST_ELEMENT_ERROR (parse, STREAM, DECODE,
2196         ("Failed to parse stream"), (NULL));
2197     return GST_FLOW_ERROR;
2198   }
2199
2200   return GST_FLOW_OK;
2201 }
2202
2203 static GstFlowReturn
2204 gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
2205 {
2206   GstBaseParseClass *bclass;
2207   GstBaseParse *parse;
2208   GstFlowReturn ret = GST_FLOW_OK;
2209   GstBuffer *outbuf = NULL;
2210   GstBuffer *tmpbuf = NULL;
2211   guint fsize = 1;
2212   gint skip = -1;
2213   const guint8 *data;
2214   guint old_min_size = 0, min_size, av;
2215   GstClockTime timestamp;
2216   GstBaseParseFrame *frame;
2217
2218   parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad));
2219   bclass = GST_BASE_PARSE_GET_CLASS (parse);
2220
2221   if (parse->priv->detecting) {
2222     GstBuffer *detect_buf;
2223
2224     if (parse->priv->detect_buffers_size == 0) {
2225       detect_buf = gst_buffer_ref (buffer);
2226     } else {
2227       GList *l;
2228       guint offset = 0;
2229
2230       detect_buf =
2231           gst_buffer_new_and_alloc (parse->priv->detect_buffers_size +
2232           (buffer ? GST_BUFFER_SIZE (buffer) : 0));
2233       for (l = parse->priv->detect_buffers; l; l = l->next) {
2234         memcpy (GST_BUFFER_DATA (detect_buf) + offset,
2235             GST_BUFFER_DATA (l->data), GST_BUFFER_SIZE (l->data));
2236         offset += GST_BUFFER_SIZE (l->data);
2237       }
2238       if (buffer)
2239         memcpy (GST_BUFFER_DATA (detect_buf) + offset, GST_BUFFER_DATA (buffer),
2240             GST_BUFFER_SIZE (buffer));
2241     }
2242
2243     ret = bclass->detect (parse, detect_buf);
2244     gst_buffer_unref (detect_buf);
2245
2246     if (ret == GST_FLOW_OK) {
2247       GList *l;
2248
2249       /* Detected something */
2250       parse->priv->detecting = FALSE;
2251
2252       for (l = parse->priv->detect_buffers; l; l = l->next) {
2253         if (ret == GST_FLOW_OK && !parse->priv->flushing)
2254           ret =
2255               gst_base_parse_chain (GST_BASE_PARSE_SINK_PAD (parse),
2256               GST_BUFFER_CAST (l->data));
2257         else
2258           gst_buffer_unref (GST_BUFFER_CAST (l->data));
2259       }
2260       g_list_free (parse->priv->detect_buffers);
2261       parse->priv->detect_buffers = NULL;
2262       parse->priv->detect_buffers_size = 0;
2263
2264       if (ret != GST_FLOW_OK) {
2265         return ret;
2266       }
2267
2268       /* Handle the current buffer */
2269     } else if (ret == GST_FLOW_NOT_NEGOTIATED) {
2270       /* Still detecting, append buffer or error out if draining */
2271
2272       if (parse->priv->drain) {
2273         GST_DEBUG_OBJECT (parse, "Draining but did not detect format yet");
2274         return GST_FLOW_ERROR;
2275       } else if (parse->priv->flushing) {
2276         g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref,
2277             NULL);
2278         g_list_free (parse->priv->detect_buffers);
2279         parse->priv->detect_buffers = NULL;
2280         parse->priv->detect_buffers_size = 0;
2281       } else {
2282         parse->priv->detect_buffers =
2283             g_list_append (parse->priv->detect_buffers, buffer);
2284         parse->priv->detect_buffers_size += GST_BUFFER_SIZE (buffer);
2285         return GST_FLOW_OK;
2286       }
2287     } else {
2288       /* Something went wrong, subclass responsible for error reporting */
2289       return ret;
2290     }
2291
2292     /* And now handle the current buffer if detection worked */
2293   }
2294
2295   frame = &parse->priv->frame;
2296
2297   if (G_LIKELY (buffer)) {
2298     GST_LOG_OBJECT (parse, "buffer size: %d, offset = %" G_GINT64_FORMAT,
2299         GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
2300     if (G_UNLIKELY (parse->priv->passthrough)) {
2301       gst_base_parse_frame_init (frame);
2302       frame->buffer = gst_buffer_make_metadata_writable (buffer);
2303       return gst_base_parse_push_frame (parse, frame);
2304     }
2305     /* upstream feeding us in reverse playback;
2306      * gather each fragment, then process it in single run */
2307     if (parse->segment.rate < 0.0) {
2308       if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
2309         GST_DEBUG_OBJECT (parse, "buffer starts new reverse playback fragment");
2310         ret = gst_base_parse_process_fragment (parse, FALSE);
2311       }
2312       gst_adapter_push (parse->priv->adapter, buffer);
2313       return ret;
2314     }
2315     gst_adapter_push (parse->priv->adapter, buffer);
2316   }
2317
2318   if (G_UNLIKELY (buffer &&
2319           GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
2320     frame->_private_flags |= GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
2321     gst_base_parse_frame_free (frame);
2322   }
2323
2324   /* Parse and push as many frames as possible */
2325   /* Stop either when adapter is empty or we are flushing */
2326   while (!parse->priv->flushing) {
2327     gboolean res;
2328
2329     /* maintain frame state for a single frame parsing round across _chain calls,
2330      * so only init when needed */
2331     if (!frame->_private_flags)
2332       gst_base_parse_frame_init (frame);
2333
2334     tmpbuf = gst_buffer_new ();
2335
2336     old_min_size = 0;
2337     /* Synchronization loop */
2338     for (;;) {
2339       /* note: if subclass indicates MAX fsize,
2340        * this will not likely be available anyway ... */
2341       min_size = MAX (parse->priv->min_frame_size, fsize);
2342       av = gst_adapter_available (parse->priv->adapter);
2343
2344       /* loop safety check */
2345       if (G_UNLIKELY (old_min_size >= min_size))
2346         goto invalid_min;
2347       old_min_size = min_size;
2348
2349       if (G_UNLIKELY (parse->priv->drain)) {
2350         min_size = av;
2351         GST_DEBUG_OBJECT (parse, "draining, data left: %d", min_size);
2352         if (G_UNLIKELY (!min_size)) {
2353           gst_buffer_unref (tmpbuf);
2354           goto done;
2355         }
2356       }
2357
2358       /* Collect at least min_frame_size bytes */
2359       if (av < min_size) {
2360         GST_DEBUG_OBJECT (parse, "not enough data available (only %d bytes)",
2361             av);
2362         gst_buffer_unref (tmpbuf);
2363         goto done;
2364       }
2365
2366       /* always pass all available data */
2367       data = gst_adapter_peek (parse->priv->adapter, av);
2368       GST_BUFFER_DATA (tmpbuf) = (guint8 *) data;
2369       GST_BUFFER_SIZE (tmpbuf) = av;
2370       GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset;
2371       GST_BUFFER_FLAG_SET (tmpbuf, GST_MINI_OBJECT_FLAG_READONLY);
2372
2373       if (parse->priv->discont) {
2374         GST_DEBUG_OBJECT (parse, "marking DISCONT");
2375         GST_BUFFER_FLAG_SET (tmpbuf, GST_BUFFER_FLAG_DISCONT);
2376       }
2377
2378       skip = -1;
2379       gst_base_parse_frame_update (parse, frame, tmpbuf);
2380       res = bclass->check_valid_frame (parse, frame, &fsize, &skip);
2381       gst_buffer_replace (&frame->buffer, NULL);
2382       if (res) {
2383         if (gst_adapter_available (parse->priv->adapter) < fsize) {
2384           GST_DEBUG_OBJECT (parse,
2385               "found valid frame but not enough data available (only %d bytes)",
2386               gst_adapter_available (parse->priv->adapter));
2387           gst_buffer_unref (tmpbuf);
2388           goto done;
2389         }
2390         GST_LOG_OBJECT (parse, "valid frame of size %d at pos %d", fsize, skip);
2391         break;
2392       }
2393       if (skip == -1) {
2394         /* subclass didn't touch this value. By default we skip 1 byte */
2395         skip = 1;
2396       }
2397       if (skip > 0) {
2398         GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
2399         if (parse->segment.rate < 0.0 && !parse->priv->buffers_queued) {
2400           /* reverse playback, and no frames found yet, so we are skipping
2401            * the leading part of a fragment, which may form the tail of
2402            * fragment coming later, hopefully subclass skips efficiently ... */
2403           timestamp = gst_adapter_prev_timestamp (parse->priv->adapter, NULL);
2404           outbuf = gst_adapter_take_buffer (parse->priv->adapter, skip);
2405           outbuf = gst_buffer_make_metadata_writable (outbuf);
2406           GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
2407           parse->priv->buffers_pending =
2408               g_slist_prepend (parse->priv->buffers_pending, outbuf);
2409           outbuf = NULL;
2410         } else {
2411           gst_adapter_flush (parse->priv->adapter, skip);
2412         }
2413         parse->priv->offset += skip;
2414         if (!parse->priv->discont)
2415           parse->priv->sync_offset = parse->priv->offset;
2416         parse->priv->discont = TRUE;
2417         /* something changed least; nullify loop check */
2418         old_min_size = 0;
2419       }
2420       /* skip == 0 should imply subclass set min_size to need more data;
2421        * we check this shortly */
2422       if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) {
2423         gst_buffer_unref (tmpbuf);
2424         goto done;
2425       }
2426     }
2427     gst_buffer_unref (tmpbuf);
2428     tmpbuf = NULL;
2429
2430     if (skip > 0) {
2431       /* Subclass found the sync, but still wants to skip some data */
2432       GST_LOG_OBJECT (parse, "skipping %d bytes", skip);
2433       gst_adapter_flush (parse->priv->adapter, skip);
2434       parse->priv->offset += skip;
2435     }
2436
2437     /* Grab lock to prevent a race with FLUSH_START handler */
2438     GST_PAD_STREAM_LOCK (parse->srcpad);
2439
2440     /* FLUSH_START event causes the "flushing" flag to be set. In this
2441      * case we can leave the frame pushing loop */
2442     if (parse->priv->flushing) {
2443       GST_PAD_STREAM_UNLOCK (parse->srcpad);
2444       break;
2445     }
2446
2447     /* move along with upstream timestamp (if any),
2448      * but interpolate in between */
2449     timestamp = gst_adapter_prev_timestamp (parse->priv->adapter, NULL);
2450     if (GST_CLOCK_TIME_IS_VALID (timestamp) &&
2451         (parse->priv->prev_ts != timestamp)) {
2452       parse->priv->prev_ts = parse->priv->next_ts = timestamp;
2453     }
2454
2455     /* FIXME: Would it be more efficient to make a subbuffer instead? */
2456     outbuf = gst_adapter_take_buffer (parse->priv->adapter, fsize);
2457     outbuf = gst_buffer_make_metadata_writable (outbuf);
2458
2459     /* Subclass may want to know the data offset */
2460     GST_BUFFER_OFFSET (outbuf) = parse->priv->offset;
2461     parse->priv->offset += fsize;
2462     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
2463     GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
2464
2465     frame->buffer = outbuf;
2466     ret = gst_base_parse_handle_and_push_frame (parse, bclass, frame);
2467     GST_PAD_STREAM_UNLOCK (parse->srcpad);
2468
2469     if (ret != GST_FLOW_OK) {
2470       GST_LOG_OBJECT (parse, "push returned %d", ret);
2471       break;
2472     }
2473   }
2474
2475 done:
2476   GST_LOG_OBJECT (parse, "chain leaving");
2477   return ret;
2478
2479   /* ERRORS */
2480 invalid_min:
2481   {
2482     GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
2483         ("min_size evolution %d -> %d; breaking to avoid looping",
2484             old_min_size, min_size));
2485     return GST_FLOW_ERROR;
2486   }
2487 }
2488
2489 /* pull @size bytes at current offset,
2490  * i.e. at least try to and possibly return a shorter buffer if near the end */
2491 static GstFlowReturn
2492 gst_base_parse_pull_range (GstBaseParse * parse, guint size,
2493     GstBuffer ** buffer)
2494 {
2495   GstFlowReturn ret = GST_FLOW_OK;
2496
2497   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
2498
2499   /* Caching here actually makes much less difference than one would expect.
2500    * We do it mainly to avoid pulling buffers of 1 byte all the time */
2501   if (parse->priv->cache) {
2502     gint64 cache_offset = GST_BUFFER_OFFSET (parse->priv->cache);
2503     gint cache_size = GST_BUFFER_SIZE (parse->priv->cache);
2504
2505     if (cache_offset <= parse->priv->offset &&
2506         (parse->priv->offset + size) <= (cache_offset + cache_size)) {
2507       *buffer = gst_buffer_create_sub (parse->priv->cache,
2508           parse->priv->offset - cache_offset, size);
2509       GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
2510       return GST_FLOW_OK;
2511     }
2512     /* not enough data in the cache, free cache and get a new one */
2513     gst_buffer_unref (parse->priv->cache);
2514     parse->priv->cache = NULL;
2515   }
2516
2517   /* refill the cache */
2518   ret =
2519       gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size,
2520           64 * 1024), &parse->priv->cache);
2521   if (ret != GST_FLOW_OK) {
2522     parse->priv->cache = NULL;
2523     return ret;
2524   }
2525
2526   if (GST_BUFFER_SIZE (parse->priv->cache) >= size) {
2527     *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
2528     GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
2529     return GST_FLOW_OK;
2530   }
2531
2532   /* Not possible to get enough data, try a last time with
2533    * requesting exactly the size we need */
2534   gst_buffer_unref (parse->priv->cache);
2535   parse->priv->cache = NULL;
2536
2537   ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, size,
2538       &parse->priv->cache);
2539
2540   if (ret != GST_FLOW_OK) {
2541     GST_DEBUG_OBJECT (parse, "pull_range returned %d", ret);
2542     *buffer = NULL;
2543     return ret;
2544   }
2545
2546   if (GST_BUFFER_SIZE (parse->priv->cache) < size) {
2547     GST_DEBUG_OBJECT (parse, "Returning short buffer at offset %"
2548         G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", parse->priv->offset,
2549         size, GST_BUFFER_SIZE (parse->priv->cache));
2550
2551     *buffer = parse->priv->cache;
2552     parse->priv->cache = NULL;
2553
2554     return GST_FLOW_OK;
2555   }
2556
2557   *buffer = gst_buffer_create_sub (parse->priv->cache, 0, size);
2558   GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
2559
2560   return GST_FLOW_OK;
2561 }
2562
2563 static GstFlowReturn
2564 gst_base_parse_handle_previous_fragment (GstBaseParse * parse)
2565 {
2566   gint64 offset = 0;
2567   GstClockTime ts = 0;
2568   GstBuffer *buffer;
2569   GstFlowReturn ret;
2570
2571   GST_DEBUG_OBJECT (parse, "fragment ended; last_ts = %" GST_TIME_FORMAT
2572       ", last_offset = %" G_GINT64_FORMAT, GST_TIME_ARGS (parse->priv->last_ts),
2573       parse->priv->last_offset);
2574
2575   if (!parse->priv->last_offset || parse->priv->last_ts <= parse->segment.start) {
2576     GST_DEBUG_OBJECT (parse, "past start of segment %" GST_TIME_FORMAT,
2577         GST_TIME_ARGS (parse->segment.start));
2578     ret = GST_FLOW_UNEXPECTED;
2579     goto exit;
2580   }
2581
2582   /* last fragment started at last_offset / last_ts;
2583    * seek back 10s capped at 1MB */
2584   if (parse->priv->last_ts >= 10 * GST_SECOND)
2585     ts = parse->priv->last_ts - 10 * GST_SECOND;
2586   /* if we are exact now, we will be more so going backwards */
2587   if (parse->priv->exact_position) {
2588     offset = gst_base_parse_find_offset (parse, ts, TRUE, NULL);
2589   } else {
2590     GstFormat dstformat = GST_FORMAT_BYTES;
2591
2592     if (!gst_pad_query_convert (parse->srcpad, GST_FORMAT_TIME, ts,
2593             &dstformat, &offset)) {
2594       GST_DEBUG_OBJECT (parse, "conversion failed, only BYTE based");
2595     }
2596   }
2597   offset = CLAMP (offset, parse->priv->last_offset - 1024 * 1024,
2598       parse->priv->last_offset - 1024);
2599   offset = MAX (0, offset);
2600
2601   GST_DEBUG_OBJECT (parse, "next fragment from offset %" G_GINT64_FORMAT,
2602       offset);
2603   parse->priv->offset = offset;
2604
2605   ret = gst_base_parse_pull_range (parse, parse->priv->last_offset - offset,
2606       &buffer);
2607   if (ret != GST_FLOW_OK)
2608     goto exit;
2609
2610   /* offset will increase again as fragment is processed/parsed */
2611   parse->priv->last_offset = offset;
2612
2613   gst_adapter_push (parse->priv->adapter, buffer);
2614   ret = gst_base_parse_process_fragment (parse, FALSE);
2615   if (ret != GST_FLOW_OK)
2616     goto exit;
2617
2618   /* force previous fragment */
2619   parse->priv->offset = -1;
2620
2621 exit:
2622   return ret;
2623 }
2624
2625 /* PULL mode:
2626  * pull and scan for next frame starting from current offset
2627  * ajusts sync, drain and offset going along */
2628 static GstFlowReturn
2629 gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass,
2630     GstBaseParseFrame * frame, gboolean full)
2631 {
2632   GstBuffer *buffer, *outbuf;
2633   GstFlowReturn ret = GST_FLOW_OK;
2634   guint fsize = 1, min_size, old_min_size = 0;
2635   gint skip = 0;
2636
2637   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
2638
2639   GST_LOG_OBJECT (parse, "scanning for frame at offset %" G_GUINT64_FORMAT
2640       " (%#" G_GINT64_MODIFIER "x)", parse->priv->offset, parse->priv->offset);
2641
2642   /* let's make this efficient for all subclass once and for all;
2643    * maybe it does not need this much, but in the latter case, we know we are
2644    * in pull mode here and might as well try to read and supply more anyway
2645    * (so does the buffer caching mechanism) */
2646   fsize = 64 * 1024;
2647
2648   while (TRUE) {
2649     gboolean res;
2650
2651     min_size = MAX (parse->priv->min_frame_size, fsize);
2652     /* loop safety check */
2653     if (G_UNLIKELY (old_min_size >= min_size))
2654       goto invalid_min;
2655     old_min_size = min_size;
2656
2657     ret = gst_base_parse_pull_range (parse, min_size, &buffer);
2658     if (ret != GST_FLOW_OK)
2659       goto done;
2660
2661     if (parse->priv->discont) {
2662       GST_DEBUG_OBJECT (parse, "marking DISCONT");
2663       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
2664     }
2665
2666     /* if we got a short read, inform subclass we are draining leftover
2667      * and no more is to be expected */
2668     if (GST_BUFFER_SIZE (buffer) < min_size)
2669       parse->priv->drain = TRUE;
2670
2671     if (parse->priv->detecting) {
2672       ret = klass->detect (parse, buffer);
2673       if (ret == GST_FLOW_NOT_NEGOTIATED) {
2674         /* If draining we error out, otherwise request a buffer
2675          * with 64kb more */
2676         if (parse->priv->drain) {
2677           gst_buffer_unref (buffer);
2678           GST_ERROR_OBJECT (parse, "Failed to detect format but draining");
2679           return GST_FLOW_ERROR;
2680         } else {
2681           fsize += 64 * 1024;
2682           gst_buffer_unref (buffer);
2683           continue;
2684         }
2685       } else if (ret != GST_FLOW_OK) {
2686         gst_buffer_unref (buffer);
2687         GST_ERROR_OBJECT (parse, "detect() returned %s",
2688             gst_flow_get_name (ret));
2689         return ret;
2690       }
2691
2692       /* Else handle this buffer normally */
2693     }
2694
2695     skip = -1;
2696     gst_base_parse_frame_update (parse, frame, buffer);
2697     res = klass->check_valid_frame (parse, frame, &fsize, &skip);
2698     gst_buffer_replace (&frame->buffer, NULL);
2699     if (res) {
2700       parse->priv->drain = FALSE;
2701       GST_LOG_OBJECT (parse, "valid frame of size %d at pos %d", fsize, skip);
2702       break;
2703     }
2704     parse->priv->drain = FALSE;
2705     if (skip == -1)
2706       skip = 1;
2707     if (skip > 0) {
2708       GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", skip);
2709       if (full && parse->segment.rate < 0.0 && !parse->priv->buffers_queued) {
2710         /* reverse playback, and no frames found yet, so we are skipping
2711          * the leading part of a fragment, which may form the tail of
2712          * fragment coming later, hopefully subclass skips efficiently ... */
2713         outbuf = gst_buffer_create_sub (buffer, 0, skip);
2714         parse->priv->buffers_pending =
2715             g_slist_prepend (parse->priv->buffers_pending, outbuf);
2716         outbuf = NULL;
2717       }
2718       parse->priv->offset += skip;
2719       if (!parse->priv->discont)
2720         parse->priv->sync_offset = parse->priv->offset;
2721       parse->priv->discont = TRUE;
2722       /* something changed at least; nullify loop check */
2723       if (fsize == G_MAXUINT)
2724         fsize = old_min_size + 64 * 1024;
2725       old_min_size = 0;
2726     }
2727     /* skip == 0 should imply subclass set min_size to need more data;
2728      * we check this shortly */
2729     GST_DEBUG_OBJECT (parse, "finding sync...");
2730     gst_buffer_unref (buffer);
2731     if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) {
2732       goto done;
2733     }
2734   }
2735
2736   /* Does the subclass want to skip too? */
2737   if (skip > 0)
2738     parse->priv->offset += skip;
2739   else if (skip < 0)
2740     skip = 0;
2741
2742   if (fsize + skip <= GST_BUFFER_SIZE (buffer)) {
2743     outbuf = gst_buffer_create_sub (buffer, skip, fsize);
2744     GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer) + skip;
2745     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
2746     gst_buffer_unref (buffer);
2747   } else {
2748     gst_buffer_unref (buffer);
2749     ret = gst_base_parse_pull_range (parse, fsize, &outbuf);
2750     if (ret != GST_FLOW_OK)
2751       goto done;
2752     if (GST_BUFFER_SIZE (outbuf) < fsize) {
2753       gst_buffer_unref (outbuf);
2754       ret = GST_FLOW_UNEXPECTED;
2755     }
2756   }
2757
2758   parse->priv->offset += fsize;
2759
2760   frame->buffer = outbuf;
2761
2762 done:
2763   return ret;
2764
2765   /* ERRORS */
2766 invalid_min:
2767   {
2768     GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
2769         ("min_size evolution %d -> %d; breaking to avoid looping",
2770             old_min_size, min_size));
2771     return GST_FLOW_ERROR;
2772   }
2773 }
2774
2775 /* Loop that is used in pull mode to retrieve data from upstream */
2776 static void
2777 gst_base_parse_loop (GstPad * pad)
2778 {
2779   GstBaseParse *parse;
2780   GstBaseParseClass *klass;
2781   GstFlowReturn ret = GST_FLOW_OK;
2782   GstBaseParseFrame frame;
2783
2784   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
2785   klass = GST_BASE_PARSE_GET_CLASS (parse);
2786
2787   /* reverse playback:
2788    * first fragment (closest to stop time) is handled normally below,
2789    * then we pull in fragments going backwards */
2790   if (parse->segment.rate < 0.0) {
2791     /* check if we jumped back to a previous fragment,
2792      * which is a post-first fragment */
2793     if (parse->priv->offset < 0) {
2794       ret = gst_base_parse_handle_previous_fragment (parse);
2795       goto done;
2796     }
2797   }
2798
2799   gst_base_parse_frame_init (&frame);
2800   ret = gst_base_parse_scan_frame (parse, klass, &frame, TRUE);
2801   if (ret != GST_FLOW_OK)
2802     goto done;
2803
2804   /* This always cleans up frame, even if error occurs */
2805   ret = gst_base_parse_handle_and_push_frame (parse, klass, &frame);
2806
2807   /* eat expected eos signalling past segment in reverse playback */
2808   if (parse->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
2809       parse->segment.last_stop >= parse->segment.stop) {
2810     GST_DEBUG_OBJECT (parse, "downstream has reached end of segment");
2811     /* push what was accumulated during loop run */
2812     gst_base_parse_process_fragment (parse, TRUE);
2813     /* force previous fragment */
2814     parse->priv->offset = -1;
2815     ret = GST_FLOW_OK;
2816   }
2817
2818 done:
2819   if (ret == GST_FLOW_UNEXPECTED)
2820     goto eos;
2821   else if (ret != GST_FLOW_OK)
2822     goto pause;
2823
2824   gst_object_unref (parse);
2825   return;
2826
2827   /* ERRORS */
2828 eos:
2829   {
2830     ret = GST_FLOW_UNEXPECTED;
2831     GST_DEBUG_OBJECT (parse, "eos");
2832     /* fall-through */
2833   }
2834 pause:
2835   {
2836     gboolean push_eos = FALSE;
2837
2838     GST_DEBUG_OBJECT (parse, "pausing task, reason %s",
2839         gst_flow_get_name (ret));
2840     gst_pad_pause_task (parse->sinkpad);
2841
2842     if (ret == GST_FLOW_UNEXPECTED) {
2843       /* handle end-of-stream/segment */
2844       if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2845         gint64 stop;
2846
2847         if ((stop = parse->segment.stop) == -1)
2848           stop = parse->segment.duration;
2849
2850         GST_DEBUG_OBJECT (parse, "sending segment_done");
2851
2852         gst_element_post_message
2853             (GST_ELEMENT_CAST (parse),
2854             gst_message_new_segment_done (GST_OBJECT_CAST (parse),
2855                 GST_FORMAT_TIME, stop));
2856       } else {
2857         /* If we STILL have zero frames processed, fire an error */
2858         if (parse->priv->framecount == 0) {
2859           GST_ELEMENT_ERROR (parse, STREAM, WRONG_TYPE,
2860               ("No valid frames found before end of stream"), (NULL));
2861         }
2862         push_eos = TRUE;
2863       }
2864     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2865       /* for fatal errors we post an error message, wrong-state is
2866        * not fatal because it happens due to flushes and only means
2867        * that we should stop now. */
2868       GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL),
2869           ("streaming stopped, reason %s", gst_flow_get_name (ret)));
2870       push_eos = TRUE;
2871     }
2872     if (push_eos) {
2873       /* Push pending events, including NEWSEGMENT events */
2874       if (G_UNLIKELY (parse->priv->pending_events)) {
2875         GList *l;
2876
2877         for (l = parse->priv->pending_events; l != NULL; l = l->next) {
2878           gst_pad_push_event (parse->srcpad, GST_EVENT (l->data));
2879         }
2880         g_list_free (parse->priv->pending_events);
2881         parse->priv->pending_events = NULL;
2882         parse->priv->pending_segment = FALSE;
2883       }
2884
2885       gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
2886     }
2887     gst_object_unref (parse);
2888   }
2889 }
2890
2891 static gboolean
2892 gst_base_parse_sink_activate (GstPad * sinkpad)
2893 {
2894   GstBaseParse *parse;
2895   gboolean result = TRUE;
2896
2897   parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
2898
2899   GST_DEBUG_OBJECT (parse, "sink activate");
2900
2901   if (gst_pad_check_pull_range (sinkpad)) {
2902     GST_DEBUG_OBJECT (parse, "trying to activate in pull mode");
2903     result = gst_pad_activate_pull (sinkpad, TRUE);
2904   } else {
2905     GST_DEBUG_OBJECT (parse, "trying to activate in push mode");
2906     result = gst_pad_activate_push (sinkpad, TRUE);
2907   }
2908
2909   GST_DEBUG_OBJECT (parse, "sink activate return %d", result);
2910   gst_object_unref (parse);
2911   return result;
2912 }
2913
2914 static gboolean
2915 gst_base_parse_activate (GstBaseParse * parse, gboolean active)
2916 {
2917   GstBaseParseClass *klass;
2918   gboolean result = TRUE;
2919
2920   GST_DEBUG_OBJECT (parse, "activate %d", active);
2921
2922   klass = GST_BASE_PARSE_GET_CLASS (parse);
2923
2924   if (active) {
2925     if (parse->priv->pad_mode == GST_ACTIVATE_NONE && klass->start)
2926       result = klass->start (parse);
2927
2928     /* If the subclass implements ::detect we want to
2929      * call it for the first buffers now */
2930     parse->priv->detecting = (klass->detect != NULL);
2931   } else {
2932     /* We must make sure streaming has finished before resetting things
2933      * and calling the ::stop vfunc */
2934     GST_PAD_STREAM_LOCK (parse->sinkpad);
2935     GST_PAD_STREAM_UNLOCK (parse->sinkpad);
2936
2937     if (parse->priv->pad_mode != GST_ACTIVATE_NONE && klass->stop)
2938       result = klass->stop (parse);
2939
2940     parse->priv->pad_mode = GST_ACTIVATE_NONE;
2941   }
2942   GST_DEBUG_OBJECT (parse, "activate return: %d", result);
2943   return result;
2944 }
2945
2946 static gboolean
2947 gst_base_parse_sink_activate_push (GstPad * pad, gboolean active)
2948 {
2949   gboolean result = TRUE;
2950   GstBaseParse *parse;
2951
2952   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
2953
2954   GST_DEBUG_OBJECT (parse, "sink activate push %d", active);
2955
2956   result = gst_base_parse_activate (parse, active);
2957
2958   if (result)
2959     parse->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2960
2961   GST_DEBUG_OBJECT (parse, "sink activate push return: %d", result);
2962
2963   gst_object_unref (parse);
2964   return result;
2965 }
2966
2967 static gboolean
2968 gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
2969 {
2970   gboolean result = FALSE;
2971   GstBaseParse *parse;
2972
2973   parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad));
2974
2975   GST_DEBUG_OBJECT (parse, "activate pull %d", active);
2976
2977   result = gst_base_parse_activate (parse, active);
2978
2979   if (result) {
2980     if (active) {
2981       GstEvent *event;
2982
2983       event = gst_event_new_new_segment (FALSE,
2984           parse->segment.rate, parse->segment.format,
2985           parse->segment.start, parse->segment.stop, parse->segment.last_stop);
2986       parse->priv->pending_events =
2987           g_list_append (parse->priv->pending_events, event);
2988       parse->priv->pending_segment = TRUE;
2989
2990       result &=
2991           gst_pad_start_task (sinkpad, (GstTaskFunction) gst_base_parse_loop,
2992           sinkpad);
2993     } else {
2994       result &= gst_pad_stop_task (sinkpad);
2995     }
2996   }
2997
2998   if (result)
2999     parse->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
3000
3001   GST_DEBUG_OBJECT (parse, "sink activate pull return: %d", result);
3002
3003   gst_object_unref (parse);
3004   return result;
3005 }
3006
3007
3008 /**
3009  * gst_base_parse_set_duration:
3010  * @parse: #GstBaseParse.
3011  * @fmt: #GstFormat.
3012  * @duration: duration value.
3013  * @interval: how often to update the duration estimate based on bitrate, or 0.
3014  *
3015  * Sets the duration of the currently playing media. Subclass can use this
3016  * when it is able to determine duration and/or notices a change in the media
3017  * duration.  Alternatively, if @interval is non-zero (default), then stream
3018  * duration is determined based on estimated bitrate, and updated every @interval
3019  * frames.
3020  *
3021  * Since: 0.10.33
3022  */
3023 void
3024 gst_base_parse_set_duration (GstBaseParse * parse,
3025     GstFormat fmt, gint64 duration, gint interval)
3026 {
3027   g_return_if_fail (parse != NULL);
3028
3029   if (parse->priv->upstream_has_duration) {
3030     GST_DEBUG_OBJECT (parse, "using upstream duration; discarding update");
3031     goto exit;
3032   }
3033
3034   if (duration != parse->priv->duration) {
3035     GstMessage *m;
3036
3037     m = gst_message_new_duration (GST_OBJECT (parse), fmt, duration);
3038     gst_element_post_message (GST_ELEMENT (parse), m);
3039
3040     /* TODO: what about duration tag? */
3041   }
3042   parse->priv->duration = duration;
3043   parse->priv->duration_fmt = fmt;
3044   GST_DEBUG_OBJECT (parse, "set duration: %" G_GINT64_FORMAT, duration);
3045   if (fmt == GST_FORMAT_TIME && GST_CLOCK_TIME_IS_VALID (duration)) {
3046     if (interval != 0) {
3047       GST_DEBUG_OBJECT (parse, "valid duration provided, disabling estimate");
3048       interval = 0;
3049     }
3050   }
3051   GST_DEBUG_OBJECT (parse, "set update interval: %d", interval);
3052   parse->priv->update_interval = interval;
3053 exit:
3054   return;
3055 }
3056
3057 /**
3058  * gst_base_parse_set_average_bitrate:
3059  * @parse: #GstBaseParse.
3060  * @bitrate: average bitrate in bits/second
3061  *
3062  * Optionally sets the average bitrate detected in media (if non-zero),
3063  * e.g. based on metadata, as it will be posted to the application.
3064  *
3065  * By default, announced average bitrate is estimated. The average bitrate
3066  * is used to estimate the total duration of the stream and to estimate
3067  * a seek position, if there's no index and the format is syncable
3068  * (see gst_base_parse_set_syncable()).
3069  *
3070  * Since: 0.10.33
3071  */
3072 void
3073 gst_base_parse_set_average_bitrate (GstBaseParse * parse, guint bitrate)
3074 {
3075   parse->priv->bitrate = bitrate;
3076   GST_DEBUG_OBJECT (parse, "bitrate %u", bitrate);
3077 }
3078
3079 /**
3080  * gst_base_parse_set_min_frame_size:
3081  * @parse: #GstBaseParse.
3082  * @min_size: Minimum size of the data that this base class should give to
3083  *            subclass.
3084  *
3085  * Subclass can use this function to tell the base class that it needs to
3086  * give at least #min_size buffers.
3087  *
3088  * Since: 0.10.33
3089  */
3090 void
3091 gst_base_parse_set_min_frame_size (GstBaseParse * parse, guint min_size)
3092 {
3093   g_return_if_fail (parse != NULL);
3094
3095   parse->priv->min_frame_size = min_size;
3096   GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size);
3097 }
3098
3099 /**
3100  * gst_base_parse_set_frame_rate:
3101  * @parse: the #GstBaseParse to set
3102  * @fps_num: frames per second (numerator).
3103  * @fps_den: frames per second (denominator).
3104  * @lead_in: frames needed before a segment for subsequent decode
3105  * @lead_out: frames needed after a segment
3106  *
3107  * If frames per second is configured, parser can take care of buffer duration
3108  * and timestamping.  When performing segment clipping, or seeking to a specific
3109  * location, a corresponding decoder might need an initial @lead_in and a
3110  * following @lead_out number of frames to ensure the desired segment is
3111  * entirely filled upon decoding.
3112  *
3113  * Since: 0.10.33
3114  */
3115 void
3116 gst_base_parse_set_frame_rate (GstBaseParse * parse, guint fps_num,
3117     guint fps_den, guint lead_in, guint lead_out)
3118 {
3119   g_return_if_fail (parse != NULL);
3120
3121   parse->priv->fps_num = fps_num;
3122   parse->priv->fps_den = fps_den;
3123   if (!fps_num || !fps_den) {
3124     GST_DEBUG_OBJECT (parse, "invalid fps (%d/%d), ignoring parameters",
3125         fps_num, fps_den);
3126     fps_num = fps_den = 0;
3127     parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
3128     parse->priv->lead_in = parse->priv->lead_out = 0;
3129     parse->priv->lead_in_ts = parse->priv->lead_out_ts = 0;
3130   } else {
3131     parse->priv->frame_duration =
3132         gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
3133     parse->priv->lead_in = lead_in;
3134     parse->priv->lead_out = lead_out;
3135     parse->priv->lead_in_ts =
3136         gst_util_uint64_scale (GST_SECOND, fps_den * lead_in, fps_num);
3137     parse->priv->lead_out_ts =
3138         gst_util_uint64_scale (GST_SECOND, fps_den * lead_out, fps_num);
3139     /* aim for about 1.5s to estimate duration */
3140     if (parse->priv->update_interval < 0) {
3141       parse->priv->update_interval = fps_num * 3 / (fps_den * 2);
3142       GST_LOG_OBJECT (parse, "estimated update interval to %d frames",
3143           parse->priv->update_interval);
3144     }
3145   }
3146   GST_LOG_OBJECT (parse, "set fps: %d/%d => duration: %" G_GINT64_FORMAT " ms",
3147       fps_num, fps_den, parse->priv->frame_duration / GST_MSECOND);
3148   GST_LOG_OBJECT (parse, "set lead in: %d frames = %" G_GUINT64_FORMAT " ms, "
3149       "lead out: %d frames = %" G_GUINT64_FORMAT " ms",
3150       lead_in, parse->priv->lead_in_ts / GST_MSECOND,
3151       lead_out, parse->priv->lead_out_ts / GST_MSECOND);
3152 }
3153
3154 /**
3155  * gst_base_parse_set_has_timing_info:
3156  * @parse: a #GstBaseParse
3157  * @has_timing: whether frames carry timing information
3158  *
3159  * Set if frames carry timing information which the subclass can (generally)
3160  * parse and provide.  In particular, intrinsic (rather than estimated) time
3161  * can be obtained following a seek.
3162  *
3163  * Since: 0.10.33
3164  */
3165 void
3166 gst_base_parse_set_has_timing_info (GstBaseParse * parse, gboolean has_timing)
3167 {
3168   parse->priv->has_timing_info = has_timing;
3169   GST_INFO_OBJECT (parse, "has_timing: %s", (has_timing) ? "yes" : "no");
3170 }
3171
3172 /**
3173  * gst_base_parse_set_syncable:
3174  * @parse: a #GstBaseParse
3175  * @syncable: set if frame starts can be identified
3176  *
3177  * Set if frame starts can be identified. This is set by default and
3178  * determines whether seeking based on bitrate averages
3179  * is possible for a format/stream.
3180  *
3181  * Since: 0.10.33
3182  */
3183 void
3184 gst_base_parse_set_syncable (GstBaseParse * parse, gboolean syncable)
3185 {
3186   parse->priv->syncable = syncable;
3187   GST_INFO_OBJECT (parse, "syncable: %s", (syncable) ? "yes" : "no");
3188 }
3189
3190 /**
3191  * gst_base_parse_set_passthrough:
3192  * @parse: a #GstBaseParse
3193  * @passthrough: %TRUE if parser should run in passthrough mode
3194  *
3195  * Set if the nature of the format or configuration does not allow (much)
3196  * parsing, and the parser should operate in passthrough mode (which only
3197  * applies when operating in push mode). That is, incoming buffers are
3198  * pushed through unmodified, i.e. no @check_valid_frame or @parse_frame
3199  * callbacks will be invoked, but @pre_push_frame will still be invoked,
3200  * so subclass can perform as much or as little is appropriate for
3201  * passthrough semantics in @pre_push_frame.
3202  *
3203  * Since: 0.10.33
3204  */
3205 void
3206 gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough)
3207 {
3208   parse->priv->passthrough = passthrough;
3209   GST_INFO_OBJECT (parse, "passthrough: %s", (passthrough) ? "yes" : "no");
3210 }
3211
3212 /**
3213  * gst_base_parse_set_latency:
3214  * @parse: a #GstBaseParse
3215  * @min_latency: minimum parse latency
3216  * @max_latency: maximum parse latency
3217  *
3218  * Sets the minimum and maximum (which may likely be equal) latency introduced
3219  * by the parsing process.  If there is such a latency, which depends on the
3220  * particular parsing of the format, it typically corresponds to 1 frame duration.
3221  *
3222  * Since: 0.10.36
3223  */
3224 void
3225 gst_base_parse_set_latency (GstBaseParse * parse, GstClockTime min_latency,
3226     GstClockTime max_latency)
3227 {
3228   GST_OBJECT_LOCK (parse);
3229   parse->priv->min_latency = min_latency;
3230   parse->priv->max_latency = max_latency;
3231   GST_OBJECT_UNLOCK (parse);
3232   GST_INFO_OBJECT (parse, "min/max latency %" GST_TIME_FORMAT ", %"
3233       GST_TIME_FORMAT, GST_TIME_ARGS (min_latency),
3234       GST_TIME_ARGS (max_latency));
3235 }
3236
3237 static gboolean
3238 gst_base_parse_get_duration (GstBaseParse * parse, GstFormat format,
3239     GstClockTime * duration)
3240 {
3241   gboolean res = FALSE;
3242
3243   g_return_val_if_fail (duration != NULL, FALSE);
3244
3245   *duration = GST_CLOCK_TIME_NONE;
3246   if (parse->priv->duration != -1 && format == parse->priv->duration_fmt) {
3247     GST_LOG_OBJECT (parse, "using provided duration");
3248     *duration = parse->priv->duration;
3249     res = TRUE;
3250   } else if (parse->priv->duration != -1) {
3251     GST_LOG_OBJECT (parse, "converting provided duration");
3252     res = gst_base_parse_convert (parse, parse->priv->duration_fmt,
3253         parse->priv->duration, format, (gint64 *) duration);
3254   } else if (format == GST_FORMAT_TIME && parse->priv->estimated_duration != -1) {
3255     GST_LOG_OBJECT (parse, "using estimated duration");
3256     *duration = parse->priv->estimated_duration;
3257     res = TRUE;
3258   }
3259
3260   GST_LOG_OBJECT (parse, "res: %d, duration %" GST_TIME_FORMAT, res,
3261       GST_TIME_ARGS (*duration));
3262   return res;
3263 }
3264
3265 static const GstQueryType *
3266 gst_base_parse_get_querytypes (GstPad * pad)
3267 {
3268   static const GstQueryType list[] = {
3269     GST_QUERY_POSITION,
3270     GST_QUERY_DURATION,
3271     GST_QUERY_FORMATS,
3272     GST_QUERY_SEEKING,
3273     GST_QUERY_CONVERT,
3274     GST_QUERY_NONE
3275   };
3276
3277   return list;
3278 }
3279
3280 static gboolean
3281 gst_base_parse_query (GstPad * pad, GstQuery * query)
3282 {
3283   GstBaseParse *parse;
3284   gboolean res = FALSE;
3285
3286   parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
3287
3288   GST_LOG_OBJECT (parse, "handling query: %" GST_PTR_FORMAT, query);
3289
3290   switch (GST_QUERY_TYPE (query)) {
3291     case GST_QUERY_POSITION:
3292     {
3293       gint64 dest_value;
3294       GstFormat format;
3295
3296       GST_DEBUG_OBJECT (parse, "position query");
3297       gst_query_parse_position (query, &format, NULL);
3298
3299       /* try upstream first */
3300       res = gst_pad_query_default (pad, query);
3301       if (!res) {
3302         /* Fall back on interpreting segment */
3303         GST_OBJECT_LOCK (parse);
3304         if (format == GST_FORMAT_BYTES) {
3305           dest_value = parse->priv->offset;
3306           res = TRUE;
3307         } else if (format == parse->segment.format &&
3308             GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop)) {
3309           dest_value = gst_segment_to_stream_time (&parse->segment,
3310               parse->segment.format, parse->segment.last_stop);
3311           res = TRUE;
3312         }
3313         GST_OBJECT_UNLOCK (parse);
3314         if (!res) {
3315           /* no precise result, upstream no idea either, then best estimate */
3316           /* priv->offset is updated in both PUSH/PULL modes */
3317           res = gst_base_parse_convert (parse,
3318               GST_FORMAT_BYTES, parse->priv->offset, format, &dest_value);
3319         }
3320         if (res)
3321           gst_query_set_position (query, format, dest_value);
3322       }
3323       break;
3324     }
3325     case GST_QUERY_DURATION:
3326     {
3327       GstFormat format;
3328       GstClockTime duration;
3329
3330       GST_DEBUG_OBJECT (parse, "duration query");
3331       gst_query_parse_duration (query, &format, NULL);
3332
3333       /* consult upstream */
3334       res = gst_pad_query_default (pad, query);
3335
3336       /* otherwise best estimate from us */
3337       if (!res) {
3338         res = gst_base_parse_get_duration (parse, format, &duration);
3339         if (res)
3340           gst_query_set_duration (query, format, duration);
3341       }
3342       break;
3343     }
3344     case GST_QUERY_SEEKING:
3345     {
3346       GstFormat fmt;
3347       GstClockTime duration = GST_CLOCK_TIME_NONE;
3348       gboolean seekable = FALSE;
3349
3350       GST_DEBUG_OBJECT (parse, "seeking query");
3351       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3352
3353       /* consult upstream */
3354       res = gst_pad_query_default (pad, query);
3355
3356       /* we may be able to help if in TIME */
3357       if (fmt == GST_FORMAT_TIME && gst_base_parse_is_seekable (parse)) {
3358         gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3359         /* already OK if upstream takes care */
3360         GST_LOG_OBJECT (parse, "upstream handled %d, seekable %d",
3361             res, seekable);
3362         if (!(res && seekable)) {
3363           if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &duration)
3364               || duration == -1) {
3365             /* seekable if we still have a chance to get duration later on */
3366             seekable =
3367                 parse->priv->upstream_seekable && parse->priv->update_interval;
3368           } else {
3369             seekable = parse->priv->upstream_seekable;
3370             GST_LOG_OBJECT (parse, "already determine upstream seekabled: %d",
3371                 seekable);
3372           }
3373           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
3374           res = TRUE;
3375         }
3376       }
3377       break;
3378     }
3379     case GST_QUERY_FORMATS:
3380       gst_query_set_formatsv (query, 3, fmtlist);
3381       res = TRUE;
3382       break;
3383     case GST_QUERY_CONVERT:
3384     {
3385       GstFormat src_format, dest_format;
3386       gint64 src_value, dest_value;
3387
3388       gst_query_parse_convert (query, &src_format, &src_value,
3389           &dest_format, &dest_value);
3390
3391       res = gst_base_parse_convert (parse, src_format, src_value,
3392           dest_format, &dest_value);
3393       if (res) {
3394         gst_query_set_convert (query, src_format, src_value,
3395             dest_format, dest_value);
3396       }
3397       break;
3398     }
3399     case GST_QUERY_LATENCY:
3400     {
3401       if ((res = gst_pad_peer_query (parse->sinkpad, query))) {
3402         gboolean live;
3403         GstClockTime min_latency, max_latency;
3404
3405         gst_query_parse_latency (query, &live, &min_latency, &max_latency);
3406         GST_DEBUG_OBJECT (parse, "Peer latency: live %d, min %"
3407             GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3408             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
3409
3410         GST_OBJECT_LOCK (parse);
3411         /* add our latency */
3412         if (min_latency != -1)
3413           min_latency += parse->priv->min_latency;
3414         if (max_latency != -1)
3415           max_latency += parse->priv->max_latency;
3416         GST_OBJECT_UNLOCK (parse);
3417
3418         gst_query_set_latency (query, live, min_latency, max_latency);
3419       }
3420       break;
3421     }
3422     default:
3423       res = gst_pad_query_default (pad, query);
3424       break;
3425   }
3426   return res;
3427 }
3428
3429 /* scans for a cluster start from @pos,
3430  * return GST_FLOW_OK and frame position/time in @pos/@time if found */
3431 static GstFlowReturn
3432 gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos,
3433     GstClockTime * time, GstClockTime * duration)
3434 {
3435   GstBaseParseClass *klass;
3436   gint64 orig_offset;
3437   gboolean orig_drain, orig_discont;
3438   GstFlowReturn ret = GST_FLOW_OK;
3439   GstBuffer *buf = NULL;
3440   GstBaseParseFrame frame;
3441
3442   g_return_val_if_fail (pos != NULL, GST_FLOW_ERROR);
3443   g_return_val_if_fail (time != NULL, GST_FLOW_ERROR);
3444   g_return_val_if_fail (duration != NULL, GST_FLOW_ERROR);
3445
3446   klass = GST_BASE_PARSE_GET_CLASS (parse);
3447
3448   *time = GST_CLOCK_TIME_NONE;
3449   *duration = GST_CLOCK_TIME_NONE;
3450
3451   /* save state */
3452   orig_offset = parse->priv->offset;
3453   orig_discont = parse->priv->discont;
3454   orig_drain = parse->priv->drain;
3455
3456   GST_DEBUG_OBJECT (parse, "scanning for frame starting at %" G_GINT64_FORMAT
3457       " (%#" G_GINT64_MODIFIER "x)", *pos, *pos);
3458
3459   gst_base_parse_frame_init (&frame);
3460
3461   /* jump elsewhere and locate next frame */
3462   parse->priv->offset = *pos;
3463   ret = gst_base_parse_scan_frame (parse, klass, &frame, FALSE);
3464   if (ret != GST_FLOW_OK)
3465     goto done;
3466
3467   buf = frame.buffer;
3468   GST_LOG_OBJECT (parse,
3469       "peek parsing frame at offset %" G_GUINT64_FORMAT
3470       " (%#" G_GINT64_MODIFIER "x) of size %d",
3471       GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
3472
3473   /* get offset first, subclass parsing might dump other stuff in there */
3474   *pos = GST_BUFFER_OFFSET (buf);
3475   ret = klass->parse_frame (parse, &frame);
3476   buf = frame.buffer;
3477
3478   /* but it should provide proper time */
3479   *time = GST_BUFFER_TIMESTAMP (buf);
3480   *duration = GST_BUFFER_DURATION (buf);
3481
3482   gst_base_parse_frame_free (&frame);
3483
3484   GST_LOG_OBJECT (parse,
3485       "frame with time %" GST_TIME_FORMAT " at offset %" G_GINT64_FORMAT,
3486       GST_TIME_ARGS (*time), *pos);
3487
3488 done:
3489   /* restore state */
3490   parse->priv->offset = orig_offset;
3491   parse->priv->discont = orig_discont;
3492   parse->priv->drain = orig_drain;
3493
3494   return ret;
3495 }
3496
3497 /* bisect and scan through file for frame starting before @time,
3498  * returns OK and @time/@offset if found, NONE and/or error otherwise
3499  * If @time == G_MAXINT64, scan for duration ( == last frame) */
3500 static GstFlowReturn
3501 gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time,
3502     gint64 * _offset)
3503 {
3504   GstFlowReturn ret = GST_FLOW_OK;
3505   gint64 lpos, hpos, newpos;
3506   GstClockTime time, ltime, htime, newtime, dur;
3507   gboolean cont = TRUE;
3508   const GstClockTime tolerance = TARGET_DIFFERENCE;
3509   const guint chunk = 4 * 1024;
3510
3511   g_return_val_if_fail (_time != NULL, GST_FLOW_ERROR);
3512   g_return_val_if_fail (_offset != NULL, GST_FLOW_ERROR);
3513
3514   GST_DEBUG_OBJECT (parse, "Bisecting for time %" GST_TIME_FORMAT,
3515       GST_TIME_ARGS (*_time));
3516
3517   /* TODO also make keyframe aware if useful some day */
3518
3519   time = *_time;
3520
3521   /* basic cases */
3522   if (time == 0) {
3523     *_offset = 0;
3524     return GST_FLOW_OK;
3525   }
3526
3527   if (time == -1) {
3528     *_offset = -1;
3529     return GST_FLOW_OK;
3530   }
3531
3532   /* do not know at first */
3533   *_offset = -1;
3534   *_time = GST_CLOCK_TIME_NONE;
3535
3536   /* need initial positions; start and end */
3537   lpos = parse->priv->first_frame_offset;
3538   ltime = parse->priv->first_frame_ts;
3539   if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &htime)) {
3540     GST_DEBUG_OBJECT (parse, "Unknown time duration, cannot bisect");
3541     return GST_FLOW_ERROR;
3542   }
3543   hpos = parse->priv->upstream_size;
3544
3545   GST_DEBUG_OBJECT (parse,
3546       "Bisection initial bounds: bytes %" G_GINT64_FORMAT " %" G_GINT64_FORMAT
3547       ", times %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, lpos, htime,
3548       GST_TIME_ARGS (ltime), GST_TIME_ARGS (htime));
3549
3550   /* check preconditions are satisfied;
3551    * start and end are needed, except for special case where we scan for
3552    * last frame to determine duration */
3553   if (parse->priv->pad_mode != GST_ACTIVATE_PULL || !hpos ||
3554       !GST_CLOCK_TIME_IS_VALID (ltime) ||
3555       (!GST_CLOCK_TIME_IS_VALID (htime) && time != G_MAXINT64)) {
3556     return GST_FLOW_OK;
3557   }
3558
3559   /* shortcut cases */
3560   if (time < ltime) {
3561     goto exit;
3562   } else if (time < ltime + tolerance) {
3563     *_offset = lpos;
3564     *_time = ltime;
3565     goto exit;
3566   } else if (time >= htime) {
3567     *_offset = hpos;
3568     *_time = htime;
3569     goto exit;
3570   }
3571
3572   while (htime > ltime && cont) {
3573     GST_LOG_OBJECT (parse,
3574         "lpos: %" G_GUINT64_FORMAT ", ltime: %" GST_TIME_FORMAT, lpos,
3575         GST_TIME_ARGS (ltime));
3576     GST_LOG_OBJECT (parse,
3577         "hpos: %" G_GUINT64_FORMAT ", htime: %" GST_TIME_FORMAT, hpos,
3578         GST_TIME_ARGS (htime));
3579     if (G_UNLIKELY (time == G_MAXINT64)) {
3580       newpos = hpos;
3581     } else if (G_LIKELY (hpos > lpos)) {
3582       newpos =
3583           gst_util_uint64_scale (hpos - lpos, time - ltime, htime - ltime) +
3584           lpos - chunk;
3585     } else {
3586       /* should mean lpos == hpos, since lpos <= hpos is invariant */
3587       newpos = lpos;
3588       /* we check this case once, but not forever, so break loop */
3589       cont = FALSE;
3590     }
3591
3592     /* ensure */
3593     newpos = CLAMP (newpos, lpos, hpos);
3594     GST_LOG_OBJECT (parse,
3595         "estimated _offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT,
3596         GST_TIME_ARGS (time), newpos);
3597
3598     ret = gst_base_parse_find_frame (parse, &newpos, &newtime, &dur);
3599     if (ret == GST_FLOW_UNEXPECTED) {
3600       /* heuristic HACK */
3601       hpos = MAX (lpos, hpos - chunk);
3602       continue;
3603     } else if (ret != GST_FLOW_OK) {
3604       goto exit;
3605     }
3606
3607     if (newtime == -1 || newpos == -1) {
3608       GST_DEBUG_OBJECT (parse, "subclass did not provide metadata; aborting");
3609       break;
3610     }
3611
3612     if (G_UNLIKELY (time == G_MAXINT64)) {
3613       *_offset = newpos;
3614       *_time = newtime;
3615       if (GST_CLOCK_TIME_IS_VALID (dur))
3616         *_time += dur;
3617       break;
3618     } else if (newtime > time) {
3619       /* overshoot */
3620       hpos = (newpos >= hpos) ? MAX (lpos, hpos - chunk) : MAX (lpos, newpos);
3621       htime = newtime;
3622     } else if (newtime + tolerance > time) {
3623       /* close enough undershoot */
3624       *_offset = newpos;
3625       *_time = newtime;
3626       break;
3627     } else if (newtime < ltime) {
3628       /* so a position beyond lpos resulted in earlier time than ltime ... */
3629       GST_DEBUG_OBJECT (parse, "non-ascending time; aborting");
3630       break;
3631     } else {
3632       /* undershoot too far */
3633       newpos += newpos == lpos ? chunk : 0;
3634       lpos = CLAMP (newpos, lpos, hpos);
3635       ltime = newtime;
3636     }
3637   }
3638
3639 exit:
3640   GST_LOG_OBJECT (parse, "return offset %" G_GINT64_FORMAT ", time %"
3641       GST_TIME_FORMAT, *_offset, GST_TIME_ARGS (*_time));
3642   return ret;
3643 }
3644
3645 static gint64
3646 gst_base_parse_find_offset (GstBaseParse * parse, GstClockTime time,
3647     gboolean before, GstClockTime * _ts)
3648 {
3649   gint64 bytes = 0, ts = 0;
3650   GstIndexEntry *entry = NULL;
3651
3652   if (time == GST_CLOCK_TIME_NONE) {
3653     ts = time;
3654     bytes = -1;
3655     goto exit;
3656   }
3657
3658   GST_BASE_PARSE_INDEX_LOCK (parse);
3659   if (parse->priv->index) {
3660     /* Let's check if we have an index entry for that time */
3661     entry = gst_index_get_assoc_entry (parse->priv->index,
3662         parse->priv->index_id,
3663         before ? GST_INDEX_LOOKUP_BEFORE : GST_INDEX_LOOKUP_AFTER,
3664         GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
3665   }
3666
3667   if (entry) {
3668     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
3669     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &ts);
3670
3671     GST_DEBUG_OBJECT (parse, "found index entry for %" GST_TIME_FORMAT
3672         " at %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT,
3673         GST_TIME_ARGS (time), GST_TIME_ARGS (ts), bytes);
3674   } else {
3675     GST_DEBUG_OBJECT (parse, "no index entry found for %" GST_TIME_FORMAT,
3676         GST_TIME_ARGS (time));
3677     if (!before) {
3678       bytes = -1;
3679       ts = GST_CLOCK_TIME_NONE;
3680     }
3681   }
3682   GST_BASE_PARSE_INDEX_UNLOCK (parse);
3683
3684 exit:
3685   if (_ts)
3686     *_ts = ts;
3687
3688   return bytes;
3689 }
3690
3691 /* returns TRUE if seek succeeded */
3692 static gboolean
3693 gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
3694 {
3695   gdouble rate;
3696   GstFormat format;
3697   GstSeekFlags flags;
3698   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
3699   gboolean flush, update, res = TRUE, accurate;
3700   gint64 cur, stop, seekpos, seekstop;
3701   GstSegment seeksegment = { 0, };
3702   GstFormat dstformat;
3703   GstClockTime start_ts;
3704
3705   gst_event_parse_seek (event, &rate, &format, &flags,
3706       &cur_type, &cur, &stop_type, &stop);
3707
3708   GST_DEBUG_OBJECT (parse, "seek to format %s, rate %f, "
3709       "start type %d at %" GST_TIME_FORMAT ", end type %d at %"
3710       GST_TIME_FORMAT, gst_format_get_name (format), rate,
3711       cur_type, GST_TIME_ARGS (cur), stop_type, GST_TIME_ARGS (stop));
3712
3713   /* no negative rates in push mode */
3714   if (rate < 0.0 && parse->priv->pad_mode == GST_ACTIVATE_PUSH)
3715     goto negative_rate;
3716
3717   if (cur_type != GST_SEEK_TYPE_SET ||
3718       (stop_type != GST_SEEK_TYPE_SET && stop_type != GST_SEEK_TYPE_NONE))
3719     goto wrong_type;
3720
3721   /* For any format other than TIME, see if upstream handles
3722    * it directly or fail. For TIME, try upstream, but do it ourselves if
3723    * it fails upstream */
3724   if (format != GST_FORMAT_TIME) {
3725     /* default action delegates to upstream */
3726     res = FALSE;
3727     goto done;
3728   } else {
3729     gst_event_ref (event);
3730     if ((res = gst_pad_push_event (parse->sinkpad, event))) {
3731       goto done;
3732     }
3733   }
3734
3735   /* get flush flag */
3736   flush = flags & GST_SEEK_FLAG_FLUSH;
3737
3738   /* copy segment, we need this because we still need the old
3739    * segment when we close the current segment. */
3740   memcpy (&seeksegment, &parse->segment, sizeof (GstSegment));
3741
3742   GST_DEBUG_OBJECT (parse, "configuring seek");
3743   gst_segment_set_seek (&seeksegment, rate, format, flags,
3744       cur_type, cur, stop_type, stop, &update);
3745
3746   /* accurate seeking implies seek tables are used to obtain position,
3747    * and the requested segment is maintained exactly, not adjusted any way */
3748   accurate = flags & GST_SEEK_FLAG_ACCURATE;
3749
3750   /* maybe we can be accurate for (almost) free */
3751   gst_base_parse_find_offset (parse, seeksegment.last_stop, TRUE, &start_ts);
3752   if (seeksegment.last_stop <= start_ts + TARGET_DIFFERENCE) {
3753     GST_DEBUG_OBJECT (parse, "accurate seek possible");
3754     accurate = TRUE;
3755   }
3756   if (accurate) {
3757     GstClockTime startpos = seeksegment.last_stop;
3758
3759     /* accurate requested, so ... seek a bit before target */
3760     if (startpos < parse->priv->lead_in_ts)
3761       startpos = 0;
3762     else
3763       startpos -= parse->priv->lead_in_ts;
3764     seekpos = gst_base_parse_find_offset (parse, startpos, TRUE, &start_ts);
3765     seekstop = gst_base_parse_find_offset (parse, seeksegment.stop, FALSE,
3766         NULL);
3767   } else {
3768     start_ts = seeksegment.last_stop;
3769     dstformat = GST_FORMAT_BYTES;
3770     if (!gst_pad_query_convert (parse->srcpad, format, seeksegment.last_stop,
3771             &dstformat, &seekpos))
3772       goto convert_failed;
3773     if (!gst_pad_query_convert (parse->srcpad, format, seeksegment.stop,
3774             &dstformat, &seekstop))
3775       goto convert_failed;
3776   }
3777
3778   GST_DEBUG_OBJECT (parse,
3779       "seek position %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT,
3780       start_ts, seekpos);
3781   GST_DEBUG_OBJECT (parse,
3782       "seek stop %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT,
3783       seeksegment.stop, seekstop);
3784
3785   if (parse->priv->pad_mode == GST_ACTIVATE_PULL) {
3786     gint64 last_stop;
3787
3788     GST_DEBUG_OBJECT (parse, "seek in PULL mode");
3789
3790     if (flush) {
3791       if (parse->srcpad) {
3792         GST_DEBUG_OBJECT (parse, "sending flush start");
3793         gst_pad_push_event (parse->srcpad, gst_event_new_flush_start ());
3794         /* unlock upstream pull_range */
3795         gst_pad_push_event (parse->sinkpad, gst_event_new_flush_start ());
3796       }
3797     } else {
3798       gst_pad_pause_task (parse->sinkpad);
3799     }
3800
3801     /* we should now be able to grab the streaming thread because we stopped it
3802      * with the above flush/pause code */
3803     GST_PAD_STREAM_LOCK (parse->sinkpad);
3804
3805     /* save current position */
3806     last_stop = parse->segment.last_stop;
3807     GST_DEBUG_OBJECT (parse, "stopped streaming at %" G_GINT64_FORMAT,
3808         last_stop);
3809
3810     /* now commit to new position */
3811
3812     /* prepare for streaming again */
3813     if (flush) {
3814       GST_DEBUG_OBJECT (parse, "sending flush stop");
3815       gst_pad_push_event (parse->srcpad, gst_event_new_flush_stop ());
3816       gst_pad_push_event (parse->sinkpad, gst_event_new_flush_stop ());
3817       gst_base_parse_clear_queues (parse);
3818     } else {
3819       if (parse->priv->close_segment)
3820         gst_event_unref (parse->priv->close_segment);
3821
3822       parse->priv->close_segment = gst_event_new_new_segment (TRUE,
3823           parse->segment.rate, parse->segment.format,
3824           parse->segment.accum, parse->segment.last_stop, parse->segment.accum);
3825
3826       /* keep track of our last_stop */
3827       seeksegment.accum = parse->segment.last_stop;
3828
3829       GST_DEBUG_OBJECT (parse, "Created close seg format %d, "
3830           "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
3831           ", pos = %" GST_TIME_FORMAT, format,
3832           GST_TIME_ARGS (parse->segment.accum),
3833           GST_TIME_ARGS (parse->segment.last_stop),
3834           GST_TIME_ARGS (parse->segment.accum));
3835     }
3836
3837     memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));
3838
3839     /* store the newsegment event so it can be sent from the streaming thread. */
3840     parse->priv->pending_segment = TRUE;
3841     parse->priv->pending_events = g_list_append (parse->priv->pending_events,
3842         gst_event_new_new_segment (FALSE, parse->segment.rate,
3843             parse->segment.format, parse->segment.start,
3844             parse->segment.stop, parse->segment.start));
3845
3846     GST_DEBUG_OBJECT (parse, "Created newseg format %d, "
3847         "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
3848         ", pos = %" GST_TIME_FORMAT, format,
3849         GST_TIME_ARGS (parse->segment.start),
3850         GST_TIME_ARGS (parse->segment.stop),
3851         GST_TIME_ARGS (parse->segment.start));
3852
3853     /* one last chance in pull mode to stay accurate;
3854      * maybe scan and subclass can find where to go */
3855     if (!accurate) {
3856       gint64 scanpos;
3857       GstClockTime ts = seeksegment.last_stop;
3858
3859       gst_base_parse_locate_time (parse, &ts, &scanpos);
3860       if (scanpos >= 0) {
3861         accurate = TRUE;
3862         seekpos = scanpos;
3863         /* running collected index now consists of several intervals,
3864          * so optimized check no longer possible */
3865         parse->priv->index_last_valid = FALSE;
3866         parse->priv->index_last_offset = 0;
3867         parse->priv->index_last_ts = 0;
3868       }
3869     }
3870
3871     /* mark discont if we are going to stream from another position. */
3872     if (seekpos != parse->priv->offset) {
3873       GST_DEBUG_OBJECT (parse,
3874           "mark DISCONT, we did a seek to another position");
3875       parse->priv->offset = seekpos;
3876       parse->priv->last_offset = seekpos;
3877       parse->priv->seen_keyframe = FALSE;
3878       parse->priv->discont = TRUE;
3879       parse->priv->next_ts = start_ts;
3880       parse->priv->last_ts = GST_CLOCK_TIME_NONE;
3881       parse->priv->sync_offset = seekpos;
3882       parse->priv->exact_position = accurate;
3883     }
3884
3885     /* Start streaming thread if paused */
3886     gst_pad_start_task (parse->sinkpad,
3887         (GstTaskFunction) gst_base_parse_loop, parse->sinkpad);
3888
3889     GST_PAD_STREAM_UNLOCK (parse->sinkpad);
3890
3891     /* handled seek */
3892     res = TRUE;
3893   } else {
3894     GstEvent *new_event;
3895     GstBaseParseSeek *seek;
3896     GstSeekFlags flags = (flush ? GST_SEEK_FLAG_FLUSH : GST_SEEK_FLAG_NONE);
3897
3898     /* The only thing we need to do in PUSH-mode is to send the
3899        seek event (in bytes) to upstream. Segment / flush handling happens
3900        in corresponding src event handlers */
3901     GST_DEBUG_OBJECT (parse, "seek in PUSH mode");
3902     if (seekstop >= 0 && seekstop <= seekpos)
3903       seekstop = seekpos;
3904     new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
3905         GST_SEEK_TYPE_SET, seekpos, stop_type, seekstop);
3906
3907     /* store segment info so its precise details can be reconstructed when
3908      * receiving newsegment;
3909      * this matters for all details when accurate seeking,
3910      * is most useful to preserve NONE stop time otherwise */
3911     seek = g_new0 (GstBaseParseSeek, 1);
3912     seek->segment = seeksegment;
3913     seek->accurate = accurate;
3914     seek->offset = seekpos;
3915     seek->start_ts = start_ts;
3916     GST_OBJECT_LOCK (parse);
3917     /* less optimal, but preserves order */
3918     parse->priv->pending_seeks =
3919         g_slist_append (parse->priv->pending_seeks, seek);
3920     GST_OBJECT_UNLOCK (parse);
3921
3922     res = gst_pad_push_event (parse->sinkpad, new_event);
3923
3924     if (!res) {
3925       GST_OBJECT_LOCK (parse);
3926       parse->priv->pending_seeks =
3927           g_slist_remove (parse->priv->pending_seeks, seek);
3928       GST_OBJECT_UNLOCK (parse);
3929       g_free (seek);
3930     }
3931   }
3932
3933 done:
3934   /* handled event is ours to free */
3935   if (res)
3936     gst_event_unref (event);
3937   return res;
3938
3939   /* ERRORS */
3940 negative_rate:
3941   {
3942     GST_DEBUG_OBJECT (parse, "negative playback rates delegated upstream.");
3943     res = FALSE;
3944     goto done;
3945   }
3946 wrong_type:
3947   {
3948     GST_DEBUG_OBJECT (parse, "unsupported seek type.");
3949     res = FALSE;
3950     goto done;
3951   }
3952 convert_failed:
3953   {
3954     GST_DEBUG_OBJECT (parse, "conversion TIME to BYTES failed.");
3955     res = FALSE;
3956     goto done;
3957   }
3958 }
3959
3960 /* Checks if bitrates are available from upstream tags so that we don't
3961  * override them later
3962  */
3963 static void
3964 gst_base_parse_handle_tag (GstBaseParse * parse, GstEvent * event)
3965 {
3966   GstTagList *taglist = NULL;
3967   guint tmp;
3968
3969   gst_event_parse_tag (event, &taglist);
3970
3971   if (gst_tag_list_get_uint (taglist, GST_TAG_MINIMUM_BITRATE, &tmp)) {
3972     GST_DEBUG_OBJECT (parse, "upstream min bitrate %d", tmp);
3973     parse->priv->post_min_bitrate = FALSE;
3974   }
3975   if (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &tmp)) {
3976     GST_DEBUG_OBJECT (parse, "upstream avg bitrate %d", tmp);
3977     parse->priv->post_avg_bitrate = FALSE;
3978   }
3979   if (gst_tag_list_get_uint (taglist, GST_TAG_MAXIMUM_BITRATE, &tmp)) {
3980     GST_DEBUG_OBJECT (parse, "upstream max bitrate %d", tmp);
3981     parse->priv->post_max_bitrate = FALSE;
3982   }
3983 }
3984
3985 static gboolean
3986 gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
3987 {
3988   GstBaseParse *parse;
3989   GstBaseParseClass *klass;
3990   gboolean res = TRUE;
3991
3992   parse = GST_BASE_PARSE (GST_PAD_PARENT (pad));
3993   klass = GST_BASE_PARSE_GET_CLASS (parse);
3994
3995   GST_DEBUG_OBJECT (parse, "caps: %" GST_PTR_FORMAT, caps);
3996
3997   if (klass->set_sink_caps)
3998     res = klass->set_sink_caps (parse, caps);
3999
4000   return res;
4001 }
4002
4003 static GstCaps *
4004 gst_base_parse_sink_getcaps (GstPad * pad)
4005 {
4006   GstBaseParse *parse;
4007   GstBaseParseClass *klass;
4008   GstCaps *caps;
4009
4010   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
4011   klass = GST_BASE_PARSE_GET_CLASS (parse);
4012   g_assert (pad == GST_BASE_PARSE_SINK_PAD (parse));
4013
4014   if (klass->get_sink_caps)
4015     caps = klass->get_sink_caps (parse);
4016   else
4017     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
4018   gst_object_unref (parse);
4019
4020   GST_LOG_OBJECT (parse, "sink getcaps returning caps %" GST_PTR_FORMAT, caps);
4021
4022   return caps;
4023 }
4024
4025 static void
4026 gst_base_parse_set_index (GstElement * element, GstIndex * index)
4027 {
4028   GstBaseParse *parse = GST_BASE_PARSE (element);
4029
4030   GST_BASE_PARSE_INDEX_LOCK (parse);
4031   if (parse->priv->index)
4032     gst_object_unref (parse->priv->index);
4033   if (index) {
4034     parse->priv->index = gst_object_ref (index);
4035     gst_index_get_writer_id (index, GST_OBJECT_CAST (element),
4036         &parse->priv->index_id);
4037     parse->priv->own_index = FALSE;
4038   } else {
4039     parse->priv->index = NULL;
4040   }
4041   GST_BASE_PARSE_INDEX_UNLOCK (parse);
4042 }
4043
4044 static GstIndex *
4045 gst_base_parse_get_index (GstElement * element)
4046 {
4047   GstBaseParse *parse = GST_BASE_PARSE (element);
4048   GstIndex *result = NULL;
4049
4050   GST_BASE_PARSE_INDEX_LOCK (parse);
4051   if (parse->priv->index)
4052     result = gst_object_ref (parse->priv->index);
4053   GST_BASE_PARSE_INDEX_UNLOCK (parse);
4054
4055   return result;
4056 }
4057
4058 static GstStateChangeReturn
4059 gst_base_parse_change_state (GstElement * element, GstStateChange transition)
4060 {
4061   GstBaseParse *parse;
4062   GstStateChangeReturn result;
4063
4064   parse = GST_BASE_PARSE (element);
4065
4066   switch (transition) {
4067     case GST_STATE_CHANGE_READY_TO_PAUSED:
4068       /* If this is our own index destroy it as the
4069        * old entries might be wrong for the new stream */
4070       GST_BASE_PARSE_INDEX_LOCK (parse);
4071       if (parse->priv->own_index) {
4072         gst_object_unref (parse->priv->index);
4073         parse->priv->index = NULL;
4074         parse->priv->own_index = FALSE;
4075       }
4076
4077       /* If no index was created, generate one */
4078       if (G_UNLIKELY (!parse->priv->index)) {
4079         GST_DEBUG_OBJECT (parse, "no index provided creating our own");
4080
4081         parse->priv->index = gst_index_factory_make ("memindex");
4082         gst_index_get_writer_id (parse->priv->index, GST_OBJECT (parse),
4083             &parse->priv->index_id);
4084         parse->priv->own_index = TRUE;
4085       }
4086       GST_BASE_PARSE_INDEX_UNLOCK (parse);
4087       break;
4088     default:
4089       break;
4090   }
4091
4092   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4093
4094   switch (transition) {
4095     case GST_STATE_CHANGE_PAUSED_TO_READY:
4096       gst_base_parse_reset (parse);
4097       break;
4098     default:
4099       break;
4100   }
4101
4102   return result;
4103 }