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