e0429b2fbaa4c9a97d0d84d20be9db31d5fb99e2
[platform/upstream/gstreamer.git] / libs / gst / base / gstbaseparse.c
1 /* GStreamer
2  * Copyright (C) 2008 Nokia Corporation. All rights reserved.
3  *   Contact: Stefan Kost <stefan.kost@nokia.com>
4  * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
5  * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
6  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gstbaseparse
26  * @title: GstBaseParse
27  * @short_description: Base class for stream parsers
28  * @see_also: #GstBaseTransform
29  *
30  * This base class is for parser elements that process data and splits it
31  * into separate audio/video/whatever frames.
32  *
33  * It provides for:
34  *
35  *   * provides one sink pad and one source pad
36  *   * handles state changes
37  *   * can operate in pull mode or push mode
38  *   * handles seeking in both modes
39  *   * handles events (SEGMENT/EOS/FLUSH)
40  *   * handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT)
41  *   * handles flushing
42  *
43  * The purpose of this base class is to provide the basic functionality of
44  * a parser and share a lot of rather complex code.
45  *
46  * # Description of the parsing mechanism:
47  *
48  * ## Set-up phase
49  *
50  *  * #GstBaseParse calls @start to inform subclass that data processing is
51  *    about to start now.
52  *
53  *  * #GstBaseParse class calls @set_sink_caps to inform the subclass about
54  *    incoming sinkpad caps. Subclass could already set the srcpad caps
55  *    accordingly, but this might be delayed until calling
56  *    gst_base_parse_finish_frame() with a non-queued frame.
57  *
58  *  * At least at this point subclass needs to tell the #GstBaseParse class
59  *    how big data chunks it wants to receive (min_frame_size). It can do
60  *    this with gst_base_parse_set_min_frame_size().
61  *
62  *  * #GstBaseParse class sets up appropriate data passing mode (pull/push)
63  *    and starts to process the data.
64  *
65  * ## Parsing phase
66  *
67  *  * #GstBaseParse gathers at least min_frame_size bytes of data either
68  *    by pulling it from upstream or collecting buffers in an internal
69  *    #GstAdapter.
70  *
71  *  * A buffer of (at least) min_frame_size bytes is passed to subclass with
72  *    @handle_frame. Subclass checks the contents and can optionally
73  *    return GST_FLOW_OK along with an amount of data to be skipped to find
74  *    a valid frame (which will result in a subsequent DISCONT).
75  *    If, otherwise, the buffer does not hold a complete frame,
76  *    @handle_frame can merely return and will be called again when additional
77  *    data is available.  In push mode this amounts to an
78  *    additional input buffer (thus minimal additional latency), in pull mode
79  *    this amounts to some arbitrary reasonable buffer size increase.
80  *    Of course, gst_base_parse_set_min_frame_size() could also be used if a
81  *    very specific known amount of additional data is required.
82  *    If, however, the buffer holds a complete valid frame, it can pass
83  *    the size of this frame to gst_base_parse_finish_frame().
84  *    If acting as a converter, it can also merely indicate consumed input data
85  *    while simultaneously providing custom output data.
86  *    Note that baseclass performs some processing (such as tracking
87  *    overall consumed data rate versus duration) for each finished frame,
88  *    but other state is only updated upon each call to @handle_frame
89  *    (such as tracking upstream input timestamp).
90  *
91  *    Subclass is also responsible for setting the buffer metadata
92  *    (e.g. buffer timestamp and duration, or keyframe if applicable).
93  *    (although the latter can also be done by #GstBaseParse if it is
94  *    appropriately configured, see below).  Frame is provided with
95  *    timestamp derived from upstream (as much as generally possible),
96  *    duration obtained from configuration (see below), and offset
97  *    if meaningful (in pull mode).
98  *
99  *    Note that @check_valid_frame might receive any small
100  *    amount of input data when leftover data is being drained (e.g. at EOS).
101  *
102  *  * As part of finish frame processing,
103  *    just prior to actually pushing the buffer in question,
104  *    it is passed to @pre_push_frame 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  *
108  *  * During the parsing process #GstBaseParseClass will handle both srcpad
109  *    and sinkpad events. They will be passed to subclass if @event or
110  *    @src_event callbacks have been provided.
111  *
112  * ## Shutdown phase
113  *
114  * * #GstBaseParse class calls @stop to inform the subclass that data
115  *   parsing will be stopped.
116  *
117  * Subclass is responsible for providing pad template caps for
118  * source and sink pads. The pads need to be named "sink" and "src". It also
119  * needs to set the fixed caps on srcpad, when the format is ensured (e.g.
120  * when base class calls subclass' @set_sink_caps function).
121  *
122  * This base class uses %GST_FORMAT_DEFAULT as a meaning of frames. So,
123  * subclass conversion routine needs to know that conversion from
124  * %GST_FORMAT_TIME to %GST_FORMAT_DEFAULT must return the
125  * frame number that can be found from the given byte position.
126  *
127  * #GstBaseParse uses subclasses conversion methods also for seeking (or
128  * otherwise uses its own default one, see also below).
129  *
130  * Subclass @start and @stop functions will be called to inform the beginning
131  * and end of data processing.
132  *
133  * Things that subclass need to take care of:
134  *
135  * * Provide pad templates
136  * * Fixate the source pad caps when appropriate
137  * * Inform base class how big data chunks should be retrieved. This is
138  *   done with gst_base_parse_set_min_frame_size() function.
139  * * Examine data chunks passed to subclass with @handle_frame and pass
140  *   proper frame(s) to gst_base_parse_finish_frame(), and setting src pad
141  *   caps and timestamps on frame.
142  * * Provide conversion functions
143  * * Update the duration information with gst_base_parse_set_duration()
144  * * Optionally passthrough using gst_base_parse_set_passthrough()
145  * * Configure various baseparse parameters using
146  *   gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable()
147  *   and gst_base_parse_set_frame_rate().
148  *
149  * * In particular, if subclass is unable to determine a duration, but
150  *   parsing (or specs) yields a frames per seconds rate, then this can be
151  *   provided to #GstBaseParse to enable it to cater for
152  *   buffer time metadata (which will be taken from upstream as much as
153  *   possible). Internally keeping track of frame durations and respective
154  *   sizes that have been pushed provides #GstBaseParse with an estimated
155  *   bitrate. A default @convert (used if not overridden) will then use these
156  *   rates to perform obvious conversions.  These rates are also used to
157  *   update (estimated) duration at regular frame intervals.
158  *
159  */
160
161 /* TODO:
162  *  - In push mode provide a queue of adapter-"queued" buffers for upstream
163  *    buffer metadata
164  *  - Queue buffers/events until caps are set
165  */
166
167 #ifdef HAVE_CONFIG_H
168 #  include "config.h"
169 #endif
170
171 #include <stdlib.h>
172 #include <string.h>
173
174 #include <gst/base/gstadapter.h>
175
176 #include "gstbaseparse.h"
177
178 /* FIXME: get rid of old GstIndex code */
179 #include "gstindex.h"
180 #include "gstindex.c"
181 #include "gstmemindex.c"
182
183 #define GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC  (1 << 0)
184
185 #define MIN_FRAMES_TO_POST_BITRATE 10
186 #define TARGET_DIFFERENCE          (20 * GST_SECOND)
187 #define MAX_INDEX_ENTRIES          4096
188 #define UPDATE_THRESHOLD           2
189
190 #define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
191
192 GST_DEBUG_CATEGORY_STATIC (gst_base_parse_debug);
193 #define GST_CAT_DEFAULT gst_base_parse_debug
194
195 /* Supported formats */
196 static const GstFormat fmtlist[] = {
197   GST_FORMAT_DEFAULT,
198   GST_FORMAT_BYTES,
199   GST_FORMAT_TIME,
200   GST_FORMAT_UNDEFINED
201 };
202
203 #define GST_BASE_PARSE_GET_PRIVATE(obj)  \
204     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_PARSE, GstBaseParsePrivate))
205
206 struct _GstBaseParsePrivate
207 {
208   GstPadMode pad_mode;
209
210   GstAdapter *adapter;
211
212   gint64 duration;
213   GstFormat duration_fmt;
214   gint64 estimated_duration;
215   gint64 estimated_drift;
216
217   guint min_frame_size;
218   gboolean disable_passthrough;
219   gboolean passthrough;
220   gboolean pts_interpolate;
221   gboolean infer_ts;
222   gboolean syncable;
223   gboolean has_timing_info;
224   guint fps_num, fps_den;
225   gint update_interval;
226   guint bitrate;
227   guint lead_in, lead_out;
228   GstClockTime lead_in_ts, lead_out_ts;
229   GstClockTime min_latency, max_latency;
230
231   gboolean discont;
232   gboolean flushing;
233   gboolean drain;
234   gboolean saw_gaps;
235
236   gint64 offset;
237   gint64 sync_offset;
238   GstClockTime next_pts;
239   GstClockTime next_dts;
240   GstClockTime prev_pts;
241   GstClockTime prev_dts;
242   gboolean prev_dts_from_pts;
243   GstClockTime frame_duration;
244   gboolean seen_keyframe;
245   gboolean is_video;
246   gint flushed;
247
248   guint64 framecount;
249   guint64 bytecount;
250   guint64 data_bytecount;
251   guint64 acc_duration;
252   GstClockTime first_frame_pts;
253   GstClockTime first_frame_dts;
254   gint64 first_frame_offset;
255
256   gboolean post_min_bitrate;
257   gboolean post_avg_bitrate;
258   gboolean post_max_bitrate;
259
260   guint min_bitrate;
261   guint avg_bitrate;
262   guint max_bitrate;
263   guint posted_avg_bitrate;
264
265   /* frames/buffers that are queued and ready to go on OK */
266   GQueue queued_frames;
267
268   GstBuffer *cache;
269
270   /* index entry storage, either ours or provided */
271   GstIndex *index;
272   gint index_id;
273   gboolean own_index;
274   GMutex index_lock;
275
276   /* seek table entries only maintained if upstream is BYTE seekable */
277   gboolean upstream_seekable;
278   gboolean upstream_has_duration;
279   gint64 upstream_size;
280   GstFormat upstream_format;
281   /* minimum distance between two index entries */
282   GstClockTimeDiff idx_interval;
283   guint64 idx_byte_interval;
284   /* ts and offset of last entry added */
285   GstClockTime index_last_ts;
286   gint64 index_last_offset;
287   gboolean index_last_valid;
288
289   /* timestamps currently produced are accurate, e.g. started from 0 onwards */
290   gboolean exact_position;
291   /* seek events are temporarily kept to match them with newsegments */
292   GSList *pending_seeks;
293
294   /* reverse playback */
295   GSList *buffers_pending;
296   GSList *buffers_head;
297   GSList *buffers_queued;
298   GSList *buffers_send;
299   GstClockTime last_pts;
300   GstClockTime last_dts;
301   gint64 last_offset;
302
303   /* Pending serialized events */
304   GList *pending_events;
305
306   /* If baseparse has checked the caps to identify if it is
307    * handling video or audio */
308   gboolean checked_media;
309
310   /* offset of last parsed frame/data */
311   gint64 prev_offset;
312   /* force a new frame, regardless of offset */
313   gboolean new_frame;
314   /* whether we are merely scanning for a frame */
315   gboolean scanning;
316   /* ... and resulting frame, if any */
317   GstBaseParseFrame *scanned_frame;
318
319   /* TRUE if we're still detecting the format, i.e.
320    * if ::detect() is still called for future buffers */
321   gboolean detecting;
322   GList *detect_buffers;
323   guint detect_buffers_size;
324
325   /* True when no buffers have been received yet */
326   gboolean first_buffer;
327
328   /* if TRUE, a STREAM_START event needs to be pushed */
329   gboolean push_stream_start;
330
331   /* When we need to skip more data than we have currently */
332   guint skip;
333
334   /* Tag handling (stream tags only, global tags are passed through as-is) */
335   GstTagList *upstream_tags;
336   GstTagList *parser_tags;
337   GstTagMergeMode parser_tags_merge_mode;
338   gboolean tags_changed;
339 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
340   /* to get pad mode early */
341   GstPadMode expected_pad_mode;
342   /* check first frame in base parser */
343   gboolean first_frame;
344   /* remove zero padding */
345   gint64 remove_from_total;
346   gboolean accurate_index_seek;
347 #endif
348 };
349
350 typedef struct _GstBaseParseSeek
351 {
352   GstSegment segment;
353   gboolean accurate;
354   gint64 offset;
355   GstClockTime start_ts;
356 } GstBaseParseSeek;
357
358 #define DEFAULT_DISABLE_PASSTHROUGH        FALSE
359
360 enum
361 {
362   PROP_0,
363   PROP_DISABLE_PASSTHROUGH,
364   PROP_LAST
365 };
366
367 #define GST_BASE_PARSE_INDEX_LOCK(parse) \
368   g_mutex_lock (&parse->priv->index_lock);
369 #define GST_BASE_PARSE_INDEX_UNLOCK(parse) \
370   g_mutex_unlock (&parse->priv->index_lock);
371
372 static GstElementClass *parent_class = NULL;
373
374 static void gst_base_parse_class_init (GstBaseParseClass * klass);
375 static void gst_base_parse_init (GstBaseParse * parse,
376     GstBaseParseClass * klass);
377
378 GType
379 gst_base_parse_get_type (void)
380 {
381   static volatile gsize base_parse_type = 0;
382
383   if (g_once_init_enter (&base_parse_type)) {
384     static const GTypeInfo base_parse_info = {
385       sizeof (GstBaseParseClass),
386       (GBaseInitFunc) NULL,
387       (GBaseFinalizeFunc) NULL,
388       (GClassInitFunc) gst_base_parse_class_init,
389       NULL,
390       NULL,
391       sizeof (GstBaseParse),
392       0,
393       (GInstanceInitFunc) gst_base_parse_init,
394     };
395     GType _type;
396
397     _type = g_type_register_static (GST_TYPE_ELEMENT,
398         "GstBaseParse", &base_parse_info, G_TYPE_FLAG_ABSTRACT);
399     g_once_init_leave (&base_parse_type, _type);
400   }
401   return (GType) base_parse_type;
402 }
403
404 static void gst_base_parse_finalize (GObject * object);
405
406 static GstStateChangeReturn gst_base_parse_change_state (GstElement * element,
407     GstStateChange transition);
408 static void gst_base_parse_reset (GstBaseParse * parse);
409
410 #if 0
411 static void gst_base_parse_set_index (GstElement * element, GstIndex * index);
412 static GstIndex *gst_base_parse_get_index (GstElement * element);
413 #endif
414
415 static gboolean gst_base_parse_sink_activate (GstPad * sinkpad,
416     GstObject * parent);
417 static gboolean gst_base_parse_sink_activate_mode (GstPad * pad,
418     GstObject * parent, GstPadMode mode, gboolean active);
419 static gboolean gst_base_parse_handle_seek (GstBaseParse * parse,
420     GstEvent * event);
421 static void gst_base_parse_set_upstream_tags (GstBaseParse * parse,
422     GstTagList * taglist);
423
424 static void gst_base_parse_set_property (GObject * object, guint prop_id,
425     const GValue * value, GParamSpec * pspec);
426 static void gst_base_parse_get_property (GObject * object, guint prop_id,
427     GValue * value, GParamSpec * pspec);
428
429 static gboolean gst_base_parse_src_event (GstPad * pad, GstObject * parent,
430     GstEvent * event);
431 static gboolean gst_base_parse_src_query (GstPad * pad, GstObject * parent,
432     GstQuery * query);
433
434 static gboolean gst_base_parse_sink_event (GstPad * pad, GstObject * parent,
435     GstEvent * event);
436 static gboolean gst_base_parse_sink_query (GstPad * pad, GstObject * parent,
437     GstQuery * query);
438
439 static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstObject * parent,
440     GstBuffer * buffer);
441 static void gst_base_parse_loop (GstPad * pad);
442
443 static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse,
444     GstBaseParseFrame * frame);
445
446 static gboolean gst_base_parse_sink_event_default (GstBaseParse * parse,
447     GstEvent * event);
448
449 static gboolean gst_base_parse_src_event_default (GstBaseParse * parse,
450     GstEvent * event);
451
452 static gboolean gst_base_parse_sink_query_default (GstBaseParse * parse,
453     GstQuery * query);
454 static gboolean gst_base_parse_src_query_default (GstBaseParse * parse,
455     GstQuery * query);
456
457 static gint64 gst_base_parse_find_offset (GstBaseParse * parse,
458     GstClockTime time, gboolean before, GstClockTime * _ts);
459 static GstFlowReturn gst_base_parse_locate_time (GstBaseParse * parse,
460     GstClockTime * _time, gint64 * _offset);
461
462 static GstFlowReturn gst_base_parse_start_fragment (GstBaseParse * parse);
463 static GstFlowReturn gst_base_parse_finish_fragment (GstBaseParse * parse,
464     gboolean prev_head);
465 static GstFlowReturn gst_base_parse_send_buffers (GstBaseParse * parse);
466
467 static inline GstFlowReturn gst_base_parse_check_sync (GstBaseParse * parse);
468
469 static gboolean gst_base_parse_is_seekable (GstBaseParse * parse);
470
471 static void gst_base_parse_push_pending_events (GstBaseParse * parse);
472
473 static void
474 gst_base_parse_clear_queues (GstBaseParse * parse)
475 {
476   g_slist_foreach (parse->priv->buffers_queued, (GFunc) gst_buffer_unref, NULL);
477   g_slist_free (parse->priv->buffers_queued);
478   parse->priv->buffers_queued = NULL;
479   g_slist_foreach (parse->priv->buffers_pending, (GFunc) gst_buffer_unref,
480       NULL);
481   g_slist_free (parse->priv->buffers_pending);
482   parse->priv->buffers_pending = NULL;
483   g_slist_foreach (parse->priv->buffers_head, (GFunc) gst_buffer_unref, NULL);
484   g_slist_free (parse->priv->buffers_head);
485   parse->priv->buffers_head = NULL;
486   g_slist_foreach (parse->priv->buffers_send, (GFunc) gst_buffer_unref, NULL);
487   g_slist_free (parse->priv->buffers_send);
488   parse->priv->buffers_send = NULL;
489
490   g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref, NULL);
491   g_list_free (parse->priv->detect_buffers);
492   parse->priv->detect_buffers = NULL;
493   parse->priv->detect_buffers_size = 0;
494
495   g_queue_foreach (&parse->priv->queued_frames,
496       (GFunc) gst_base_parse_frame_free, NULL);
497   g_queue_clear (&parse->priv->queued_frames);
498
499   gst_buffer_replace (&parse->priv->cache, NULL);
500
501   g_list_foreach (parse->priv->pending_events, (GFunc) gst_event_unref, NULL);
502   g_list_free (parse->priv->pending_events);
503   parse->priv->pending_events = NULL;
504
505   parse->priv->checked_media = FALSE;
506 }
507
508 static void
509 gst_base_parse_finalize (GObject * object)
510 {
511   GstBaseParse *parse = GST_BASE_PARSE (object);
512
513   g_object_unref (parse->priv->adapter);
514
515   if (parse->priv->index) {
516     gst_object_unref (parse->priv->index);
517     parse->priv->index = NULL;
518   }
519   g_mutex_clear (&parse->priv->index_lock);
520
521   gst_base_parse_clear_queues (parse);
522
523   G_OBJECT_CLASS (parent_class)->finalize (object);
524 }
525
526 static void
527 gst_base_parse_class_init (GstBaseParseClass * klass)
528 {
529   GObjectClass *gobject_class;
530   GstElementClass *gstelement_class;
531
532   gobject_class = G_OBJECT_CLASS (klass);
533   g_type_class_add_private (klass, sizeof (GstBaseParsePrivate));
534   parent_class = g_type_class_peek_parent (klass);
535
536   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_parse_finalize);
537   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_parse_set_property);
538   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_parse_get_property);
539
540   /**
541    * GstBaseParse:disable-passthrough:
542    *
543    * If set to %TRUE, baseparse will unconditionally force parsing of the
544    * incoming data. This can be required in the rare cases where the incoming
545    * side-data (caps, pts, dts, ...) is not trusted by the user and wants to
546    * force validation and parsing of the incoming data.
547    * If set to %FALSE, decision of whether to parse the data or not is up to
548    * the implementation (standard behaviour).
549    */
550   g_object_class_install_property (gobject_class, PROP_DISABLE_PASSTHROUGH,
551       g_param_spec_boolean ("disable-passthrough", "Disable passthrough",
552           "Force processing (disables passthrough)",
553           DEFAULT_DISABLE_PASSTHROUGH,
554           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
555
556   gstelement_class = (GstElementClass *) klass;
557   gstelement_class->change_state =
558       GST_DEBUG_FUNCPTR (gst_base_parse_change_state);
559
560 #if 0
561   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_base_parse_set_index);
562   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_base_parse_get_index);
563 #endif
564
565   /* Default handlers */
566   klass->sink_event = gst_base_parse_sink_event_default;
567   klass->src_event = gst_base_parse_src_event_default;
568   klass->sink_query = gst_base_parse_sink_query_default;
569   klass->src_query = gst_base_parse_src_query_default;
570   klass->convert = gst_base_parse_convert_default;
571
572   GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "baseparse", 0,
573       "baseparse element");
574 }
575
576 static void
577 gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
578 {
579   GstPadTemplate *pad_template;
580
581   GST_DEBUG_OBJECT (parse, "gst_base_parse_init");
582
583   parse->priv = GST_BASE_PARSE_GET_PRIVATE (parse);
584
585   pad_template =
586       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
587   g_return_if_fail (pad_template != NULL);
588   parse->sinkpad = gst_pad_new_from_template (pad_template, "sink");
589   gst_pad_set_event_function (parse->sinkpad,
590       GST_DEBUG_FUNCPTR (gst_base_parse_sink_event));
591   gst_pad_set_query_function (parse->sinkpad,
592       GST_DEBUG_FUNCPTR (gst_base_parse_sink_query));
593   gst_pad_set_chain_function (parse->sinkpad,
594       GST_DEBUG_FUNCPTR (gst_base_parse_chain));
595   gst_pad_set_activate_function (parse->sinkpad,
596       GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate));
597   gst_pad_set_activatemode_function (parse->sinkpad,
598       GST_DEBUG_FUNCPTR (gst_base_parse_sink_activate_mode));
599   GST_PAD_SET_PROXY_ALLOCATION (parse->sinkpad);
600   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
601
602   GST_DEBUG_OBJECT (parse, "sinkpad created");
603
604   pad_template =
605       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
606   g_return_if_fail (pad_template != NULL);
607   parse->srcpad = gst_pad_new_from_template (pad_template, "src");
608   gst_pad_set_event_function (parse->srcpad,
609       GST_DEBUG_FUNCPTR (gst_base_parse_src_event));
610   gst_pad_set_query_function (parse->srcpad,
611       GST_DEBUG_FUNCPTR (gst_base_parse_src_query));
612   gst_pad_use_fixed_caps (parse->srcpad);
613   gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
614   GST_DEBUG_OBJECT (parse, "src created");
615
616   g_queue_init (&parse->priv->queued_frames);
617
618   parse->priv->adapter = gst_adapter_new ();
619
620   parse->priv->pad_mode = GST_PAD_MODE_NONE;
621
622 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
623   parse->priv->expected_pad_mode = GST_PAD_MODE_NONE;
624 #endif
625
626   g_mutex_init (&parse->priv->index_lock);
627
628   /* init state */
629   gst_base_parse_reset (parse);
630   GST_DEBUG_OBJECT (parse, "init ok");
631
632   GST_OBJECT_FLAG_SET (parse, GST_ELEMENT_FLAG_INDEXABLE);
633
634   parse->priv->upstream_tags = NULL;
635   parse->priv->parser_tags = NULL;
636   parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
637 }
638
639 static void
640 gst_base_parse_set_property (GObject * object, guint prop_id,
641     const GValue * value, GParamSpec * pspec)
642 {
643   GstBaseParse *parse = GST_BASE_PARSE (object);
644
645   switch (prop_id) {
646     case PROP_DISABLE_PASSTHROUGH:
647       parse->priv->disable_passthrough = g_value_get_boolean (value);
648       break;
649     default:
650       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
651       break;
652   }
653 }
654
655 static void
656 gst_base_parse_get_property (GObject * object, guint prop_id, GValue * value,
657     GParamSpec * pspec)
658 {
659   GstBaseParse *parse = GST_BASE_PARSE (object);
660
661   switch (prop_id) {
662     case PROP_DISABLE_PASSTHROUGH:
663       g_value_set_boolean (value, parse->priv->disable_passthrough);
664       break;
665     default:
666       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667       break;
668   }
669 }
670
671 GstBaseParseFrame *
672 gst_base_parse_frame_copy (GstBaseParseFrame * frame)
673 {
674   GstBaseParseFrame *copy;
675
676   copy = g_slice_dup (GstBaseParseFrame, frame);
677   copy->buffer = gst_buffer_ref (frame->buffer);
678   copy->_private_flags &= ~GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
679
680   GST_TRACE ("copied frame %p -> %p", frame, copy);
681
682   return copy;
683 }
684
685 void
686 gst_base_parse_frame_free (GstBaseParseFrame * frame)
687 {
688   GST_TRACE ("freeing frame %p", frame);
689
690   if (frame->buffer) {
691     gst_buffer_unref (frame->buffer);
692     frame->buffer = NULL;
693   }
694
695   if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) {
696     g_slice_free (GstBaseParseFrame, frame);
697   } else {
698     memset (frame, 0, sizeof (*frame));
699   }
700 }
701
702 G_DEFINE_BOXED_TYPE (GstBaseParseFrame, gst_base_parse_frame,
703     (GBoxedCopyFunc) gst_base_parse_frame_copy,
704     (GBoxedFreeFunc) gst_base_parse_frame_free);
705
706 /**
707  * gst_base_parse_frame_init:
708  * @frame: #GstBaseParseFrame.
709  *
710  * Sets a #GstBaseParseFrame to initial state.  Currently this means
711  * all public fields are zero-ed and a private flag is set to make
712  * sure gst_base_parse_frame_free() only frees the contents but not
713  * the actual frame. Use this function to initialise a #GstBaseParseFrame
714  * allocated on the stack.
715  */
716 void
717 gst_base_parse_frame_init (GstBaseParseFrame * frame)
718 {
719   memset (frame, 0, sizeof (GstBaseParseFrame));
720   frame->_private_flags = GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
721   GST_TRACE ("inited frame %p", frame);
722 }
723
724 /**
725  * gst_base_parse_frame_new:
726  * @buffer: (transfer none): a #GstBuffer
727  * @flags: the flags
728  * @overhead: number of bytes in this frame which should be counted as
729  *     metadata overhead, ie. not used to calculate the average bitrate.
730  *     Set to -1 to mark the entire frame as metadata. If in doubt, set to 0.
731  *
732  * Allocates a new #GstBaseParseFrame. This function is mainly for bindings,
733  * elements written in C should usually allocate the frame on the stack and
734  * then use gst_base_parse_frame_init() to initialise it.
735  *
736  * Returns: a newly-allocated #GstBaseParseFrame. Free with
737  *     gst_base_parse_frame_free() when no longer needed.
738  */
739 GstBaseParseFrame *
740 gst_base_parse_frame_new (GstBuffer * buffer, GstBaseParseFrameFlags flags,
741     gint overhead)
742 {
743   GstBaseParseFrame *frame;
744
745   frame = g_slice_new0 (GstBaseParseFrame);
746   frame->buffer = gst_buffer_ref (buffer);
747
748   GST_TRACE ("created frame %p", frame);
749   return frame;
750 }
751
752 static inline void
753 gst_base_parse_update_flags (GstBaseParse * parse)
754 {
755   parse->flags = 0;
756
757   /* set flags one by one for clarity */
758   if (G_UNLIKELY (parse->priv->drain))
759     parse->flags |= GST_BASE_PARSE_FLAG_DRAINING;
760
761   /* losing sync is pretty much a discont (and vice versa), no ? */
762   if (G_UNLIKELY (parse->priv->discont))
763     parse->flags |= GST_BASE_PARSE_FLAG_LOST_SYNC;
764 }
765
766 static inline void
767 gst_base_parse_update_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
768 {
769   if (G_UNLIKELY (parse->priv->discont)) {
770     GST_DEBUG_OBJECT (parse, "marking DISCONT");
771     GST_BUFFER_FLAG_SET (frame->buffer, GST_BUFFER_FLAG_DISCONT);
772   } else {
773     GST_BUFFER_FLAG_UNSET (frame->buffer, GST_BUFFER_FLAG_DISCONT);
774   }
775
776   if (parse->priv->prev_offset != parse->priv->offset || parse->priv->new_frame) {
777     GST_LOG_OBJECT (parse, "marking as new frame");
778     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME;
779   }
780
781   frame->offset = parse->priv->prev_offset = parse->priv->offset;
782 }
783
784 static void
785 gst_base_parse_reset (GstBaseParse * parse)
786 {
787   GST_OBJECT_LOCK (parse);
788   gst_segment_init (&parse->segment, GST_FORMAT_TIME);
789   parse->priv->duration = -1;
790   parse->priv->min_frame_size = 1;
791   parse->priv->discont = TRUE;
792   parse->priv->flushing = FALSE;
793   parse->priv->saw_gaps = FALSE;
794   parse->priv->offset = 0;
795   parse->priv->sync_offset = 0;
796   parse->priv->update_interval = -1;
797   parse->priv->fps_num = parse->priv->fps_den = 0;
798   parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
799   parse->priv->lead_in = parse->priv->lead_out = 0;
800   parse->priv->lead_in_ts = parse->priv->lead_out_ts = 0;
801   parse->priv->bitrate = 0;
802   parse->priv->framecount = 0;
803   parse->priv->bytecount = 0;
804   parse->priv->acc_duration = 0;
805   parse->priv->first_frame_pts = GST_CLOCK_TIME_NONE;
806   parse->priv->first_frame_dts = GST_CLOCK_TIME_NONE;
807   parse->priv->first_frame_offset = -1;
808   parse->priv->estimated_duration = -1;
809   parse->priv->estimated_drift = 0;
810   parse->priv->next_pts = GST_CLOCK_TIME_NONE;
811   parse->priv->next_dts = 0;
812   parse->priv->syncable = TRUE;
813   parse->priv->disable_passthrough = DEFAULT_DISABLE_PASSTHROUGH;
814   parse->priv->passthrough = FALSE;
815   parse->priv->pts_interpolate = TRUE;
816   parse->priv->infer_ts = TRUE;
817   parse->priv->has_timing_info = FALSE;
818   parse->priv->min_bitrate = G_MAXUINT;
819   parse->priv->max_bitrate = 0;
820   parse->priv->avg_bitrate = 0;
821   parse->priv->posted_avg_bitrate = 0;
822
823   parse->priv->index_last_ts = GST_CLOCK_TIME_NONE;
824   parse->priv->index_last_offset = -1;
825   parse->priv->index_last_valid = TRUE;
826   parse->priv->upstream_seekable = FALSE;
827   parse->priv->upstream_size = 0;
828   parse->priv->upstream_has_duration = FALSE;
829   parse->priv->upstream_format = GST_FORMAT_UNDEFINED;
830   parse->priv->idx_interval = 0;
831   parse->priv->idx_byte_interval = 0;
832   parse->priv->exact_position = TRUE;
833   parse->priv->seen_keyframe = FALSE;
834   parse->priv->checked_media = FALSE;
835
836   parse->priv->last_dts = GST_CLOCK_TIME_NONE;
837   parse->priv->last_pts = GST_CLOCK_TIME_NONE;
838   parse->priv->last_offset = 0;
839
840   parse->priv->skip = 0;
841
842 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
843   parse->priv->first_frame = TRUE;
844   parse->priv->remove_from_total = 0;
845   parse->priv->accurate_index_seek = TRUE;
846 #endif
847
848   g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref,
849       NULL);
850   g_list_free (parse->priv->pending_events);
851   parse->priv->pending_events = NULL;
852
853   if (parse->priv->cache) {
854     gst_buffer_unref (parse->priv->cache);
855     parse->priv->cache = NULL;
856   }
857
858   g_slist_foreach (parse->priv->pending_seeks, (GFunc) g_free, NULL);
859   g_slist_free (parse->priv->pending_seeks);
860   parse->priv->pending_seeks = NULL;
861
862   if (parse->priv->adapter)
863     gst_adapter_clear (parse->priv->adapter);
864
865   gst_base_parse_set_upstream_tags (parse, NULL);
866
867   if (parse->priv->parser_tags) {
868     gst_tag_list_unref (parse->priv->parser_tags);
869     parse->priv->parser_tags = NULL;
870   }
871   parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
872
873   parse->priv->new_frame = TRUE;
874
875   parse->priv->first_buffer = TRUE;
876
877   g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref, NULL);
878   g_list_free (parse->priv->detect_buffers);
879   parse->priv->detect_buffers = NULL;
880   parse->priv->detect_buffers_size = 0;
881 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
882   parse->priv->accurate_index_seek = TRUE;
883 #endif
884   GST_OBJECT_UNLOCK (parse);
885 }
886
887 static gboolean
888 gst_base_parse_check_bitrate_tag (GstBaseParse * parse, const gchar * tag)
889 {
890   gboolean got_tag = FALSE;
891   guint n = 0;
892
893   if (parse->priv->upstream_tags != NULL)
894     got_tag = gst_tag_list_get_uint (parse->priv->upstream_tags, tag, &n);
895
896   if (!got_tag && parse->priv->parser_tags != NULL)
897     got_tag = gst_tag_list_get_uint (parse->priv->parser_tags, tag, &n);
898
899   return got_tag;
900 }
901
902 /* check if upstream or subclass tags contain bitrates already */
903 static void
904 gst_base_parse_check_bitrate_tags (GstBaseParse * parse)
905 {
906   parse->priv->post_min_bitrate =
907       !gst_base_parse_check_bitrate_tag (parse, GST_TAG_MINIMUM_BITRATE);
908   parse->priv->post_avg_bitrate =
909       !gst_base_parse_check_bitrate_tag (parse, GST_TAG_BITRATE);
910   parse->priv->post_max_bitrate =
911       !gst_base_parse_check_bitrate_tag (parse, GST_TAG_MAXIMUM_BITRATE);
912 }
913
914 /* Queues new tag event with the current combined state of the stream tags
915  * (i.e. upstream tags merged with subclass tags and current baseparse tags) */
916 static void
917 gst_base_parse_queue_tag_event_update (GstBaseParse * parse)
918 {
919   GstTagList *merged_tags;
920
921   GST_LOG_OBJECT (parse, "upstream : %" GST_PTR_FORMAT,
922       parse->priv->upstream_tags);
923   GST_LOG_OBJECT (parse, "parser   : %" GST_PTR_FORMAT,
924       parse->priv->parser_tags);
925   GST_LOG_OBJECT (parse, "mode     : %d", parse->priv->parser_tags_merge_mode);
926
927   merged_tags =
928       gst_tag_list_merge (parse->priv->upstream_tags, parse->priv->parser_tags,
929       parse->priv->parser_tags_merge_mode);
930
931   GST_DEBUG_OBJECT (parse, "merged   : %" GST_PTR_FORMAT, merged_tags);
932
933   if (merged_tags == NULL)
934     return;
935
936   if (gst_tag_list_is_empty (merged_tags)) {
937     gst_tag_list_unref (merged_tags);
938     return;
939   }
940
941   if (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE) {
942     /* only add bitrate tags to non-empty taglists for now, and only if neither
943      * upstream tags nor the subclass sets the bitrate tag in question already */
944     if (parse->priv->min_bitrate != G_MAXUINT && parse->priv->post_min_bitrate) {
945       GST_LOG_OBJECT (parse, "adding min bitrate %u", parse->priv->min_bitrate);
946       gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
947           GST_TAG_MINIMUM_BITRATE, parse->priv->min_bitrate, NULL);
948     }
949     if (parse->priv->max_bitrate != 0 && parse->priv->post_max_bitrate) {
950       GST_LOG_OBJECT (parse, "adding max bitrate %u", parse->priv->max_bitrate);
951       gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
952           GST_TAG_MAXIMUM_BITRATE, parse->priv->max_bitrate, NULL);
953     }
954     if (parse->priv->avg_bitrate != 0 && parse->priv->post_avg_bitrate) {
955       parse->priv->posted_avg_bitrate = parse->priv->avg_bitrate;
956       GST_LOG_OBJECT (parse, "adding avg bitrate %u", parse->priv->avg_bitrate);
957       gst_tag_list_add (merged_tags, GST_TAG_MERGE_KEEP,
958           GST_TAG_BITRATE, parse->priv->avg_bitrate, NULL);
959     }
960   }
961
962   parse->priv->pending_events =
963       g_list_prepend (parse->priv->pending_events,
964       gst_event_new_tag (merged_tags));
965 }
966
967 /* gst_base_parse_parse_frame:
968  * @parse: #GstBaseParse.
969  * @buffer: #GstBuffer.
970  *
971  * Default callback for parse_frame.
972  */
973 static GstFlowReturn
974 gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
975 {
976   GstBuffer *buffer = frame->buffer;
977
978   if (!GST_BUFFER_PTS_IS_VALID (buffer) &&
979       GST_CLOCK_TIME_IS_VALID (parse->priv->next_pts)) {
980     GST_BUFFER_PTS (buffer) = parse->priv->next_pts;
981   }
982   if (!GST_BUFFER_DTS_IS_VALID (buffer) &&
983       GST_CLOCK_TIME_IS_VALID (parse->priv->next_dts)) {
984     GST_BUFFER_DTS (buffer) = parse->priv->next_dts;
985   }
986   if (!GST_BUFFER_DURATION_IS_VALID (buffer) &&
987       GST_CLOCK_TIME_IS_VALID (parse->priv->frame_duration)) {
988     GST_BUFFER_DURATION (buffer) = parse->priv->frame_duration;
989   }
990   return GST_FLOW_OK;
991 }
992
993 /* gst_base_parse_convert:
994  * @parse: #GstBaseParse.
995  * @src_format: #GstFormat describing the source format.
996  * @src_value: Source value to be converted.
997  * @dest_format: #GstFormat defining the converted format.
998  * @dest_value: Pointer where the conversion result will be put.
999  *
1000  * Converts using configured "convert" vmethod in #GstBaseParse class.
1001  *
1002  * Returns: %TRUE if conversion was successful.
1003  */
1004 static gboolean
1005 gst_base_parse_convert (GstBaseParse * parse,
1006     GstFormat src_format,
1007     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
1008 {
1009   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
1010   gboolean ret;
1011
1012   g_return_val_if_fail (dest_value != NULL, FALSE);
1013
1014   if (!klass->convert)
1015     return FALSE;
1016
1017   ret = klass->convert (parse, src_format, src_value, dest_format, dest_value);
1018
1019 #ifndef GST_DISABLE_GST_DEBUG
1020   {
1021     if (ret) {
1022       if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
1023         GST_LOG_OBJECT (parse,
1024             "TIME -> BYTES: %" GST_TIME_FORMAT " -> %" G_GINT64_FORMAT,
1025             GST_TIME_ARGS (src_value), *dest_value);
1026       } else if (dest_format == GST_FORMAT_TIME &&
1027           src_format == GST_FORMAT_BYTES) {
1028         GST_LOG_OBJECT (parse,
1029             "BYTES -> TIME: %" G_GINT64_FORMAT " -> %" GST_TIME_FORMAT,
1030             src_value, GST_TIME_ARGS (*dest_value));
1031       } else {
1032         GST_LOG_OBJECT (parse,
1033             "%s -> %s: %" G_GINT64_FORMAT " -> %" G_GINT64_FORMAT,
1034             GST_STR_NULL (gst_format_get_name (src_format)),
1035             GST_STR_NULL (gst_format_get_name (dest_format)),
1036             src_value, *dest_value);
1037       }
1038     } else {
1039       GST_DEBUG_OBJECT (parse, "conversion failed");
1040     }
1041   }
1042 #endif
1043
1044   return ret;
1045 }
1046
1047 static gboolean
1048 update_upstream_provided (GQuark field_id, const GValue * value,
1049     gpointer user_data)
1050 {
1051   GstCaps *default_caps = user_data;
1052   gint i;
1053   gint caps_size;
1054
1055   caps_size = gst_caps_get_size (default_caps);
1056   for (i = 0; i < caps_size; i++) {
1057     GstStructure *structure = gst_caps_get_structure (default_caps, i);
1058     if (gst_structure_id_has_field (structure, field_id))
1059       gst_structure_id_set_value (structure, field_id, value);
1060   }
1061
1062   return TRUE;
1063 }
1064
1065 static GstCaps *
1066 gst_base_parse_negotiate_default_caps (GstBaseParse * parse)
1067 {
1068   GstCaps *caps, *templcaps;
1069   GstCaps *sinkcaps = NULL;
1070   GstCaps *default_caps = NULL;
1071   GstStructure *structure;
1072
1073   templcaps = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse));
1074   caps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), templcaps);
1075   if (caps)
1076     gst_caps_unref (templcaps);
1077   else
1078     caps = templcaps;
1079   templcaps = NULL;
1080
1081   if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
1082     goto caps_error;
1083   }
1084
1085   GST_LOG_OBJECT (parse, "peer caps  %" GST_PTR_FORMAT, caps);
1086
1087   /* before fixating, try to use whatever upstream provided */
1088   default_caps = gst_caps_copy (caps);
1089   sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
1090
1091   GST_LOG_OBJECT (parse, "current caps %" GST_PTR_FORMAT " for sinkpad",
1092       sinkcaps);
1093
1094   if (sinkcaps) {
1095     structure = gst_caps_get_structure (sinkcaps, 0);
1096     gst_structure_foreach (structure, update_upstream_provided, default_caps);
1097   }
1098
1099   default_caps = gst_caps_fixate (default_caps);
1100
1101   if (!default_caps) {
1102     GST_WARNING_OBJECT (parse, "Failed to create default caps !");
1103     goto caps_error;
1104   }
1105
1106   GST_INFO_OBJECT (parse,
1107       "Chose default caps %" GST_PTR_FORMAT " for initial gap", default_caps);
1108
1109   if (sinkcaps)
1110     gst_caps_unref (sinkcaps);
1111   gst_caps_unref (caps);
1112
1113   return default_caps;
1114
1115 caps_error:
1116   {
1117     if (caps)
1118       gst_caps_unref (caps);
1119     if (sinkcaps)
1120       gst_caps_unref (sinkcaps);
1121     return NULL;
1122   }
1123 }
1124
1125 /* gst_base_parse_sink_event:
1126  * @pad: #GstPad that received the event.
1127  * @event: #GstEvent to be handled.
1128  *
1129  * Handler for sink pad events.
1130  *
1131  * Returns: %TRUE if the event was handled.
1132  */
1133 static gboolean
1134 gst_base_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1135 {
1136   GstBaseParse *parse = GST_BASE_PARSE (parent);
1137   GstBaseParseClass *bclass = GST_BASE_PARSE_GET_CLASS (parse);
1138   gboolean ret;
1139
1140   ret = bclass->sink_event (parse, event);
1141
1142   return ret;
1143 }
1144
1145 /* gst_base_parse_sink_event_default:
1146  * @parse: #GstBaseParse.
1147  * @event: #GstEvent to be handled.
1148  *
1149  * Element-level event handler function.
1150  *
1151  * The event will be unreffed only if it has been handled and this
1152  * function returns %TRUE
1153  *
1154  * Returns: %TRUE if the event was handled and not need forwarding.
1155  */
1156 static gboolean
1157 gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event)
1158 {
1159   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
1160   gboolean ret = FALSE;
1161   gboolean forward_immediate = FALSE;
1162
1163   GST_DEBUG_OBJECT (parse, "handling event %d, %s", GST_EVENT_TYPE (event),
1164       GST_EVENT_TYPE_NAME (event));
1165
1166   switch (GST_EVENT_TYPE (event)) {
1167     case GST_EVENT_CAPS:
1168     {
1169       GstCaps *caps;
1170
1171       gst_event_parse_caps (event, &caps);
1172       GST_DEBUG_OBJECT (parse, "caps: %" GST_PTR_FORMAT, caps);
1173
1174       if (klass->set_sink_caps)
1175         ret = klass->set_sink_caps (parse, caps);
1176       else
1177         ret = TRUE;
1178
1179       /* will send our own caps downstream */
1180       gst_event_unref (event);
1181       event = NULL;
1182       break;
1183     }
1184     case GST_EVENT_SEGMENT:
1185     {
1186       const GstSegment *in_segment;
1187       GstSegment out_segment;
1188       gint64 offset = 0, next_dts;
1189       guint32 seqnum = gst_event_get_seqnum (event);
1190
1191       gst_event_parse_segment (event, &in_segment);
1192       gst_segment_init (&out_segment, GST_FORMAT_TIME);
1193       out_segment.rate = in_segment->rate;
1194       out_segment.applied_rate = in_segment->applied_rate;
1195
1196       GST_DEBUG_OBJECT (parse, "segment %" GST_SEGMENT_FORMAT, in_segment);
1197
1198       parse->priv->upstream_format = in_segment->format;
1199       if (in_segment->format == GST_FORMAT_BYTES) {
1200         GstBaseParseSeek *seek = NULL;
1201         GSList *node;
1202
1203         /* stop time is allowed to be open-ended, but not start & pos */
1204         offset = in_segment->time;
1205
1206         GST_OBJECT_LOCK (parse);
1207         for (node = parse->priv->pending_seeks; node; node = node->next) {
1208           GstBaseParseSeek *tmp = node->data;
1209
1210           if (tmp->offset == offset) {
1211             seek = tmp;
1212             break;
1213           }
1214         }
1215         parse->priv->pending_seeks =
1216             g_slist_remove (parse->priv->pending_seeks, seek);
1217         GST_OBJECT_UNLOCK (parse);
1218
1219         if (seek) {
1220           GST_DEBUG_OBJECT (parse,
1221               "Matched newsegment to%s seek: %" GST_SEGMENT_FORMAT,
1222               seek->accurate ? " accurate" : "", &seek->segment);
1223
1224           out_segment.start = seek->segment.start;
1225           out_segment.stop = seek->segment.stop;
1226           out_segment.time = seek->segment.start;
1227
1228           next_dts = seek->start_ts;
1229           parse->priv->exact_position = seek->accurate;
1230           g_free (seek);
1231         } else {
1232           /* best attempt convert */
1233           /* as these are only estimates, stop is kept open-ended to avoid
1234            * premature cutting */
1235           gst_base_parse_convert (parse, GST_FORMAT_BYTES, in_segment->start,
1236               GST_FORMAT_TIME, (gint64 *) & next_dts);
1237
1238           out_segment.start = next_dts;
1239           out_segment.stop = GST_CLOCK_TIME_NONE;
1240           out_segment.time = next_dts;
1241
1242           parse->priv->exact_position = (in_segment->start == 0);
1243         }
1244
1245         gst_event_unref (event);
1246
1247         event = gst_event_new_segment (&out_segment);
1248         gst_event_set_seqnum (event, seqnum);
1249
1250         GST_DEBUG_OBJECT (parse, "Converted incoming segment to TIME. %"
1251             GST_SEGMENT_FORMAT, in_segment);
1252
1253       } else if (in_segment->format != GST_FORMAT_TIME) {
1254         /* Unknown incoming segment format. Output a default open-ended
1255          * TIME segment */
1256         gst_event_unref (event);
1257
1258         out_segment.start = 0;
1259         out_segment.stop = GST_CLOCK_TIME_NONE;
1260         out_segment.time = 0;
1261
1262         event = gst_event_new_segment (&out_segment);
1263         gst_event_set_seqnum (event, seqnum);
1264
1265         next_dts = 0;
1266       } else {
1267         /* not considered BYTE seekable if it is talking to us in TIME,
1268          * whatever else it might claim */
1269         parse->priv->upstream_seekable = FALSE;
1270         next_dts = in_segment->start;
1271         gst_event_copy_segment (event, &out_segment);
1272       }
1273
1274       memcpy (&parse->segment, &out_segment, sizeof (GstSegment));
1275
1276       /*
1277          gst_segment_set_newsegment (&parse->segment, update, rate,
1278          applied_rate, format, start, stop, start);
1279        */
1280
1281       ret = TRUE;
1282
1283       /* save the segment for later, right before we push a new buffer so that
1284        * the caps are fixed and the next linked element can receive
1285        * the segment but finish the current segment */
1286       GST_DEBUG_OBJECT (parse, "draining current segment");
1287       if (in_segment->rate > 0.0)
1288         gst_base_parse_drain (parse);
1289       else
1290         gst_base_parse_finish_fragment (parse, FALSE);
1291       gst_adapter_clear (parse->priv->adapter);
1292
1293       parse->priv->offset = offset;
1294       parse->priv->sync_offset = offset;
1295       parse->priv->next_dts = next_dts;
1296       parse->priv->next_pts = GST_CLOCK_TIME_NONE;
1297       parse->priv->last_pts = GST_CLOCK_TIME_NONE;
1298       parse->priv->last_dts = GST_CLOCK_TIME_NONE;
1299       parse->priv->prev_pts = GST_CLOCK_TIME_NONE;
1300       parse->priv->prev_dts = GST_CLOCK_TIME_NONE;
1301       parse->priv->prev_dts_from_pts = FALSE;
1302       parse->priv->discont = TRUE;
1303       parse->priv->seen_keyframe = FALSE;
1304       parse->priv->skip = 0;
1305       break;
1306     }
1307
1308     case GST_EVENT_SEGMENT_DONE:
1309       /* need to drain now, rather than upon a new segment,
1310        * since that would have SEGMENT_DONE come before potential
1311        * delayed last part of the current segment */
1312       GST_DEBUG_OBJECT (parse, "draining current segment");
1313       if (parse->segment.rate > 0.0)
1314         gst_base_parse_drain (parse);
1315       else
1316         gst_base_parse_finish_fragment (parse, FALSE);
1317       /* Also forward event immediately, there might be no new data
1318        * coming afterwards that would allow us to forward it later */
1319       forward_immediate = TRUE;
1320       break;
1321
1322     case GST_EVENT_FLUSH_START:
1323       GST_OBJECT_LOCK (parse);
1324       parse->priv->flushing = TRUE;
1325       GST_OBJECT_UNLOCK (parse);
1326       break;
1327
1328     case GST_EVENT_FLUSH_STOP:
1329       gst_adapter_clear (parse->priv->adapter);
1330       gst_base_parse_clear_queues (parse);
1331       parse->priv->flushing = FALSE;
1332       parse->priv->discont = TRUE;
1333       parse->priv->last_pts = GST_CLOCK_TIME_NONE;
1334       parse->priv->last_dts = GST_CLOCK_TIME_NONE;
1335       parse->priv->new_frame = TRUE;
1336       parse->priv->skip = 0;
1337
1338       forward_immediate = TRUE;
1339       break;
1340
1341     case GST_EVENT_EOS:
1342       if (parse->segment.rate > 0.0)
1343         gst_base_parse_drain (parse);
1344       else
1345         gst_base_parse_finish_fragment (parse, TRUE);
1346
1347       /* If we STILL have zero frames processed, fire an error */
1348       if (parse->priv->framecount == 0 && !parse->priv->saw_gaps &&
1349           !parse->priv->first_buffer) {
1350         GST_ELEMENT_ERROR (parse, STREAM, WRONG_TYPE,
1351             ("No valid frames found before end of stream"), (NULL));
1352       }
1353
1354       if (!parse->priv->saw_gaps
1355           && parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE) {
1356         /* We've not posted bitrate tags yet - do so now */
1357         gst_base_parse_queue_tag_event_update (parse);
1358       }
1359
1360       /* newsegment and other serialized events before eos */
1361       gst_base_parse_push_pending_events (parse);
1362
1363       forward_immediate = TRUE;
1364       break;
1365     case GST_EVENT_CUSTOM_DOWNSTREAM:{
1366       /* FIXME: Code duplicated from libgstvideo because core can't depend on -base */
1367 #ifndef GST_VIDEO_EVENT_STILL_STATE_NAME
1368 #define GST_VIDEO_EVENT_STILL_STATE_NAME "GstEventStillFrame"
1369 #endif
1370
1371       const GstStructure *s;
1372       gboolean ev_still_state;
1373
1374       s = gst_event_get_structure (event);
1375       if (s != NULL &&
1376           gst_structure_has_name (s, GST_VIDEO_EVENT_STILL_STATE_NAME) &&
1377           gst_structure_get_boolean (s, "still-state", &ev_still_state)) {
1378         if (ev_still_state) {
1379           GST_DEBUG_OBJECT (parse, "draining current data for still-frame");
1380           if (parse->segment.rate > 0.0)
1381             gst_base_parse_drain (parse);
1382           else
1383             gst_base_parse_finish_fragment (parse, TRUE);
1384         }
1385         forward_immediate = TRUE;
1386       }
1387       break;
1388     }
1389     case GST_EVENT_GAP:
1390     {
1391       GST_DEBUG_OBJECT (parse, "draining current data due to gap event");
1392
1393       /* Ensure we have caps before forwarding the event */
1394       if (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (parse))) {
1395         GstCaps *default_caps = NULL;
1396         if ((default_caps = gst_base_parse_negotiate_default_caps (parse))) {
1397           GList *l;
1398           GstEvent *caps_event = gst_event_new_caps (default_caps);
1399
1400           GST_DEBUG_OBJECT (parse,
1401               "Store caps event to pending list for initial pre-rolling");
1402
1403           /* Events are in decreasing order. Go down the list until we
1404            * find the first pre-CAPS event and insert our CAPS event there.
1405            *
1406            * There should be a SEGMENT event already, which is > CAPS */
1407           for (l = parse->priv->pending_events; l; l = l->next) {
1408             GstEvent *e = l->data;
1409
1410             if (GST_EVENT_TYPE (e) < GST_EVENT_CAPS) {
1411               parse->priv->pending_events =
1412                   g_list_insert_before (parse->priv->pending_events, l,
1413                   caps_event);
1414               break;
1415             }
1416           }
1417           /* No pending event that is < CAPS, so we have to add it at the very
1418            * end of the list */
1419           if (!l) {
1420             parse->priv->pending_events =
1421                 g_list_append (parse->priv->pending_events, caps_event);
1422           }
1423           gst_caps_unref (default_caps);
1424         } else {
1425           gst_event_unref (event);
1426           event = NULL;
1427           ret = FALSE;
1428           GST_ELEMENT_ERROR (parse, STREAM, FORMAT, (NULL),
1429               ("Parser output not negotiated before GAP event."));
1430           break;
1431         }
1432       }
1433
1434       gst_base_parse_push_pending_events (parse);
1435
1436       if (parse->segment.rate > 0.0)
1437         gst_base_parse_drain (parse);
1438       else
1439         gst_base_parse_finish_fragment (parse, TRUE);
1440       forward_immediate = TRUE;
1441       parse->priv->saw_gaps = TRUE;
1442       break;
1443     }
1444     case GST_EVENT_TAG:
1445     {
1446       GstTagList *tags = NULL;
1447
1448       gst_event_parse_tag (event, &tags);
1449
1450       /* We only care about stream tags here, global tags we just forward */
1451       if (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_STREAM)
1452         break;
1453
1454       gst_base_parse_set_upstream_tags (parse, tags);
1455       gst_base_parse_queue_tag_event_update (parse);
1456       parse->priv->tags_changed = FALSE;
1457       gst_event_unref (event);
1458       event = NULL;
1459       ret = TRUE;
1460       break;
1461     }
1462     case GST_EVENT_STREAM_START:
1463     {
1464       if (parse->priv->pad_mode != GST_PAD_MODE_PULL)
1465         forward_immediate = TRUE;
1466
1467       gst_base_parse_set_upstream_tags (parse, NULL);
1468       parse->priv->tags_changed = TRUE;
1469       break;
1470     }
1471     default:
1472       break;
1473   }
1474
1475   /* Forward non-serialized events and EOS/FLUSH_STOP immediately.
1476    * For EOS this is required because no buffer or serialized event
1477    * will come after EOS and nothing could trigger another
1478    * _finish_frame() call.   *
1479    * If the subclass handles sending of EOS manually it can return
1480    * _DROPPED from ::finish() and all other subclasses should have
1481    * decoded/flushed all remaining data before this
1482    *
1483    * For FLUSH_STOP this is required because it is expected
1484    * to be forwarded immediately and no buffers are queued anyway.
1485    */
1486   if (event) {
1487     if (!GST_EVENT_IS_SERIALIZED (event) || forward_immediate) {
1488       ret = gst_pad_push_event (parse->srcpad, event);
1489     } else {
1490       parse->priv->pending_events =
1491           g_list_prepend (parse->priv->pending_events, event);
1492       ret = TRUE;
1493     }
1494   }
1495
1496   GST_DEBUG_OBJECT (parse, "event handled");
1497
1498   return ret;
1499 }
1500
1501 static gboolean
1502 gst_base_parse_sink_query_default (GstBaseParse * parse, GstQuery * query)
1503 {
1504   GstPad *pad;
1505   gboolean res;
1506
1507   pad = GST_BASE_PARSE_SINK_PAD (parse);
1508
1509   switch (GST_QUERY_TYPE (query)) {
1510     case GST_QUERY_CAPS:
1511     {
1512       GstBaseParseClass *bclass;
1513
1514       bclass = GST_BASE_PARSE_GET_CLASS (parse);
1515
1516       if (bclass->get_sink_caps) {
1517         GstCaps *caps, *filter;
1518
1519         gst_query_parse_caps (query, &filter);
1520         caps = bclass->get_sink_caps (parse, filter);
1521         GST_LOG_OBJECT (parse, "sink getcaps returning caps %" GST_PTR_FORMAT,
1522             caps);
1523         gst_query_set_caps_result (query, caps);
1524         gst_caps_unref (caps);
1525
1526         res = TRUE;
1527       } else {
1528         GstCaps *caps, *template_caps, *filter;
1529
1530         gst_query_parse_caps (query, &filter);
1531         template_caps = gst_pad_get_pad_template_caps (pad);
1532         if (filter != NULL) {
1533           caps =
1534               gst_caps_intersect_full (filter, template_caps,
1535               GST_CAPS_INTERSECT_FIRST);
1536           gst_caps_unref (template_caps);
1537         } else {
1538           caps = template_caps;
1539         }
1540         gst_query_set_caps_result (query, caps);
1541         gst_caps_unref (caps);
1542
1543         res = TRUE;
1544       }
1545       break;
1546     }
1547     default:
1548     {
1549       res = gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query);
1550       break;
1551     }
1552   }
1553
1554   return res;
1555 }
1556
1557 static gboolean
1558 gst_base_parse_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
1559 {
1560   GstBaseParseClass *bclass;
1561   GstBaseParse *parse;
1562   gboolean ret;
1563
1564   parse = GST_BASE_PARSE (parent);
1565   bclass = GST_BASE_PARSE_GET_CLASS (parse);
1566
1567   GST_DEBUG_OBJECT (parse, "%s query", GST_QUERY_TYPE_NAME (query));
1568
1569   if (bclass->sink_query)
1570     ret = bclass->sink_query (parse, query);
1571   else
1572     ret = FALSE;
1573
1574   GST_LOG_OBJECT (parse, "%s query result: %d %" GST_PTR_FORMAT,
1575       GST_QUERY_TYPE_NAME (query), ret, query);
1576
1577   return ret;
1578 }
1579
1580 static gboolean
1581 gst_base_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1582 {
1583   GstBaseParseClass *bclass;
1584   GstBaseParse *parse;
1585   gboolean ret;
1586
1587   parse = GST_BASE_PARSE (parent);
1588   bclass = GST_BASE_PARSE_GET_CLASS (parse);
1589
1590   GST_DEBUG_OBJECT (parse, "%s query: %" GST_PTR_FORMAT,
1591       GST_QUERY_TYPE_NAME (query), query);
1592
1593   if (bclass->src_query)
1594     ret = bclass->src_query (parse, query);
1595   else
1596     ret = FALSE;
1597
1598   GST_LOG_OBJECT (parse, "%s query result: %d %" GST_PTR_FORMAT,
1599       GST_QUERY_TYPE_NAME (query), ret, query);
1600
1601   return ret;
1602 }
1603
1604 /* gst_base_parse_src_event:
1605  * @pad: #GstPad that received the event.
1606  * @event: #GstEvent that was received.
1607  *
1608  * Handler for source pad events.
1609  *
1610  * Returns: %TRUE if the event was handled.
1611  */
1612 static gboolean
1613 gst_base_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1614 {
1615   GstBaseParse *parse;
1616   GstBaseParseClass *bclass;
1617   gboolean ret = TRUE;
1618
1619   parse = GST_BASE_PARSE (parent);
1620   bclass = GST_BASE_PARSE_GET_CLASS (parse);
1621
1622   GST_DEBUG_OBJECT (parse, "event %d, %s", GST_EVENT_TYPE (event),
1623       GST_EVENT_TYPE_NAME (event));
1624
1625   if (bclass->src_event)
1626     ret = bclass->src_event (parse, event);
1627   else
1628     gst_event_unref (event);
1629
1630   return ret;
1631 }
1632
1633 static gboolean
1634 gst_base_parse_is_seekable (GstBaseParse * parse)
1635 {
1636   /* FIXME: could do more here, e.g. check index or just send data from 0
1637    * in pull mode and let decoder/sink clip */
1638   return parse->priv->syncable;
1639 }
1640
1641 /* gst_base_parse_src_event_default:
1642  * @parse: #GstBaseParse.
1643  * @event: #GstEvent that was received.
1644  *
1645  * Default srcpad event handler.
1646  *
1647  * Returns: %TRUE if the event was handled and can be dropped.
1648  */
1649 static gboolean
1650 gst_base_parse_src_event_default (GstBaseParse * parse, GstEvent * event)
1651 {
1652   gboolean res = FALSE;
1653
1654   switch (GST_EVENT_TYPE (event)) {
1655     case GST_EVENT_SEEK:
1656       if (gst_base_parse_is_seekable (parse))
1657         res = gst_base_parse_handle_seek (parse, event);
1658       break;
1659     default:
1660       res = gst_pad_event_default (parse->srcpad, GST_OBJECT_CAST (parse),
1661           event);
1662       break;
1663   }
1664   return res;
1665 }
1666
1667
1668 /**
1669  * gst_base_parse_convert_default:
1670  * @parse: #GstBaseParse.
1671  * @src_format: #GstFormat describing the source format.
1672  * @src_value: Source value to be converted.
1673  * @dest_format: #GstFormat defining the converted format.
1674  * @dest_value: Pointer where the conversion result will be put.
1675  *
1676  * Default implementation of "convert" vmethod in #GstBaseParse class.
1677  *
1678  * Returns: %TRUE if conversion was successful.
1679  */
1680 gboolean
1681 gst_base_parse_convert_default (GstBaseParse * parse,
1682     GstFormat src_format,
1683     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
1684 {
1685   gboolean ret = FALSE;
1686   guint64 bytes, duration;
1687
1688   if (G_UNLIKELY (src_format == dest_format)) {
1689     *dest_value = src_value;
1690     return TRUE;
1691   }
1692
1693   if (G_UNLIKELY (src_value == -1)) {
1694     *dest_value = -1;
1695     return TRUE;
1696   }
1697
1698   if (G_UNLIKELY (src_value == 0)) {
1699     *dest_value = 0;
1700     return TRUE;
1701   }
1702
1703   if (parse->priv->upstream_format != GST_FORMAT_BYTES) {
1704     /* don't do byte format conversions if we're not really parsing
1705      * a raw elementary stream, since we don't really have BYTES
1706      * position / duration info */
1707     if (src_format == GST_FORMAT_BYTES || dest_format == GST_FORMAT_BYTES)
1708       goto no_slaved_conversions;
1709   }
1710
1711   /* need at least some frames */
1712   if (!parse->priv->framecount)
1713     goto no_framecount;
1714
1715 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
1716   duration = parse->priv->acc_duration / GST_USECOND;
1717 #else
1718   duration = parse->priv->acc_duration / GST_MSECOND;
1719 #endif
1720   bytes = parse->priv->bytecount;
1721
1722   if (G_UNLIKELY (!duration || !bytes))
1723     goto no_duration_bytes;
1724
1725   if (src_format == GST_FORMAT_BYTES) {
1726     if (dest_format == GST_FORMAT_TIME) {
1727       /* BYTES -> TIME conversion */
1728       GST_DEBUG_OBJECT (parse, "converting bytes -> time");
1729 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
1730       src_value = src_value - parse->priv->remove_from_total;
1731 #endif
1732       *dest_value = gst_util_uint64_scale (src_value, duration, bytes);
1733 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
1734       *dest_value /= GST_USECOND;
1735 #endif
1736       *dest_value *= GST_MSECOND;
1737       GST_DEBUG_OBJECT (parse, "conversion result: %" G_GINT64_FORMAT " ms",
1738           *dest_value / GST_MSECOND);
1739       ret = TRUE;
1740     } else {
1741       GST_DEBUG_OBJECT (parse, "converting bytes -> other not implemented");
1742     }
1743   } else if (src_format == GST_FORMAT_TIME) {
1744     if (dest_format == GST_FORMAT_BYTES) {
1745       GST_DEBUG_OBJECT (parse, "converting time -> bytes");
1746 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
1747       *dest_value = gst_util_uint64_scale (src_value / GST_USECOND, bytes,
1748           duration);
1749 #else
1750       *dest_value = gst_util_uint64_scale (src_value / GST_MSECOND, bytes,
1751           duration);
1752 #endif
1753       GST_DEBUG_OBJECT (parse,
1754           "time %" G_GINT64_FORMAT " ms in bytes = %" G_GINT64_FORMAT,
1755           src_value / GST_MSECOND, *dest_value);
1756       ret = TRUE;
1757     } else {
1758       GST_DEBUG_OBJECT (parse, "converting time -> other not implemented");
1759     }
1760   } else if (src_format == GST_FORMAT_DEFAULT) {
1761     /* DEFAULT == frame-based */
1762     if (dest_format == GST_FORMAT_TIME) {
1763       GST_DEBUG_OBJECT (parse, "converting default -> time");
1764       if (parse->priv->fps_den) {
1765         *dest_value = gst_util_uint64_scale (src_value,
1766             GST_SECOND * parse->priv->fps_den, parse->priv->fps_num);
1767         ret = TRUE;
1768       }
1769     } else {
1770       GST_DEBUG_OBJECT (parse, "converting default -> other not implemented");
1771     }
1772   } else {
1773     GST_DEBUG_OBJECT (parse, "conversion not implemented");
1774   }
1775   return ret;
1776
1777   /* ERRORS */
1778 no_framecount:
1779   {
1780     GST_DEBUG_OBJECT (parse, "no framecount");
1781     return FALSE;
1782   }
1783 no_duration_bytes:
1784   {
1785     GST_DEBUG_OBJECT (parse, "no duration %" G_GUINT64_FORMAT ", bytes %"
1786         G_GUINT64_FORMAT, duration, bytes);
1787     return FALSE;
1788   }
1789 no_slaved_conversions:
1790   {
1791     GST_DEBUG_OBJECT (parse,
1792         "Can't do format conversions when upstream format is not BYTES");
1793     return FALSE;
1794   }
1795 }
1796
1797 static void
1798 gst_base_parse_update_duration (GstBaseParse * parse)
1799 {
1800   gint64 ptot, dest_value;
1801
1802   if (!gst_pad_peer_query_duration (parse->sinkpad, GST_FORMAT_BYTES, &ptot))
1803     return;
1804
1805   if (!gst_base_parse_convert (parse, GST_FORMAT_BYTES, ptot,
1806           GST_FORMAT_TIME, &dest_value))
1807     return;
1808
1809   /* inform if duration changed, but try to avoid spamming */
1810   parse->priv->estimated_drift += dest_value - parse->priv->estimated_duration;
1811
1812   parse->priv->estimated_duration = dest_value;
1813   GST_LOG_OBJECT (parse,
1814       "updated estimated duration to %" GST_TIME_FORMAT,
1815       GST_TIME_ARGS (dest_value));
1816
1817   if (parse->priv->estimated_drift > GST_SECOND ||
1818       parse->priv->estimated_drift < -GST_SECOND) {
1819     gst_element_post_message (GST_ELEMENT (parse),
1820         gst_message_new_duration_changed (GST_OBJECT (parse)));
1821     parse->priv->estimated_drift = 0;
1822   }
1823 }
1824
1825 /* gst_base_parse_update_bitrates:
1826  * @parse: #GstBaseParse.
1827  * @buffer: Current frame as a #GstBuffer
1828  *
1829  * Keeps track of the minimum and maximum bitrates, and also maintains a
1830  * running average bitrate of the stream so far.
1831  */
1832 static void
1833 gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
1834 {
1835   guint64 data_len, frame_dur;
1836   gint overhead, frame_bitrate;
1837   GstBuffer *buffer = frame->buffer;
1838
1839   overhead = frame->overhead;
1840   if (overhead == -1)
1841     return;
1842
1843   data_len = gst_buffer_get_size (buffer) - overhead;
1844   parse->priv->data_bytecount += data_len;
1845
1846   /* duration should be valid by now,
1847    * either set by subclass or maybe based on fps settings */
1848   if (GST_BUFFER_DURATION_IS_VALID (buffer) && parse->priv->acc_duration != 0) {
1849     /* Calculate duration of a frame from buffer properties */
1850     frame_dur = GST_BUFFER_DURATION (buffer);
1851     parse->priv->avg_bitrate = (8 * parse->priv->data_bytecount * GST_SECOND) /
1852         parse->priv->acc_duration;
1853
1854   } else {
1855     /* No way to figure out frame duration (is this even possible?) */
1856     return;
1857   }
1858
1859   /* override if subclass provided bitrate, e.g. metadata based */
1860   if (parse->priv->bitrate) {
1861     parse->priv->avg_bitrate = parse->priv->bitrate;
1862     /* spread this (confirmed) info ASAP */
1863     if (parse->priv->posted_avg_bitrate != parse->priv->avg_bitrate)
1864       parse->priv->tags_changed = TRUE;
1865   }
1866
1867   if (frame_dur)
1868     frame_bitrate = (8 * data_len * GST_SECOND) / frame_dur;
1869   else
1870     return;
1871
1872   GST_LOG_OBJECT (parse, "frame bitrate %u, avg bitrate %u", frame_bitrate,
1873       parse->priv->avg_bitrate);
1874
1875   if (parse->priv->framecount < MIN_FRAMES_TO_POST_BITRATE)
1876     return;
1877
1878   if (parse->priv->framecount == MIN_FRAMES_TO_POST_BITRATE &&
1879       (parse->priv->post_min_bitrate || parse->priv->post_avg_bitrate
1880           || parse->priv->post_max_bitrate))
1881     parse->priv->tags_changed = TRUE;
1882
1883   if (G_LIKELY (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE)) {
1884     if (frame_bitrate < parse->priv->min_bitrate) {
1885       parse->priv->min_bitrate = frame_bitrate;
1886       if (parse->priv->post_min_bitrate)
1887         parse->priv->tags_changed = TRUE;
1888     }
1889
1890     if (frame_bitrate > parse->priv->max_bitrate) {
1891       parse->priv->max_bitrate = frame_bitrate;
1892       if (parse->priv->post_max_bitrate)
1893         parse->priv->tags_changed = TRUE;
1894     }
1895
1896     /* Only update the tag on a 2% change */
1897     if (parse->priv->post_avg_bitrate && parse->priv->avg_bitrate) {
1898       guint64 diffprev = gst_util_uint64_scale_int (100,
1899           ABSDIFF (parse->priv->avg_bitrate, parse->priv->posted_avg_bitrate),
1900           parse->priv->avg_bitrate);
1901       if (diffprev >= UPDATE_THRESHOLD)
1902         parse->priv->tags_changed = TRUE;
1903     }
1904   }
1905 }
1906
1907 /**
1908  * gst_base_parse_add_index_entry:
1909  * @parse: #GstBaseParse.
1910  * @offset: offset of entry
1911  * @ts: timestamp associated with offset
1912  * @key: whether entry refers to keyframe
1913  * @force: add entry disregarding sanity checks
1914  *
1915  * Adds an entry to the index associating @offset to @ts.  It is recommended
1916  * to only add keyframe entries.  @force allows to bypass checks, such as
1917  * whether the stream is (upstream) seekable, another entry is already "close"
1918  * to the new entry, etc.
1919  *
1920  * Returns: #gboolean indicating whether entry was added
1921  */
1922 gboolean
1923 gst_base_parse_add_index_entry (GstBaseParse * parse, guint64 offset,
1924     GstClockTime ts, gboolean key, gboolean force)
1925 {
1926   gboolean ret = FALSE;
1927   GstIndexAssociation associations[2];
1928
1929   GST_LOG_OBJECT (parse, "Adding key=%d index entry %" GST_TIME_FORMAT
1930       " @ offset 0x%08" G_GINT64_MODIFIER "x", key, GST_TIME_ARGS (ts), offset);
1931
1932   if (G_LIKELY (!force)) {
1933
1934     if (!parse->priv->upstream_seekable) {
1935       GST_DEBUG_OBJECT (parse, "upstream not seekable; discarding");
1936       goto exit;
1937     }
1938
1939     /* FIXME need better helper data structure that handles these issues
1940      * related to ongoing collecting of index entries */
1941     if (parse->priv->index_last_offset + parse->priv->idx_byte_interval >=
1942         (gint64) offset) {
1943       GST_LOG_OBJECT (parse,
1944           "already have entries up to offset 0x%08" G_GINT64_MODIFIER "x",
1945           parse->priv->index_last_offset + parse->priv->idx_byte_interval);
1946       goto exit;
1947     }
1948
1949     if (GST_CLOCK_TIME_IS_VALID (parse->priv->index_last_ts) &&
1950         GST_CLOCK_DIFF (parse->priv->index_last_ts, ts) <
1951         parse->priv->idx_interval) {
1952       GST_LOG_OBJECT (parse, "entry too close to last time %" GST_TIME_FORMAT,
1953           GST_TIME_ARGS (parse->priv->index_last_ts));
1954       goto exit;
1955     }
1956
1957     /* if last is not really the last one */
1958     if (!parse->priv->index_last_valid) {
1959       GstClockTime prev_ts;
1960
1961       gst_base_parse_find_offset (parse, ts, TRUE, &prev_ts);
1962       if (GST_CLOCK_DIFF (prev_ts, ts) < parse->priv->idx_interval) {
1963         GST_LOG_OBJECT (parse,
1964             "entry too close to existing entry %" GST_TIME_FORMAT,
1965             GST_TIME_ARGS (prev_ts));
1966         parse->priv->index_last_offset = offset;
1967         parse->priv->index_last_ts = ts;
1968         goto exit;
1969       }
1970     }
1971   }
1972
1973   associations[0].format = GST_FORMAT_TIME;
1974   associations[0].value = ts;
1975   associations[1].format = GST_FORMAT_BYTES;
1976   associations[1].value = offset;
1977
1978   /* index might change on-the-fly, although that would be nutty app ... */
1979   GST_BASE_PARSE_INDEX_LOCK (parse);
1980   gst_index_add_associationv (parse->priv->index, parse->priv->index_id,
1981       (key) ? GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT :
1982       GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT, 2,
1983       (const GstIndexAssociation *) &associations);
1984   GST_BASE_PARSE_INDEX_UNLOCK (parse);
1985
1986   if (key) {
1987     parse->priv->index_last_offset = offset;
1988     parse->priv->index_last_ts = ts;
1989   }
1990
1991   ret = TRUE;
1992
1993 exit:
1994   return ret;
1995 }
1996
1997 /* check for seekable upstream, above and beyond a mere query */
1998 static void
1999 gst_base_parse_check_seekability (GstBaseParse * parse)
2000 {
2001   GstQuery *query;
2002   gboolean seekable = FALSE;
2003   gint64 start = -1, stop = -1;
2004   guint idx_interval = 0;
2005   guint64 idx_byte_interval = 0;
2006
2007   query = gst_query_new_seeking (GST_FORMAT_BYTES);
2008   if (!gst_pad_peer_query (parse->sinkpad, query)) {
2009     GST_DEBUG_OBJECT (parse, "seeking query failed");
2010     goto done;
2011   }
2012
2013   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
2014
2015   /* try harder to query upstream size if we didn't get it the first time */
2016   if (seekable && stop == -1) {
2017     GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop");
2018     gst_pad_peer_query_duration (parse->sinkpad, GST_FORMAT_BYTES, &stop);
2019   }
2020
2021   /* if upstream doesn't know the size, it's likely that it's not seekable in
2022    * practice even if it technically may be seekable */
2023   if (seekable && (start != 0 || stop <= start)) {
2024     GST_DEBUG_OBJECT (parse, "seekable but unknown start/stop -> disable");
2025     seekable = FALSE;
2026   }
2027
2028   /* let's not put every single frame into our index */
2029   if (seekable) {
2030     if (stop < 10 * 1024 * 1024)
2031       idx_interval = 100;
2032     else if (stop < 100 * 1024 * 1024)
2033       idx_interval = 500;
2034     else
2035       idx_interval = 1000;
2036
2037     /* ensure that even for large files (e.g. very long audio files), the index
2038      * stays reasonably-size, with some arbitrary limit to the total number of
2039      * index entries */
2040     idx_byte_interval = (stop - start) / MAX_INDEX_ENTRIES;
2041     GST_DEBUG_OBJECT (parse,
2042         "Limiting index entries to %d, indexing byte interval %"
2043         G_GUINT64_FORMAT " bytes", MAX_INDEX_ENTRIES, idx_byte_interval);
2044   }
2045
2046 done:
2047   gst_query_unref (query);
2048
2049   GST_DEBUG_OBJECT (parse, "seekable: %d (%" G_GUINT64_FORMAT " - %"
2050       G_GUINT64_FORMAT ")", seekable, start, stop);
2051   parse->priv->upstream_seekable = seekable;
2052   parse->priv->upstream_size = seekable ? stop : 0;
2053
2054   GST_DEBUG_OBJECT (parse, "idx_interval: %ums", idx_interval);
2055   parse->priv->idx_interval = idx_interval * GST_MSECOND;
2056   parse->priv->idx_byte_interval = idx_byte_interval;
2057 }
2058
2059 /* some misc checks on upstream */
2060 static void
2061 gst_base_parse_check_upstream (GstBaseParse * parse)
2062 {
2063   gint64 stop;
2064
2065   if (gst_pad_peer_query_duration (parse->sinkpad, GST_FORMAT_TIME, &stop))
2066     if (GST_CLOCK_TIME_IS_VALID (stop) && stop) {
2067       /* upstream has one, accept it also, and no further updates */
2068       gst_base_parse_set_duration (parse, GST_FORMAT_TIME, stop, 0);
2069       parse->priv->upstream_has_duration = TRUE;
2070     }
2071
2072   GST_DEBUG_OBJECT (parse, "upstream_has_duration: %d",
2073       parse->priv->upstream_has_duration);
2074 }
2075
2076 /* checks src caps to determine if dealing with audio or video */
2077 /* TODO maybe forego automagic stuff and let subclass configure it ? */
2078 static void
2079 gst_base_parse_check_media (GstBaseParse * parse)
2080 {
2081   GstCaps *caps;
2082   GstStructure *s;
2083
2084   caps = gst_pad_get_current_caps (parse->srcpad);
2085   if (G_LIKELY (caps) && (s = gst_caps_get_structure (caps, 0))) {
2086     parse->priv->is_video =
2087         g_str_has_prefix (gst_structure_get_name (s), "video");
2088   } else {
2089     /* historical default */
2090     parse->priv->is_video = FALSE;
2091   }
2092   if (caps)
2093     gst_caps_unref (caps);
2094
2095   parse->priv->checked_media = TRUE;
2096   GST_DEBUG_OBJECT (parse, "media is video: %d", parse->priv->is_video);
2097 }
2098
2099 /* takes ownership of frame */
2100 static void
2101 gst_base_parse_queue_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
2102 {
2103   if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) {
2104     /* frame allocated on the heap, we can just take ownership */
2105     g_queue_push_tail (&parse->priv->queued_frames, frame);
2106     GST_TRACE ("queued frame %p", frame);
2107   } else {
2108     GstBaseParseFrame *copy;
2109
2110     /* probably allocated on the stack, must make a proper copy */
2111     copy = gst_base_parse_frame_copy (frame);
2112     g_queue_push_tail (&parse->priv->queued_frames, copy);
2113     GST_TRACE ("queued frame %p (copy of %p)", copy, frame);
2114     gst_base_parse_frame_free (frame);
2115   }
2116 }
2117
2118 /* makes sure that @buf is properly prepared and decorated for passing
2119  * to baseclass, and an equally setup frame is returned setup with @buf.
2120  * Takes ownership of @buf. */
2121 static GstBaseParseFrame *
2122 gst_base_parse_prepare_frame (GstBaseParse * parse, GstBuffer * buffer)
2123 {
2124   GstBaseParseFrame *frame = NULL;
2125
2126   buffer = gst_buffer_make_writable (buffer);
2127
2128   GST_LOG_OBJECT (parse,
2129       "preparing frame at offset %" G_GUINT64_FORMAT
2130       " (%#" G_GINT64_MODIFIER "x) of size %" G_GSIZE_FORMAT,
2131       GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer),
2132       gst_buffer_get_size (buffer));
2133
2134   GST_BUFFER_OFFSET (buffer) = parse->priv->offset;
2135
2136   gst_base_parse_update_flags (parse);
2137
2138   frame = gst_base_parse_frame_new (buffer, 0, 0);
2139   gst_buffer_unref (buffer);
2140   gst_base_parse_update_frame (parse, frame);
2141
2142   /* clear flags for next frame */
2143   parse->priv->discont = FALSE;
2144   parse->priv->new_frame = FALSE;
2145
2146   /* use default handler to provide initial (upstream) metadata */
2147   gst_base_parse_parse_frame (parse, frame);
2148
2149   return frame;
2150 }
2151
2152 /* Wraps buffer in a frame and dispatches to subclass.
2153  * Also manages data skipping and offset handling (including adapter flushing).
2154  * Takes ownership of @buffer */
2155 static GstFlowReturn
2156 gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
2157     gint * skip, gint * flushed)
2158 {
2159   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
2160   GstBaseParseFrame *frame;
2161   GstFlowReturn ret;
2162
2163   g_return_val_if_fail (skip != NULL || flushed != NULL, GST_FLOW_ERROR);
2164
2165   GST_LOG_OBJECT (parse,
2166       "handling buffer of size %" G_GSIZE_FORMAT " with dts %" GST_TIME_FORMAT
2167       ", pts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
2168       gst_buffer_get_size (buffer), GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2169       GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2170       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
2171
2172   /* track what is being flushed during this single round of frame processing */
2173   parse->priv->flushed = 0;
2174   *skip = 0;
2175
2176   /* make it easy for _finish_frame to pick up input data */
2177   if (parse->priv->pad_mode == GST_PAD_MODE_PULL) {
2178     gst_buffer_ref (buffer);
2179     gst_adapter_push (parse->priv->adapter, buffer);
2180   }
2181
2182 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
2183   /* some one-time start-up */
2184   if (G_UNLIKELY (parse->priv->framecount == 0)) {
2185     gst_base_parse_check_seekability (parse);
2186     gst_base_parse_check_upstream (parse);
2187   }
2188 #endif
2189
2190   frame = gst_base_parse_prepare_frame (parse, buffer);
2191   ret = klass->handle_frame (parse, frame, skip);
2192
2193   *flushed = parse->priv->flushed;
2194
2195   GST_LOG_OBJECT (parse, "handle_frame skipped %d, flushed %d",
2196       *skip, *flushed);
2197
2198   /* subclass can only do one of these, or semantics are too unclear */
2199   g_assert (*skip == 0 || *flushed == 0);
2200
2201   /* track skipping */
2202   if (*skip > 0) {
2203     GstClockTime pts, dts;
2204     GstBuffer *outbuf;
2205
2206     GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", *skip);
2207     if (parse->segment.rate < 0.0 && !parse->priv->buffers_queued) {
2208       /* reverse playback, and no frames found yet, so we are skipping
2209        * the leading part of a fragment, which may form the tail of
2210        * fragment coming later, hopefully subclass skips efficiently ... */
2211       pts = gst_adapter_prev_pts (parse->priv->adapter, NULL);
2212       dts = gst_adapter_prev_dts (parse->priv->adapter, NULL);
2213       outbuf = gst_adapter_take_buffer (parse->priv->adapter, *skip);
2214       outbuf = gst_buffer_make_writable (outbuf);
2215       GST_BUFFER_PTS (outbuf) = pts;
2216       GST_BUFFER_DTS (outbuf) = dts;
2217       parse->priv->buffers_head =
2218           g_slist_prepend (parse->priv->buffers_head, outbuf);
2219       outbuf = NULL;
2220     } else {
2221       /* If we're asked to skip more than is available in the adapter,
2222          we need to remember what we need to skip for next iteration */
2223       gsize av = gst_adapter_available (parse->priv->adapter);
2224       GST_DEBUG ("Asked to skip %u (%" G_GSIZE_FORMAT " available)", *skip, av);
2225       if (av >= *skip) {
2226         gst_adapter_flush (parse->priv->adapter, *skip);
2227       } else {
2228         GST_DEBUG
2229             ("This is more than available, flushing %" G_GSIZE_FORMAT
2230             ", storing %u to skip", av, (guint) (*skip - av));
2231         parse->priv->skip = *skip - av;
2232         gst_adapter_flush (parse->priv->adapter, av);
2233         *skip = av;
2234       }
2235     }
2236     if (!parse->priv->discont)
2237       parse->priv->sync_offset = parse->priv->offset;
2238     parse->priv->offset += *skip;
2239     parse->priv->discont = TRUE;
2240     /* check for indefinite skipping */
2241     if (ret == GST_FLOW_OK)
2242       ret = gst_base_parse_check_sync (parse);
2243   }
2244
2245   parse->priv->offset += *flushed;
2246
2247   if (parse->priv->pad_mode == GST_PAD_MODE_PULL) {
2248     gst_adapter_clear (parse->priv->adapter);
2249   }
2250
2251   if (*skip == 0 && *flushed == 0) {
2252     /* Carry over discont if we need more data */
2253     if (GST_BUFFER_IS_DISCONT (frame->buffer))
2254       parse->priv->discont = TRUE;
2255   }
2256
2257   gst_base_parse_frame_free (frame);
2258
2259   return ret;
2260 }
2261
2262 /* gst_base_parse_push_pending_events:
2263  * @parse: #GstBaseParse
2264  *
2265  * Pushes the pending events
2266  */
2267 static void
2268 gst_base_parse_push_pending_events (GstBaseParse * parse)
2269 {
2270   if (G_UNLIKELY (parse->priv->pending_events)) {
2271     GList *r = g_list_reverse (parse->priv->pending_events);
2272     GList *l;
2273
2274     parse->priv->pending_events = NULL;
2275     for (l = r; l != NULL; l = l->next) {
2276       gst_pad_push_event (parse->srcpad, GST_EVENT_CAST (l->data));
2277     }
2278     g_list_free (r);
2279   }
2280 }
2281
2282 /* gst_base_parse_handle_and_push_frame:
2283  * @parse: #GstBaseParse.
2284  * @klass: #GstBaseParseClass.
2285  * @frame: (transfer full): a #GstBaseParseFrame
2286  *
2287  * Parses the frame from given buffer and pushes it forward. Also performs
2288  * timestamp handling and checks the segment limits.
2289  *
2290  * This is called with srcpad STREAM_LOCK held.
2291  *
2292  * Returns: #GstFlowReturn
2293  */
2294 static GstFlowReturn
2295 gst_base_parse_handle_and_push_frame (GstBaseParse * parse,
2296     GstBaseParseFrame * frame)
2297 {
2298   gint64 offset;
2299   GstBuffer *buffer;
2300
2301   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
2302
2303   buffer = frame->buffer;
2304   offset = frame->offset;
2305
2306   /* check if subclass/format can provide ts.
2307    * If so, that allows and enables extra seek and duration determining options */
2308   if (G_UNLIKELY (parse->priv->first_frame_offset < 0)) {
2309     if (GST_BUFFER_PTS_IS_VALID (buffer) && parse->priv->has_timing_info
2310         && parse->priv->pad_mode == GST_PAD_MODE_PULL) {
2311       parse->priv->first_frame_offset = offset;
2312       parse->priv->first_frame_pts = GST_BUFFER_PTS (buffer);
2313       parse->priv->first_frame_dts = GST_BUFFER_DTS (buffer);
2314       GST_DEBUG_OBJECT (parse, "subclass provided dts %" GST_TIME_FORMAT
2315           ", pts %" GST_TIME_FORMAT " for first frame at offset %"
2316           G_GINT64_FORMAT, GST_TIME_ARGS (parse->priv->first_frame_dts),
2317           GST_TIME_ARGS (parse->priv->first_frame_pts),
2318           parse->priv->first_frame_offset);
2319       if (!GST_CLOCK_TIME_IS_VALID (parse->priv->duration)) {
2320         gint64 off;
2321         GstClockTime last_ts = G_MAXINT64;
2322
2323         GST_DEBUG_OBJECT (parse, "no duration; trying scan to determine");
2324         gst_base_parse_locate_time (parse, &last_ts, &off);
2325         if (GST_CLOCK_TIME_IS_VALID (last_ts))
2326           gst_base_parse_set_duration (parse, GST_FORMAT_TIME, last_ts, 0);
2327       }
2328     } else {
2329       /* disable further checks */
2330       parse->priv->first_frame_offset = 0;
2331     }
2332   }
2333
2334   /* track upstream time if provided, not subclass' internal notion of it */
2335   if (parse->priv->upstream_format == GST_FORMAT_TIME) {
2336     GST_BUFFER_PTS (frame->buffer) = GST_CLOCK_TIME_NONE;
2337     GST_BUFFER_DTS (frame->buffer) = GST_CLOCK_TIME_NONE;
2338   }
2339
2340   /* interpolating and no valid pts yet,
2341    * start with dts and carry on from there */
2342   if (parse->priv->infer_ts && parse->priv->pts_interpolate
2343       && !GST_CLOCK_TIME_IS_VALID (parse->priv->next_pts))
2344     parse->priv->next_pts = parse->priv->next_dts;
2345
2346   /* again use default handler to add missing metadata;
2347    * we may have new information on frame properties */
2348   gst_base_parse_parse_frame (parse, frame);
2349
2350 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
2351   if (parse->priv->first_frame) {
2352     parse->priv->remove_from_total = GST_BUFFER_OFFSET (buffer);
2353     GST_DEBUG_OBJECT (parse, "first frame has offset %" G_GINT64_FORMAT ". remove from total",
2354         parse->priv->remove_from_total);
2355     parse->priv->first_frame = FALSE;
2356   }
2357 #endif
2358
2359   parse->priv->next_pts = GST_CLOCK_TIME_NONE;
2360   if (GST_BUFFER_DTS_IS_VALID (buffer) && GST_BUFFER_DURATION_IS_VALID (buffer)) {
2361     parse->priv->next_dts =
2362         GST_BUFFER_DTS (buffer) + GST_BUFFER_DURATION (buffer);
2363     if (parse->priv->pts_interpolate && GST_BUFFER_PTS_IS_VALID (buffer)) {
2364       GstClockTime next_pts =
2365           GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer);
2366       if (next_pts >= parse->priv->next_dts)
2367         parse->priv->next_pts = next_pts;
2368     }
2369   } else {
2370     /* we lost track, do not produce bogus time next time around
2371      * (probably means parser subclass has given up on parsing as well) */
2372     GST_DEBUG_OBJECT (parse, "no next fallback timestamp");
2373     parse->priv->next_dts = GST_CLOCK_TIME_NONE;
2374   }
2375
2376   if (parse->priv->upstream_seekable && parse->priv->exact_position &&
2377       GST_BUFFER_PTS_IS_VALID (buffer))
2378     gst_base_parse_add_index_entry (parse, offset,
2379         GST_BUFFER_PTS (buffer),
2380         !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE);
2381
2382   /* All OK, push queued frames if there are any */
2383   if (G_UNLIKELY (!g_queue_is_empty (&parse->priv->queued_frames))) {
2384     GstBaseParseFrame *queued_frame;
2385
2386     while ((queued_frame = g_queue_pop_head (&parse->priv->queued_frames))) {
2387       gst_base_parse_push_frame (parse, queued_frame);
2388       gst_base_parse_frame_free (queued_frame);
2389     }
2390   }
2391
2392   return gst_base_parse_push_frame (parse, frame);
2393 }
2394
2395 /**
2396  * gst_base_parse_push_frame:
2397  * @parse: #GstBaseParse.
2398  * @frame: (transfer none): a #GstBaseParseFrame
2399  *
2400  * Pushes the frame's buffer downstream, sends any pending events and
2401  * does some timestamp and segment handling. Takes ownership of
2402  * frame's buffer, though caller retains ownership of @frame.
2403  *
2404  * This must be called with sinkpad STREAM_LOCK held.
2405  *
2406  * Returns: #GstFlowReturn
2407  */
2408 GstFlowReturn
2409 gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
2410 {
2411   GstFlowReturn ret = GST_FLOW_OK;
2412   GstClockTime last_start = GST_CLOCK_TIME_NONE;
2413   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2414   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
2415   GstBuffer *buffer;
2416   gsize size;
2417
2418   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
2419   g_return_val_if_fail (frame->buffer != NULL, GST_FLOW_ERROR);
2420
2421   GST_TRACE_OBJECT (parse, "pushing frame %p", frame);
2422
2423   buffer = frame->buffer;
2424
2425 #ifdef TIZEN_PROFILE_TV
2426   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer))) {
2427     GST_LOG_OBJECT (parse, "invalid pts, set with dts");
2428     GST_BUFFER_PTS (buffer) = GST_BUFFER_DTS (buffer);
2429   }
2430 #endif
2431
2432   GST_LOG_OBJECT (parse,
2433       "processing buffer of size %" G_GSIZE_FORMAT " with dts %" GST_TIME_FORMAT
2434       ", pts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
2435       gst_buffer_get_size (buffer),
2436       GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2437       GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2438       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
2439
2440   /* update stats */
2441   parse->priv->bytecount += frame->size;
2442   if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) {
2443     parse->priv->framecount++;
2444     if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
2445       parse->priv->acc_duration += GST_BUFFER_DURATION (buffer);
2446     }
2447   }
2448   /* 0 means disabled */
2449   if (parse->priv->update_interval < 0)
2450     parse->priv->update_interval = 50;
2451   else if (parse->priv->update_interval > 0 &&
2452 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
2453       ((parse->priv->framecount - 1) % parse->priv->update_interval) == 0)
2454 #else
2455       (parse->priv->framecount % parse->priv->update_interval) == 0)
2456 #endif
2457     gst_base_parse_update_duration (parse);
2458
2459   if (GST_BUFFER_PTS_IS_VALID (buffer))
2460     last_start = last_stop = GST_BUFFER_PTS (buffer);
2461   if (last_start != GST_CLOCK_TIME_NONE
2462       && GST_BUFFER_DURATION_IS_VALID (buffer))
2463     last_stop = last_start + GST_BUFFER_DURATION (buffer);
2464
2465   /* should have caps by now */
2466   if (!gst_pad_has_current_caps (parse->srcpad))
2467     goto no_caps;
2468
2469   if (G_UNLIKELY (!parse->priv->checked_media)) {
2470     /* have caps; check identity */
2471     gst_base_parse_check_media (parse);
2472   }
2473
2474   if (parse->priv->tags_changed) {
2475     gst_base_parse_queue_tag_event_update (parse);
2476     parse->priv->tags_changed = FALSE;
2477   }
2478
2479   /* Push pending events, including SEGMENT events */
2480   gst_base_parse_push_pending_events (parse);
2481
2482   /* segment adjustment magic; only if we are running the whole show */
2483   if (!parse->priv->passthrough && parse->segment.rate > 0.0 &&
2484       (parse->priv->pad_mode == GST_PAD_MODE_PULL ||
2485           parse->priv->upstream_seekable)) {
2486     /* handle gaps */
2487     if (GST_CLOCK_TIME_IS_VALID (parse->segment.position) &&
2488         GST_CLOCK_TIME_IS_VALID (last_start)) {
2489       GstClockTimeDiff diff;
2490
2491       /* only send newsegments with increasing start times,
2492        * otherwise if these go back and forth downstream (sinks) increase
2493        * accumulated time and running_time */
2494       diff = GST_CLOCK_DIFF (parse->segment.position, last_start);
2495       if (G_UNLIKELY (diff > 2 * GST_SECOND
2496               && last_start > parse->segment.start
2497               && (!GST_CLOCK_TIME_IS_VALID (parse->segment.stop)
2498                   || last_start < parse->segment.stop))) {
2499
2500         GST_DEBUG_OBJECT (parse,
2501             "Gap of %" G_GINT64_FORMAT " ns detected in stream " "(%"
2502             GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "). "
2503             "Sending updated SEGMENT events", diff,
2504             GST_TIME_ARGS (parse->segment.position),
2505             GST_TIME_ARGS (last_start));
2506
2507         /* skip gap FIXME */
2508         gst_pad_push_event (parse->srcpad,
2509             gst_event_new_segment (&parse->segment));
2510
2511         parse->segment.position = last_start;
2512       }
2513     }
2514   }
2515
2516   /* update bitrates and optionally post corresponding tags
2517    * (following newsegment) */
2518   gst_base_parse_update_bitrates (parse, frame);
2519
2520   if (klass->pre_push_frame) {
2521     ret = klass->pre_push_frame (parse, frame);
2522   } else {
2523     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
2524   }
2525
2526   /* Push pending events, if there are any new ones
2527    * like tags added by pre_push_frame */
2528   if (parse->priv->tags_changed) {
2529     gst_base_parse_queue_tag_event_update (parse);
2530     parse->priv->tags_changed = FALSE;
2531   }
2532   gst_base_parse_push_pending_events (parse);
2533
2534   /* take final ownership of frame buffer */
2535   if (frame->out_buffer) {
2536     buffer = frame->out_buffer;
2537     frame->out_buffer = NULL;
2538     gst_buffer_replace (&frame->buffer, NULL);
2539   } else {
2540     buffer = frame->buffer;
2541     frame->buffer = NULL;
2542   }
2543
2544   /* subclass must play nice */
2545   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
2546
2547   size = gst_buffer_get_size (buffer);
2548
2549   parse->priv->seen_keyframe |= parse->priv->is_video &&
2550       !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
2551
2552   if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_CLIP) {
2553     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
2554         GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
2555         GST_BUFFER_TIMESTAMP (buffer) >
2556         parse->segment.stop + parse->priv->lead_out_ts) {
2557       GST_LOG_OBJECT (parse, "Dropped frame, after segment");
2558       ret = GST_FLOW_EOS;
2559     } else if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
2560         GST_BUFFER_DURATION_IS_VALID (buffer) &&
2561         GST_CLOCK_TIME_IS_VALID (parse->segment.start) &&
2562         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) +
2563         parse->priv->lead_in_ts < parse->segment.start) {
2564       if (parse->priv->seen_keyframe) {
2565         GST_LOG_OBJECT (parse, "Frame before segment, after keyframe");
2566         ret = GST_FLOW_OK;
2567       } else {
2568         GST_LOG_OBJECT (parse, "Dropped frame, before segment");
2569         ret = GST_BASE_PARSE_FLOW_DROPPED;
2570       }
2571     } else {
2572       ret = GST_FLOW_OK;
2573     }
2574   }
2575
2576   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
2577     GST_LOG_OBJECT (parse, "frame (%" G_GSIZE_FORMAT " bytes) dropped", size);
2578     if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
2579       parse->priv->discont = TRUE;
2580     gst_buffer_unref (buffer);
2581     ret = GST_FLOW_OK;
2582   } else if (ret == GST_FLOW_OK) {
2583     if (parse->segment.rate > 0.0) {
2584       GST_LOG_OBJECT (parse, "pushing frame (%" G_GSIZE_FORMAT " bytes) now..",
2585           size);
2586       ret = gst_pad_push (parse->srcpad, buffer);
2587       GST_LOG_OBJECT (parse, "frame pushed, flow %s", gst_flow_get_name (ret));
2588     } else if (!parse->priv->disable_passthrough && parse->priv->passthrough) {
2589
2590       /* in backwards playback mode, if on passthrough we need to push buffers
2591        * directly without accumulating them into the buffers_queued as baseparse
2592        * will never check for a DISCONT while on passthrough and those buffers
2593        * will never be pushed.
2594        *
2595        * also, as we are on reverse playback, it might be possible that
2596        * passthrough might have just been enabled, so make sure to drain the
2597        * buffers_queued list */
2598       if (G_UNLIKELY (parse->priv->buffers_queued != NULL)) {
2599         gst_base_parse_finish_fragment (parse, TRUE);
2600         ret = gst_base_parse_send_buffers (parse);
2601       }
2602
2603       if (ret == GST_FLOW_OK) {
2604         GST_LOG_OBJECT (parse,
2605             "pushing frame (%" G_GSIZE_FORMAT " bytes) now..", size);
2606         ret = gst_pad_push (parse->srcpad, buffer);
2607         GST_LOG_OBJECT (parse, "frame pushed, flow %s",
2608             gst_flow_get_name (ret));
2609       } else {
2610         GST_LOG_OBJECT (parse,
2611             "frame (%" G_GSIZE_FORMAT " bytes) not pushed: %s", size,
2612             gst_flow_get_name (ret));
2613         gst_buffer_unref (buffer);
2614       }
2615
2616     } else {
2617       GST_LOG_OBJECT (parse, "frame (%" G_GSIZE_FORMAT " bytes) queued for now",
2618           size);
2619       parse->priv->buffers_queued =
2620           g_slist_prepend (parse->priv->buffers_queued, buffer);
2621       ret = GST_FLOW_OK;
2622     }
2623   } else {
2624     GST_LOG_OBJECT (parse, "frame (%" G_GSIZE_FORMAT " bytes) not pushed: %s",
2625         size, gst_flow_get_name (ret));
2626     gst_buffer_unref (buffer);
2627     /* if we are not sufficiently in control, let upstream decide on EOS */
2628     if (ret == GST_FLOW_EOS && !parse->priv->disable_passthrough &&
2629         (parse->priv->passthrough ||
2630             (parse->priv->pad_mode == GST_PAD_MODE_PUSH &&
2631                 !parse->priv->upstream_seekable)))
2632       ret = GST_FLOW_OK;
2633   }
2634
2635   /* Update current running segment position */
2636   if ((ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
2637       && last_stop != GST_CLOCK_TIME_NONE
2638       && parse->segment.position < last_stop)
2639     parse->segment.position = last_stop;
2640
2641   return ret;
2642
2643   /* ERRORS */
2644 no_caps:
2645   {
2646     if (GST_PAD_IS_FLUSHING (parse->srcpad))
2647       return GST_FLOW_FLUSHING;
2648
2649     GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("No caps set"), (NULL));
2650     return GST_FLOW_ERROR;
2651   }
2652 }
2653
2654 /**
2655  * gst_base_parse_finish_frame:
2656  * @parse: a #GstBaseParse
2657  * @frame: a #GstBaseParseFrame
2658  * @size: consumed input data represented by frame
2659  *
2660  * Collects parsed data and pushes this downstream.
2661  * Source pad caps must be set when this is called.
2662  *
2663  * If @frame's out_buffer is set, that will be used as subsequent frame data.
2664  * Otherwise, @size samples will be taken from the input and used for output,
2665  * and the output's metadata (timestamps etc) will be taken as (optionally)
2666  * set by the subclass on @frame's (input) buffer (which is otherwise
2667  * ignored for any but the above purpose/information).
2668  *
2669  * Note that the latter buffer is invalidated by this call, whereas the
2670  * caller retains ownership of @frame.
2671  *
2672  * Returns: a #GstFlowReturn that should be escalated to caller (of caller)
2673  */
2674 GstFlowReturn
2675 gst_base_parse_finish_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
2676     gint size)
2677 {
2678   GstFlowReturn ret = GST_FLOW_OK;
2679
2680   g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
2681   g_return_val_if_fail (frame->buffer != NULL, GST_FLOW_ERROR);
2682   g_return_val_if_fail (size > 0 || frame->out_buffer, GST_FLOW_ERROR);
2683   g_return_val_if_fail (gst_adapter_available (parse->priv->adapter) >= size,
2684       GST_FLOW_ERROR);
2685
2686   GST_LOG_OBJECT (parse, "finished frame at offset %" G_GUINT64_FORMAT ", "
2687       "flushing size %d", frame->offset, size);
2688
2689   /* some one-time start-up */
2690   if (G_UNLIKELY (parse->priv->framecount == 0)) {
2691     gst_base_parse_check_seekability (parse);
2692     gst_base_parse_check_upstream (parse);
2693   }
2694
2695   parse->priv->flushed += size;
2696
2697   if (parse->priv->scanning && frame->buffer) {
2698     if (!parse->priv->scanned_frame) {
2699       parse->priv->scanned_frame = gst_base_parse_frame_copy (frame);
2700     }
2701     goto exit;
2702   }
2703
2704   /* either PUSH or PULL mode arranges for adapter data */
2705   /* ensure output buffer */
2706   if (!frame->out_buffer) {
2707     GstBuffer *src, *dest;
2708
2709     frame->out_buffer = gst_adapter_take_buffer (parse->priv->adapter, size);
2710     dest = frame->out_buffer;
2711     src = frame->buffer;
2712     GST_BUFFER_PTS (dest) = GST_BUFFER_PTS (src);
2713     GST_BUFFER_DTS (dest) = GST_BUFFER_DTS (src);
2714     GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
2715     GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
2716     GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
2717     GST_MINI_OBJECT_FLAGS (dest) = GST_MINI_OBJECT_FLAGS (src);
2718   } else {
2719     gst_adapter_flush (parse->priv->adapter, size);
2720   }
2721
2722   /* use as input for subsequent processing */
2723   gst_buffer_replace (&frame->buffer, frame->out_buffer);
2724   gst_buffer_unref (frame->out_buffer);
2725   frame->out_buffer = NULL;
2726
2727   /* mark input size consumed */
2728   frame->size = size;
2729
2730   /* subclass might queue frames/data internally if it needs more
2731    * frames to decide on the format, or might request us to queue here. */
2732   if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_DROP) {
2733     gst_buffer_replace (&frame->buffer, NULL);
2734     goto exit;
2735   } else if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_QUEUE) {
2736     GstBaseParseFrame *copy;
2737
2738     copy = gst_base_parse_frame_copy (frame);
2739     copy->flags &= ~GST_BASE_PARSE_FRAME_FLAG_QUEUE;
2740     gst_base_parse_queue_frame (parse, copy);
2741     goto exit;
2742   }
2743
2744   ret = gst_base_parse_handle_and_push_frame (parse, frame);
2745
2746 exit:
2747   return ret;
2748 }
2749
2750 /**
2751  * gst_base_parse_drain:
2752  * @parse: a #GstBaseParse
2753  *
2754  * Drains the adapter until it is empty. It decreases the min_frame_size to
2755  * match the current adapter size and calls chain method until the adapter
2756  * is emptied or chain returns with error.
2757  *
2758  * Since: 1.12
2759  */
2760 void
2761 gst_base_parse_drain (GstBaseParse * parse)
2762 {
2763   guint avail;
2764
2765   GST_DEBUG_OBJECT (parse, "draining");
2766   parse->priv->drain = TRUE;
2767
2768   for (;;) {
2769     avail = gst_adapter_available (parse->priv->adapter);
2770     if (!avail)
2771       break;
2772
2773     if (gst_base_parse_chain (parse->sinkpad, GST_OBJECT_CAST (parse),
2774             NULL) != GST_FLOW_OK) {
2775       break;
2776     }
2777
2778     /* nothing changed, maybe due to truncated frame; break infinite loop */
2779     if (avail == gst_adapter_available (parse->priv->adapter)) {
2780       GST_DEBUG_OBJECT (parse, "no change during draining; flushing");
2781       gst_adapter_clear (parse->priv->adapter);
2782     }
2783   }
2784
2785   parse->priv->drain = FALSE;
2786 }
2787
2788 /* gst_base_parse_send_buffers
2789  *
2790  * Sends buffers collected in send_buffers downstream, and ensures that list
2791  * is empty at the end (errors or not).
2792  */
2793 static GstFlowReturn
2794 gst_base_parse_send_buffers (GstBaseParse * parse)
2795 {
2796   GSList *send = NULL;
2797   GstBuffer *buf;
2798   GstFlowReturn ret = GST_FLOW_OK;
2799   gboolean first = TRUE;
2800
2801   send = parse->priv->buffers_send;
2802
2803   /* send buffers */
2804   while (send) {
2805     buf = GST_BUFFER_CAST (send->data);
2806     GST_LOG_OBJECT (parse, "pushing buffer %p, dts %"
2807         GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
2808         ", offset %" G_GINT64_FORMAT, buf,
2809         GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
2810         GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
2811         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf));
2812
2813     /* Make sure the first buffer is always DISCONT. If we split
2814      * GOPs inside the parser this is otherwise not guaranteed */
2815     if (first) {
2816       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
2817       first = FALSE;
2818     } else {
2819       /* likewise, subsequent buffers should never have DISCONT
2820        * according to the "reverse fragment protocol", or such would
2821        * confuse a downstream decoder
2822        * (could be DISCONT due to aggregating upstream fragments by parsing) */
2823       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
2824     }
2825
2826     /* iterate output queue an push downstream */
2827     ret = gst_pad_push (parse->srcpad, buf);
2828     send = g_slist_delete_link (send, send);
2829
2830     /* clear any leftover if error */
2831     if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2832       while (send) {
2833         buf = GST_BUFFER_CAST (send->data);
2834         gst_buffer_unref (buf);
2835         send = g_slist_delete_link (send, send);
2836       }
2837     }
2838   }
2839
2840   parse->priv->buffers_send = send;
2841
2842   return ret;
2843 }
2844
2845 /* gst_base_parse_start_fragment:
2846  *
2847  * Prepares for processing a reverse playback (forward) fragment
2848  * by (re)setting proper state variables.
2849  */
2850 static GstFlowReturn
2851 gst_base_parse_start_fragment (GstBaseParse * parse)
2852 {
2853   GST_LOG_OBJECT (parse, "starting fragment");
2854
2855   /* invalidate so no fall-back timestamping is performed;
2856    * ok if taken from subclass or upstream */
2857   parse->priv->next_pts = GST_CLOCK_TIME_NONE;
2858   parse->priv->prev_pts = GST_CLOCK_TIME_NONE;
2859   parse->priv->next_dts = GST_CLOCK_TIME_NONE;
2860   parse->priv->prev_dts = GST_CLOCK_TIME_NONE;
2861   parse->priv->prev_dts_from_pts = FALSE;
2862   /* prevent it hanging around stop all the time */
2863   parse->segment.position = GST_CLOCK_TIME_NONE;
2864   /* mark next run */
2865   parse->priv->discont = TRUE;
2866
2867   /* head of previous fragment is now pending tail of current fragment */
2868   parse->priv->buffers_pending = parse->priv->buffers_head;
2869   parse->priv->buffers_head = NULL;
2870
2871   return GST_FLOW_OK;
2872 }
2873
2874
2875 /* gst_base_parse_finish_fragment:
2876  *
2877  * Processes a reverse playback (forward) fragment:
2878  * - append head of last fragment that was skipped to current fragment data
2879  * - drain the resulting current fragment data (i.e. repeated chain)
2880  * - add time/duration (if needed) to frames queued by chain
2881  * - push queued data
2882  */
2883 static GstFlowReturn
2884 gst_base_parse_finish_fragment (GstBaseParse * parse, gboolean prev_head)
2885 {
2886   GstBuffer *buf;
2887   GstFlowReturn ret = GST_FLOW_OK;
2888   gboolean seen_key = FALSE, seen_delta = FALSE;
2889
2890   GST_LOG_OBJECT (parse, "finishing fragment");
2891
2892   /* restore order */
2893   parse->priv->buffers_pending = g_slist_reverse (parse->priv->buffers_pending);
2894   while (parse->priv->buffers_pending) {
2895     buf = GST_BUFFER_CAST (parse->priv->buffers_pending->data);
2896     if (prev_head) {
2897       GST_LOG_OBJECT (parse, "adding pending buffer (size %" G_GSIZE_FORMAT ")",
2898           gst_buffer_get_size (buf));
2899       gst_adapter_push (parse->priv->adapter, buf);
2900     } else {
2901       GST_LOG_OBJECT (parse, "discarding head buffer");
2902       gst_buffer_unref (buf);
2903     }
2904     parse->priv->buffers_pending =
2905         g_slist_delete_link (parse->priv->buffers_pending,
2906         parse->priv->buffers_pending);
2907   }
2908
2909   /* chain looks for frames and queues resulting ones (in stead of pushing) */
2910   /* initial skipped data is added to buffers_pending */
2911   gst_base_parse_drain (parse);
2912
2913   if (parse->priv->buffers_send) {
2914     buf = GST_BUFFER_CAST (parse->priv->buffers_send->data);
2915     seen_key |= !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2916   }
2917
2918   /* add metadata (if needed to queued buffers */
2919   GST_LOG_OBJECT (parse, "last timestamp: %" GST_TIME_FORMAT,
2920       GST_TIME_ARGS (parse->priv->last_pts));
2921   while (parse->priv->buffers_queued) {
2922     buf = GST_BUFFER_CAST (parse->priv->buffers_queued->data);
2923
2924     /* no touching if upstream or parsing provided time */
2925     if (GST_BUFFER_PTS_IS_VALID (buf)) {
2926       GST_LOG_OBJECT (parse, "buffer has time %" GST_TIME_FORMAT,
2927           GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
2928     } else if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2929       if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_pts)) {
2930         if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_pts))
2931           parse->priv->last_pts -= GST_BUFFER_DURATION (buf);
2932         else
2933           parse->priv->last_pts = 0;
2934         GST_BUFFER_PTS (buf) = parse->priv->last_pts;
2935         GST_LOG_OBJECT (parse, "applied time %" GST_TIME_FORMAT,
2936             GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
2937       }
2938       if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_dts)) {
2939         if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_dts))
2940           parse->priv->last_dts -= GST_BUFFER_DURATION (buf);
2941         else
2942           parse->priv->last_dts = 0;
2943         GST_BUFFER_DTS (buf) = parse->priv->last_dts;
2944         GST_LOG_OBJECT (parse, "applied dts %" GST_TIME_FORMAT,
2945             GST_TIME_ARGS (GST_BUFFER_DTS (buf)));
2946       }
2947     } else {
2948       /* no idea, very bad */
2949       GST_WARNING_OBJECT (parse, "could not determine time for buffer");
2950     }
2951
2952     parse->priv->last_pts = GST_BUFFER_PTS (buf);
2953     parse->priv->last_dts = GST_BUFFER_DTS (buf);
2954
2955     /* reverse order for ascending sending */
2956     /* send downstream at keyframe not preceded by a keyframe
2957      * (e.g. that should identify start of collection of IDR nals) */
2958     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
2959       if (seen_key) {
2960         ret = gst_base_parse_send_buffers (parse);
2961         /* if a problem, throw all to sending */
2962         if (ret != GST_FLOW_OK) {
2963           parse->priv->buffers_send =
2964               g_slist_reverse (parse->priv->buffers_queued);
2965           parse->priv->buffers_queued = NULL;
2966           break;
2967         }
2968         seen_key = FALSE;
2969       }
2970       seen_delta = TRUE;
2971     } else {
2972       seen_key = TRUE;
2973     }
2974
2975     parse->priv->buffers_send =
2976         g_slist_prepend (parse->priv->buffers_send, buf);
2977     parse->priv->buffers_queued =
2978         g_slist_delete_link (parse->priv->buffers_queued,
2979         parse->priv->buffers_queued);
2980   }
2981
2982   /* audio may have all marked as keyframe, so arrange to send here. Also
2983    * we might have ended the loop above on a keyframe, in which case we
2984    * should */
2985   if (!seen_delta || seen_key)
2986     ret = gst_base_parse_send_buffers (parse);
2987
2988   /* any trailing unused no longer usable (ideally none) */
2989   if (G_UNLIKELY (gst_adapter_available (parse->priv->adapter))) {
2990     GST_DEBUG_OBJECT (parse, "discarding %" G_GSIZE_FORMAT " trailing bytes",
2991         gst_adapter_available (parse->priv->adapter));
2992     gst_adapter_clear (parse->priv->adapter);
2993   }
2994
2995   return ret;
2996 }
2997
2998 /* small helper that checks whether we have been trying to resync too long */
2999 static inline GstFlowReturn
3000 gst_base_parse_check_sync (GstBaseParse * parse)
3001 {
3002   if (G_UNLIKELY (parse->priv->discont &&
3003           parse->priv->offset - parse->priv->sync_offset > 2 * 1024 * 1024)) {
3004     GST_ELEMENT_ERROR (parse, STREAM, DECODE,
3005         ("Failed to parse stream"), (NULL));
3006     return GST_FLOW_ERROR;
3007   }
3008
3009   return GST_FLOW_OK;
3010 }
3011
3012 static GstFlowReturn
3013 gst_base_parse_process_streamheader (GstBaseParse * parse)
3014 {
3015   GstCaps *caps;
3016   GstStructure *str;
3017   const GValue *value;
3018   GstFlowReturn ret = GST_FLOW_OK;
3019
3020   caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
3021   if (caps == NULL)
3022     goto notfound;
3023
3024   str = gst_caps_get_structure (caps, 0);
3025   value = gst_structure_get_value (str, "streamheader");
3026   if (value == NULL)
3027     goto notfound;
3028
3029   GST_DEBUG_OBJECT (parse, "Found streamheader field on input caps");
3030
3031   if (GST_VALUE_HOLDS_ARRAY (value)) {
3032     gint i;
3033     gsize len = gst_value_array_get_size (value);
3034
3035     for (i = 0; i < len; i++) {
3036       GstBuffer *buffer =
3037           gst_value_get_buffer (gst_value_array_get_value (value, i));
3038       ret =
3039           gst_base_parse_chain (GST_BASE_PARSE_SINK_PAD (parse),
3040           GST_OBJECT_CAST (parse), gst_buffer_ref (buffer));
3041     }
3042
3043   } else if (GST_VALUE_HOLDS_BUFFER (value)) {
3044     GstBuffer *buffer = gst_value_get_buffer (value);
3045     ret =
3046         gst_base_parse_chain (GST_BASE_PARSE_SINK_PAD (parse),
3047         GST_OBJECT_CAST (parse), gst_buffer_ref (buffer));
3048   }
3049
3050   gst_caps_unref (caps);
3051
3052   return ret;
3053
3054 notfound:
3055   {
3056     if (caps) {
3057       gst_caps_unref (caps);
3058     }
3059
3060     GST_DEBUG_OBJECT (parse, "No streamheader on caps");
3061     return GST_FLOW_OK;
3062   }
3063 }
3064
3065 static GstFlowReturn
3066 gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
3067 {
3068   GstBaseParseClass *bclass;
3069   GstBaseParse *parse;
3070   GstFlowReturn ret = GST_FLOW_OK;
3071   GstFlowReturn old_ret = GST_FLOW_OK;
3072   GstBuffer *tmpbuf = NULL;
3073   guint fsize = 1;
3074   gint skip = -1;
3075   guint min_size, av;
3076   GstClockTime pts, dts;
3077
3078   parse = GST_BASE_PARSE (parent);
3079   bclass = GST_BASE_PARSE_GET_CLASS (parse);
3080   GST_DEBUG_OBJECT (parent, "chain");
3081
3082   /* early out for speed, if we need to skip */
3083   if (buffer && GST_BUFFER_IS_DISCONT (buffer))
3084     parse->priv->skip = 0;
3085   if (parse->priv->skip > 0) {
3086     gsize bsize = gst_buffer_get_size (buffer);
3087     GST_DEBUG ("Got %" G_GSIZE_FORMAT " buffer, need to skip %u", bsize,
3088         parse->priv->skip);
3089     if (parse->priv->skip >= bsize) {
3090       parse->priv->skip -= bsize;
3091       GST_DEBUG ("All the buffer is skipped");
3092       parse->priv->offset += bsize;
3093       parse->priv->sync_offset = parse->priv->offset;
3094       return GST_FLOW_OK;
3095     }
3096     buffer = gst_buffer_make_writable (buffer);
3097     gst_buffer_resize (buffer, parse->priv->skip, bsize - parse->priv->skip);
3098     parse->priv->offset += parse->priv->skip;
3099     GST_DEBUG ("Done skipping, we have %u left on this buffer",
3100         (unsigned) (bsize - parse->priv->skip));
3101     parse->priv->skip = 0;
3102     parse->priv->discont = TRUE;
3103   }
3104
3105   if (G_UNLIKELY (parse->priv->first_buffer)) {
3106     parse->priv->first_buffer = FALSE;
3107     if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) {
3108       /* this stream has no header buffers, check if we just prepend the
3109        * streamheader from caps to the stream */
3110       GST_DEBUG_OBJECT (parse, "Looking for streamheader field on caps to "
3111           "prepend to the stream");
3112       gst_base_parse_process_streamheader (parse);
3113     } else {
3114       GST_DEBUG_OBJECT (parse, "Stream has header buffers, not prepending "
3115           "streamheader from caps");
3116     }
3117   }
3118
3119   if (parse->priv->detecting) {
3120     GstBuffer *detect_buf;
3121
3122     if (parse->priv->detect_buffers_size == 0) {
3123       detect_buf = gst_buffer_ref (buffer);
3124     } else {
3125       GList *l;
3126       guint offset = 0;
3127
3128       detect_buf = gst_buffer_new ();
3129
3130       for (l = parse->priv->detect_buffers; l; l = l->next) {
3131         gsize tmpsize = gst_buffer_get_size (l->data);
3132
3133         gst_buffer_copy_into (detect_buf, GST_BUFFER_CAST (l->data),
3134             GST_BUFFER_COPY_MEMORY, offset, tmpsize);
3135         offset += tmpsize;
3136       }
3137       if (buffer)
3138         gst_buffer_copy_into (detect_buf, buffer, GST_BUFFER_COPY_MEMORY,
3139             offset, gst_buffer_get_size (buffer));
3140     }
3141
3142     ret = bclass->detect (parse, detect_buf);
3143     gst_buffer_unref (detect_buf);
3144
3145     if (ret == GST_FLOW_OK) {
3146       GList *l;
3147
3148       /* Detected something */
3149       parse->priv->detecting = FALSE;
3150
3151       for (l = parse->priv->detect_buffers; l; l = l->next) {
3152         if (ret == GST_FLOW_OK && !parse->priv->flushing)
3153           ret =
3154               gst_base_parse_chain (GST_BASE_PARSE_SINK_PAD (parse),
3155               parent, GST_BUFFER_CAST (l->data));
3156         else
3157           gst_buffer_unref (GST_BUFFER_CAST (l->data));
3158       }
3159       g_list_free (parse->priv->detect_buffers);
3160       parse->priv->detect_buffers = NULL;
3161       parse->priv->detect_buffers_size = 0;
3162
3163       if (ret != GST_FLOW_OK) {
3164         return ret;
3165       }
3166
3167       /* Handle the current buffer */
3168     } else if (ret == GST_FLOW_NOT_NEGOTIATED) {
3169       /* Still detecting, append buffer or error out if draining */
3170
3171       if (parse->priv->drain) {
3172         GST_DEBUG_OBJECT (parse, "Draining but did not detect format yet");
3173         return GST_FLOW_ERROR;
3174       } else if (parse->priv->flushing) {
3175         g_list_foreach (parse->priv->detect_buffers, (GFunc) gst_buffer_unref,
3176             NULL);
3177         g_list_free (parse->priv->detect_buffers);
3178         parse->priv->detect_buffers = NULL;
3179         parse->priv->detect_buffers_size = 0;
3180       } else {
3181         parse->priv->detect_buffers =
3182             g_list_append (parse->priv->detect_buffers, buffer);
3183         parse->priv->detect_buffers_size += gst_buffer_get_size (buffer);
3184         return GST_FLOW_OK;
3185       }
3186     } else {
3187       /* Something went wrong, subclass responsible for error reporting */
3188       return ret;
3189     }
3190
3191     /* And now handle the current buffer if detection worked */
3192   }
3193
3194   if (G_LIKELY (buffer)) {
3195     GST_LOG_OBJECT (parse,
3196         "buffer size: %" G_GSIZE_FORMAT ", offset = %" G_GINT64_FORMAT
3197         ", dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
3198         gst_buffer_get_size (buffer), GST_BUFFER_OFFSET (buffer),
3199         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
3200         GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
3201
3202     if (G_UNLIKELY (!parse->priv->disable_passthrough
3203             && parse->priv->passthrough)) {
3204       GstBaseParseFrame frame;
3205
3206       gst_base_parse_frame_init (&frame);
3207       frame.buffer = gst_buffer_make_writable (buffer);
3208       ret = gst_base_parse_push_frame (parse, &frame);
3209       gst_base_parse_frame_free (&frame);
3210       return ret;
3211     }
3212     if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
3213       /* upstream feeding us in reverse playback;
3214        * finish previous fragment and start new upon DISCONT */
3215       if (parse->segment.rate < 0.0) {
3216         GST_DEBUG_OBJECT (parse, "buffer starts new reverse playback fragment");
3217         ret = gst_base_parse_finish_fragment (parse, TRUE);
3218         gst_base_parse_start_fragment (parse);
3219       } else {
3220         /* discont in the stream, drain and mark discont for next output */
3221         gst_base_parse_drain (parse);
3222         parse->priv->discont = TRUE;
3223       }
3224     }
3225     gst_adapter_push (parse->priv->adapter, buffer);
3226   }
3227
3228   /* Parse and push as many frames as possible */
3229   /* Stop either when adapter is empty or we are flushing */
3230   while (!parse->priv->flushing) {
3231     gint flush = 0;
3232     gboolean updated_prev_pts = FALSE;
3233
3234     /* note: if subclass indicates MAX fsize,
3235      * this will not likely be available anyway ... */
3236     min_size = MAX (parse->priv->min_frame_size, fsize);
3237     av = gst_adapter_available (parse->priv->adapter);
3238
3239     if (G_UNLIKELY (parse->priv->drain)) {
3240       min_size = av;
3241       GST_DEBUG_OBJECT (parse, "draining, data left: %d", min_size);
3242       if (G_UNLIKELY (!min_size)) {
3243         goto done;
3244       }
3245     }
3246
3247     /* Collect at least min_frame_size bytes */
3248     if (av < min_size) {
3249       GST_DEBUG_OBJECT (parse, "not enough data available (only %d bytes)", av);
3250       goto done;
3251     }
3252
3253     /* move along with upstream timestamp (if any),
3254      * but interpolate in between */
3255     pts = gst_adapter_prev_pts (parse->priv->adapter, NULL);
3256     dts = gst_adapter_prev_dts (parse->priv->adapter, NULL);
3257     if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts)) {
3258       parse->priv->prev_pts = parse->priv->next_pts = pts;
3259       updated_prev_pts = TRUE;
3260     }
3261
3262     if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts)) {
3263       parse->priv->prev_dts = parse->priv->next_dts = dts;
3264       parse->priv->prev_dts_from_pts = FALSE;
3265     }
3266
3267     /* we can mess with, erm interpolate, timestamps,
3268      * and incoming stuff has PTS but no DTS seen so far,
3269      * then pick up DTS from PTS and hope for the best ... */
3270     if (parse->priv->infer_ts &&
3271         parse->priv->pts_interpolate &&
3272         !GST_CLOCK_TIME_IS_VALID (dts) &&
3273         (!GST_CLOCK_TIME_IS_VALID (parse->priv->prev_dts)
3274             || (parse->priv->prev_dts_from_pts && updated_prev_pts))
3275         && GST_CLOCK_TIME_IS_VALID (pts)) {
3276       parse->priv->prev_dts = parse->priv->next_dts = pts;
3277       parse->priv->prev_dts_from_pts = TRUE;
3278     }
3279
3280     /* always pass all available data */
3281     tmpbuf = gst_adapter_get_buffer (parse->priv->adapter, av);
3282
3283     /* already inform subclass what timestamps we have planned,
3284      * at least if provided by time-based upstream */
3285     if (parse->priv->upstream_format == GST_FORMAT_TIME) {
3286       tmpbuf = gst_buffer_make_writable (tmpbuf);
3287       GST_BUFFER_PTS (tmpbuf) = parse->priv->next_pts;
3288       GST_BUFFER_DTS (tmpbuf) = parse->priv->next_dts;
3289       GST_BUFFER_DURATION (tmpbuf) = GST_CLOCK_TIME_NONE;
3290     }
3291
3292     /* keep the adapter mapped, so keep track of what has to be flushed */
3293     ret = gst_base_parse_handle_buffer (parse, tmpbuf, &skip, &flush);
3294     tmpbuf = NULL;
3295
3296     if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
3297       goto done;
3298     }
3299     if (skip == 0 && flush == 0) {
3300       GST_LOG_OBJECT (parse, "nothing skipped and no frames finished, "
3301           "breaking to get more data");
3302       /* ignore this return as it produced no data */
3303       ret = old_ret;
3304       goto done;
3305     }
3306     if (old_ret == GST_FLOW_OK)
3307       old_ret = ret;
3308   }
3309
3310 done:
3311   GST_LOG_OBJECT (parse, "chain leaving");
3312   return ret;
3313 }
3314
3315 /* pull @size bytes at current offset,
3316  * i.e. at least try to and possibly return a shorter buffer if near the end */
3317 static GstFlowReturn
3318 gst_base_parse_pull_range (GstBaseParse * parse, guint size,
3319     GstBuffer ** buffer)
3320 {
3321   GstFlowReturn ret = GST_FLOW_OK;
3322
3323   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
3324
3325   /* Caching here actually makes much less difference than one would expect.
3326    * We do it mainly to avoid pulling buffers of 1 byte all the time */
3327   if (parse->priv->cache) {
3328     gint64 cache_offset = GST_BUFFER_OFFSET (parse->priv->cache);
3329     gint cache_size = gst_buffer_get_size (parse->priv->cache);
3330
3331     if (cache_offset <= parse->priv->offset &&
3332         (parse->priv->offset + size) <= (cache_offset + cache_size)) {
3333       *buffer = gst_buffer_copy_region (parse->priv->cache, GST_BUFFER_COPY_ALL,
3334           parse->priv->offset - cache_offset, size);
3335       GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
3336       return GST_FLOW_OK;
3337     }
3338     /* not enough data in the cache, free cache and get a new one */
3339     gst_buffer_unref (parse->priv->cache);
3340     parse->priv->cache = NULL;
3341   }
3342
3343   /* refill the cache */
3344   ret =
3345       gst_pad_pull_range (parse->sinkpad, parse->priv->offset, MAX (size,
3346           64 * 1024), &parse->priv->cache);
3347   if (ret != GST_FLOW_OK) {
3348     parse->priv->cache = NULL;
3349     return ret;
3350   }
3351
3352   if (gst_buffer_get_size (parse->priv->cache) >= size) {
3353     *buffer =
3354         gst_buffer_copy_region (parse->priv->cache, GST_BUFFER_COPY_ALL, 0,
3355         size);
3356     GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
3357     return GST_FLOW_OK;
3358   }
3359
3360   /* Not possible to get enough data, try a last time with
3361    * requesting exactly the size we need */
3362   gst_buffer_unref (parse->priv->cache);
3363   parse->priv->cache = NULL;
3364
3365   ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset, size,
3366       &parse->priv->cache);
3367
3368   if (ret != GST_FLOW_OK) {
3369     GST_DEBUG_OBJECT (parse, "pull_range returned %d", ret);
3370     *buffer = NULL;
3371     return ret;
3372   }
3373
3374   if (gst_buffer_get_size (parse->priv->cache) < size) {
3375     GST_DEBUG_OBJECT (parse, "Returning short buffer at offset %"
3376         G_GUINT64_FORMAT ": wanted %u bytes, got %" G_GSIZE_FORMAT " bytes",
3377         parse->priv->offset, size, gst_buffer_get_size (parse->priv->cache));
3378
3379     *buffer = parse->priv->cache;
3380     parse->priv->cache = NULL;
3381
3382     return GST_FLOW_OK;
3383   }
3384
3385   *buffer =
3386       gst_buffer_copy_region (parse->priv->cache, GST_BUFFER_COPY_ALL, 0, size);
3387   GST_BUFFER_OFFSET (*buffer) = parse->priv->offset;
3388
3389   return GST_FLOW_OK;
3390 }
3391
3392 static GstFlowReturn
3393 gst_base_parse_handle_previous_fragment (GstBaseParse * parse)
3394 {
3395   gint64 offset = 0;
3396   GstClockTime ts = 0;
3397   GstBuffer *buffer;
3398   GstFlowReturn ret;
3399
3400   GST_DEBUG_OBJECT (parse, "fragment ended; last_ts = %" GST_TIME_FORMAT
3401       ", last_offset = %" G_GINT64_FORMAT,
3402       GST_TIME_ARGS (parse->priv->last_pts), parse->priv->last_offset);
3403
3404   if (!parse->priv->last_offset
3405       || parse->priv->last_pts <= parse->segment.start) {
3406     GST_DEBUG_OBJECT (parse, "past start of segment %" GST_TIME_FORMAT,
3407         GST_TIME_ARGS (parse->segment.start));
3408     ret = GST_FLOW_EOS;
3409     goto exit;
3410   }
3411
3412   /* last fragment started at last_offset / last_ts;
3413    * seek back 10s capped at 1MB */
3414   if (parse->priv->last_pts >= 10 * GST_SECOND)
3415     ts = parse->priv->last_pts - 10 * GST_SECOND;
3416   /* if we are exact now, we will be more so going backwards */
3417   if (parse->priv->exact_position) {
3418     offset = gst_base_parse_find_offset (parse, ts, TRUE, NULL);
3419   } else {
3420     if (!gst_base_parse_convert (parse, GST_FORMAT_TIME, ts,
3421             GST_FORMAT_BYTES, &offset)) {
3422       GST_DEBUG_OBJECT (parse, "conversion failed, only BYTE based");
3423     }
3424   }
3425   offset = CLAMP (offset, parse->priv->last_offset - 1024 * 1024,
3426       parse->priv->last_offset - 1024);
3427   offset = MAX (0, offset);
3428
3429   GST_DEBUG_OBJECT (parse, "next fragment from offset %" G_GINT64_FORMAT,
3430       offset);
3431   parse->priv->offset = offset;
3432
3433   ret = gst_base_parse_pull_range (parse, parse->priv->last_offset - offset,
3434       &buffer);
3435   if (ret != GST_FLOW_OK)
3436     goto exit;
3437
3438   /* offset will increase again as fragment is processed/parsed */
3439   parse->priv->last_offset = offset;
3440
3441   gst_base_parse_start_fragment (parse);
3442   gst_adapter_push (parse->priv->adapter, buffer);
3443   ret = gst_base_parse_finish_fragment (parse, TRUE);
3444   if (ret != GST_FLOW_OK)
3445     goto exit;
3446
3447   /* force previous fragment */
3448   parse->priv->offset = -1;
3449
3450 exit:
3451   return ret;
3452 }
3453
3454 /* PULL mode:
3455  * pull and scan for next frame starting from current offset
3456  * ajusts sync, drain and offset going along */
3457 static GstFlowReturn
3458 gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass)
3459 {
3460   GstBuffer *buffer;
3461   GstFlowReturn ret = GST_FLOW_OK;
3462   guint fsize, min_size;
3463   gint flushed = 0;
3464   gint skip = 0;
3465
3466   GST_LOG_OBJECT (parse, "scanning for frame at offset %" G_GUINT64_FORMAT
3467       " (%#" G_GINT64_MODIFIER "x)", parse->priv->offset, parse->priv->offset);
3468
3469   /* let's make this efficient for all subclass once and for all;
3470    * maybe it does not need this much, but in the latter case, we know we are
3471    * in pull mode here and might as well try to read and supply more anyway
3472    * (so does the buffer caching mechanism) */
3473   fsize = 64 * 1024;
3474
3475   while (TRUE) {
3476     min_size = MAX (parse->priv->min_frame_size, fsize);
3477
3478     GST_LOG_OBJECT (parse, "reading buffer size %u", min_size);
3479
3480     ret = gst_base_parse_pull_range (parse, min_size, &buffer);
3481     if (ret != GST_FLOW_OK)
3482       goto done;
3483
3484     /* if we got a short read, inform subclass we are draining leftover
3485      * and no more is to be expected */
3486     if (gst_buffer_get_size (buffer) < min_size) {
3487       GST_LOG_OBJECT (parse, "... but did not get that; marked draining");
3488       parse->priv->drain = TRUE;
3489     }
3490
3491     if (parse->priv->detecting) {
3492       ret = klass->detect (parse, buffer);
3493       if (ret == GST_FLOW_NOT_NEGOTIATED) {
3494         /* If draining we error out, otherwise request a buffer
3495          * with 64kb more */
3496         if (parse->priv->drain) {
3497           gst_buffer_unref (buffer);
3498           GST_ERROR_OBJECT (parse, "Failed to detect format but draining");
3499           return GST_FLOW_ERROR;
3500         } else {
3501           fsize += 64 * 1024;
3502           gst_buffer_unref (buffer);
3503           continue;
3504         }
3505       } else if (ret != GST_FLOW_OK) {
3506         gst_buffer_unref (buffer);
3507         GST_ERROR_OBJECT (parse, "detect() returned %s",
3508             gst_flow_get_name (ret));
3509         return ret;
3510       }
3511
3512       /* Else handle this buffer normally */
3513     }
3514
3515     ret = gst_base_parse_handle_buffer (parse, buffer, &skip, &flushed);
3516     if (ret != GST_FLOW_OK)
3517       break;
3518
3519     /* If a large amount of data was requested to be skipped, _handle_buffer
3520        might have set the priv->skip flag to an extra amount on top of skip.
3521        In pull mode, we can just pull from the new offset directly. */
3522     parse->priv->offset += parse->priv->skip;
3523     parse->priv->skip = 0;
3524
3525     /* something flushed means something happened,
3526      * and we should bail out of this loop so as not to occupy
3527      * the task thread indefinitely */
3528     if (flushed) {
3529       GST_LOG_OBJECT (parse, "frame finished, breaking loop");
3530       break;
3531     }
3532     /* nothing flushed, no skip and draining, so nothing left to do */
3533     if (!skip && parse->priv->drain) {
3534       GST_LOG_OBJECT (parse, "no activity or result when draining; "
3535           "breaking loop and marking EOS");
3536       ret = GST_FLOW_EOS;
3537       break;
3538     }
3539     /* otherwise, get some more data
3540      * note that is checked this does not happen indefinitely */
3541     if (!skip) {
3542       GST_LOG_OBJECT (parse, "getting some more data");
3543       fsize += 64 * 1024;
3544     }
3545     parse->priv->drain = FALSE;
3546   }
3547
3548 done:
3549   return ret;
3550 }
3551
3552 /* Loop that is used in pull mode to retrieve data from upstream */
3553 static void
3554 gst_base_parse_loop (GstPad * pad)
3555 {
3556   GstBaseParse *parse;
3557   GstBaseParseClass *klass;
3558   GstFlowReturn ret = GST_FLOW_OK;
3559
3560   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
3561   klass = GST_BASE_PARSE_GET_CLASS (parse);
3562
3563   GST_LOG_OBJECT (parse, "Entering parse loop");
3564
3565   if (G_UNLIKELY (parse->priv->push_stream_start)) {
3566     gchar *stream_id;
3567     GstEvent *event;
3568
3569     stream_id =
3570         gst_pad_create_stream_id (parse->srcpad, GST_ELEMENT_CAST (parse),
3571         NULL);
3572
3573     event = gst_event_new_stream_start (stream_id);
3574     gst_event_set_group_id (event, gst_util_group_id_next ());
3575
3576     GST_DEBUG_OBJECT (parse, "Pushing STREAM_START");
3577     gst_pad_push_event (parse->srcpad, event);
3578     parse->priv->push_stream_start = FALSE;
3579     g_free (stream_id);
3580   }
3581
3582   /* reverse playback:
3583    * first fragment (closest to stop time) is handled normally below,
3584    * then we pull in fragments going backwards */
3585   if (parse->segment.rate < 0.0) {
3586     /* check if we jumped back to a previous fragment,
3587      * which is a post-first fragment */
3588     if (parse->priv->offset < 0) {
3589       ret = gst_base_parse_handle_previous_fragment (parse);
3590       goto done;
3591     }
3592   }
3593
3594   ret = gst_base_parse_scan_frame (parse, klass);
3595
3596   /* eat expected eos signalling past segment in reverse playback */
3597   if (parse->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
3598       parse->segment.position >= parse->segment.stop) {
3599     GST_DEBUG_OBJECT (parse, "downstream has reached end of segment");
3600     /* push what was accumulated during loop run */
3601     gst_base_parse_finish_fragment (parse, FALSE);
3602     /* force previous fragment */
3603     parse->priv->offset = -1;
3604     goto eos;
3605   }
3606
3607   if (ret != GST_FLOW_OK)
3608     goto done;
3609
3610 done:
3611   if (ret == GST_FLOW_EOS)
3612     goto eos;
3613   else if (ret != GST_FLOW_OK)
3614     goto pause;
3615
3616   gst_object_unref (parse);
3617   return;
3618
3619   /* ERRORS */
3620 eos:
3621   {
3622     ret = GST_FLOW_EOS;
3623     GST_DEBUG_OBJECT (parse, "eos");
3624     /* fall-through */
3625   }
3626 pause:
3627   {
3628     gboolean push_eos = FALSE;
3629
3630     GST_DEBUG_OBJECT (parse, "pausing task, reason %s",
3631         gst_flow_get_name (ret));
3632     gst_pad_pause_task (parse->sinkpad);
3633
3634     if (ret == GST_FLOW_EOS) {
3635       /* handle end-of-stream/segment */
3636       if (parse->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
3637         gint64 stop;
3638
3639         if ((stop = parse->segment.stop) == -1)
3640           stop = parse->segment.duration;
3641
3642         GST_DEBUG_OBJECT (parse, "sending segment_done");
3643
3644         gst_element_post_message
3645             (GST_ELEMENT_CAST (parse),
3646             gst_message_new_segment_done (GST_OBJECT_CAST (parse),
3647                 GST_FORMAT_TIME, stop));
3648         gst_pad_push_event (parse->srcpad,
3649             gst_event_new_segment_done (GST_FORMAT_TIME, stop));
3650       } else {
3651         /* If we STILL have zero frames processed, fire an error */
3652         if (parse->priv->framecount == 0) {
3653           GST_ELEMENT_ERROR (parse, STREAM, WRONG_TYPE,
3654               ("No valid frames found before end of stream"), (NULL));
3655         }
3656         push_eos = TRUE;
3657       }
3658     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
3659       /* for fatal errors we post an error message, wrong-state is
3660        * not fatal because it happens due to flushes and only means
3661        * that we should stop now. */
3662       GST_ELEMENT_FLOW_ERROR (parse, ret);
3663       push_eos = TRUE;
3664     }
3665     if (push_eos) {
3666       if (parse->priv->estimated_duration <= 0) {
3667         gst_base_parse_update_duration (parse);
3668       }
3669       /* Push pending events, including SEGMENT events */
3670       gst_base_parse_push_pending_events (parse);
3671
3672       gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
3673     }
3674     gst_object_unref (parse);
3675   }
3676 }
3677
3678 static gboolean
3679 gst_base_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
3680 {
3681   GstSchedulingFlags sched_flags;
3682   GstBaseParse *parse;
3683   GstQuery *query;
3684   gboolean pull_mode;
3685
3686   parse = GST_BASE_PARSE (parent);
3687
3688   GST_DEBUG_OBJECT (parse, "sink activate");
3689
3690   query = gst_query_new_scheduling ();
3691   if (!gst_pad_peer_query (sinkpad, query)) {
3692     gst_query_unref (query);
3693     goto baseparse_push;
3694   }
3695
3696   gst_query_parse_scheduling (query, &sched_flags, NULL, NULL, NULL);
3697
3698   pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL)
3699       && ((sched_flags & GST_SCHEDULING_FLAG_SEEKABLE) != 0);
3700
3701   gst_query_unref (query);
3702
3703   if (!pull_mode)
3704     goto baseparse_push;
3705
3706   GST_DEBUG_OBJECT (parse, "trying to activate in pull mode");
3707   if (!gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE))
3708     goto baseparse_push;
3709
3710   parse->priv->push_stream_start = TRUE;
3711   /* In pull mode, upstream is BYTES */
3712   parse->priv->upstream_format = GST_FORMAT_BYTES;
3713
3714   return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_base_parse_loop,
3715       sinkpad, NULL);
3716   /* fallback */
3717 baseparse_push:
3718   {
3719     GST_DEBUG_OBJECT (parse, "trying to activate in push mode");
3720     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3721   }
3722 }
3723
3724 static gboolean
3725 gst_base_parse_activate (GstBaseParse * parse, gboolean active)
3726 {
3727   GstBaseParseClass *klass;
3728   gboolean result = TRUE;
3729
3730   GST_DEBUG_OBJECT (parse, "activate %d", active);
3731
3732   klass = GST_BASE_PARSE_GET_CLASS (parse);
3733
3734   if (active) {
3735     if (parse->priv->pad_mode == GST_PAD_MODE_NONE && klass->start)
3736       result = klass->start (parse);
3737
3738     /* If the subclass implements ::detect we want to
3739      * call it for the first buffers now */
3740     parse->priv->detecting = (klass->detect != NULL);
3741   } else {
3742     /* We must make sure streaming has finished before resetting things
3743      * and calling the ::stop vfunc */
3744     GST_PAD_STREAM_LOCK (parse->sinkpad);
3745     GST_PAD_STREAM_UNLOCK (parse->sinkpad);
3746
3747     if (parse->priv->pad_mode != GST_PAD_MODE_NONE && klass->stop)
3748       result = klass->stop (parse);
3749
3750     parse->priv->pad_mode = GST_PAD_MODE_NONE;
3751     parse->priv->upstream_format = GST_FORMAT_UNDEFINED;
3752   }
3753   GST_DEBUG_OBJECT (parse, "activate return: %d", result);
3754   return result;
3755 }
3756
3757 static gboolean
3758 gst_base_parse_sink_activate_mode (GstPad * pad, GstObject * parent,
3759     GstPadMode mode, gboolean active)
3760 {
3761   gboolean result;
3762   GstBaseParse *parse;
3763
3764   parse = GST_BASE_PARSE (parent);
3765
3766   GST_DEBUG_OBJECT (parse, "sink %sactivate in %s mode",
3767       (active) ? "" : "de", gst_pad_mode_get_name (mode));
3768
3769 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
3770     /* to know early what is the mode */
3771     parse->priv->expected_pad_mode = active ? mode : GST_PAD_MODE_NONE;
3772 #endif
3773
3774   if (!gst_base_parse_activate (parse, active))
3775     goto activate_failed;
3776
3777   switch (mode) {
3778     case GST_PAD_MODE_PULL:
3779       if (active) {
3780         parse->priv->pending_events =
3781             g_list_prepend (parse->priv->pending_events,
3782             gst_event_new_segment (&parse->segment));
3783         result = TRUE;
3784       } else {
3785         result = gst_pad_stop_task (pad);
3786       }
3787       break;
3788     default:
3789       result = TRUE;
3790       break;
3791   }
3792   if (result)
3793     parse->priv->pad_mode = active ? mode : GST_PAD_MODE_NONE;
3794
3795   GST_DEBUG_OBJECT (parse, "sink activate return: %d", result);
3796
3797   return result;
3798
3799   /* ERRORS */
3800 activate_failed:
3801   {
3802     GST_DEBUG_OBJECT (parse, "activate failed");
3803     return FALSE;
3804   }
3805 }
3806
3807 /**
3808  * gst_base_parse_set_duration:
3809  * @parse: #GstBaseParse.
3810  * @fmt: #GstFormat.
3811  * @duration: duration value.
3812  * @interval: how often to update the duration estimate based on bitrate, or 0.
3813  *
3814  * Sets the duration of the currently playing media. Subclass can use this
3815  * when it is able to determine duration and/or notices a change in the media
3816  * duration.  Alternatively, if @interval is non-zero (default), then stream
3817  * duration is determined based on estimated bitrate, and updated every @interval
3818  * frames.
3819  */
3820 void
3821 gst_base_parse_set_duration (GstBaseParse * parse,
3822     GstFormat fmt, gint64 duration, gint interval)
3823 {
3824   g_return_if_fail (parse != NULL);
3825
3826   if (parse->priv->upstream_has_duration) {
3827     GST_DEBUG_OBJECT (parse, "using upstream duration; discarding update");
3828     goto exit;
3829   }
3830
3831   if (duration != parse->priv->duration) {
3832     GstMessage *m;
3833
3834     m = gst_message_new_duration_changed (GST_OBJECT (parse));
3835     gst_element_post_message (GST_ELEMENT (parse), m);
3836
3837     /* TODO: what about duration tag? */
3838   }
3839   parse->priv->duration = duration;
3840   parse->priv->duration_fmt = fmt;
3841   GST_DEBUG_OBJECT (parse, "set duration: %" G_GINT64_FORMAT, duration);
3842   if (fmt == GST_FORMAT_TIME && GST_CLOCK_TIME_IS_VALID (duration)) {
3843     if (interval != 0) {
3844       GST_DEBUG_OBJECT (parse, "valid duration provided, disabling estimate");
3845       interval = 0;
3846     }
3847   }
3848   GST_DEBUG_OBJECT (parse, "set update interval: %d", interval);
3849   parse->priv->update_interval = interval;
3850 exit:
3851   return;
3852 }
3853
3854 /**
3855  * gst_base_parse_set_average_bitrate:
3856  * @parse: #GstBaseParse.
3857  * @bitrate: average bitrate in bits/second
3858  *
3859  * Optionally sets the average bitrate detected in media (if non-zero),
3860  * e.g. based on metadata, as it will be posted to the application.
3861  *
3862  * By default, announced average bitrate is estimated. The average bitrate
3863  * is used to estimate the total duration of the stream and to estimate
3864  * a seek position, if there's no index and the format is syncable
3865  * (see gst_base_parse_set_syncable()).
3866  */
3867 void
3868 gst_base_parse_set_average_bitrate (GstBaseParse * parse, guint bitrate)
3869 {
3870   parse->priv->bitrate = bitrate;
3871   GST_DEBUG_OBJECT (parse, "bitrate %u", bitrate);
3872 }
3873
3874 /**
3875  * gst_base_parse_set_min_frame_size:
3876  * @parse: #GstBaseParse.
3877  * @min_size: Minimum size of the data that this base class should give to
3878  *            subclass.
3879  *
3880  * Subclass can use this function to tell the base class that it needs to
3881  * give at least #min_size buffers.
3882  */
3883 void
3884 gst_base_parse_set_min_frame_size (GstBaseParse * parse, guint min_size)
3885 {
3886   g_return_if_fail (parse != NULL);
3887
3888   parse->priv->min_frame_size = min_size;
3889   GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size);
3890 }
3891
3892 /**
3893  * gst_base_parse_set_frame_rate:
3894  * @parse: the #GstBaseParse to set
3895  * @fps_num: frames per second (numerator).
3896  * @fps_den: frames per second (denominator).
3897  * @lead_in: frames needed before a segment for subsequent decode
3898  * @lead_out: frames needed after a segment
3899  *
3900  * If frames per second is configured, parser can take care of buffer duration
3901  * and timestamping.  When performing segment clipping, or seeking to a specific
3902  * location, a corresponding decoder might need an initial @lead_in and a
3903  * following @lead_out number of frames to ensure the desired segment is
3904  * entirely filled upon decoding.
3905  */
3906 void
3907 gst_base_parse_set_frame_rate (GstBaseParse * parse, guint fps_num,
3908     guint fps_den, guint lead_in, guint lead_out)
3909 {
3910   g_return_if_fail (parse != NULL);
3911
3912   parse->priv->fps_num = fps_num;
3913   parse->priv->fps_den = fps_den;
3914   if (!fps_num || !fps_den) {
3915     GST_DEBUG_OBJECT (parse, "invalid fps (%d/%d), ignoring parameters",
3916         fps_num, fps_den);
3917     fps_num = fps_den = 0;
3918     parse->priv->frame_duration = GST_CLOCK_TIME_NONE;
3919     parse->priv->lead_in = parse->priv->lead_out = 0;
3920     parse->priv->lead_in_ts = parse->priv->lead_out_ts = 0;
3921   } else {
3922     parse->priv->frame_duration =
3923         gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
3924     parse->priv->lead_in = lead_in;
3925     parse->priv->lead_out = lead_out;
3926     parse->priv->lead_in_ts =
3927         gst_util_uint64_scale (GST_SECOND, fps_den * lead_in, fps_num);
3928     parse->priv->lead_out_ts =
3929         gst_util_uint64_scale (GST_SECOND, fps_den * lead_out, fps_num);
3930     /* aim for about 1.5s to estimate duration */
3931     if (parse->priv->update_interval < 0) {
3932       parse->priv->update_interval = fps_num * 3 / (fps_den * 2);
3933       GST_LOG_OBJECT (parse, "estimated update interval to %d frames",
3934           parse->priv->update_interval);
3935     }
3936   }
3937   GST_LOG_OBJECT (parse, "set fps: %d/%d => duration: %" G_GINT64_FORMAT " ms",
3938       fps_num, fps_den, parse->priv->frame_duration / GST_MSECOND);
3939   GST_LOG_OBJECT (parse, "set lead in: %d frames = %" G_GUINT64_FORMAT " ms, "
3940       "lead out: %d frames = %" G_GUINT64_FORMAT " ms",
3941       lead_in, parse->priv->lead_in_ts / GST_MSECOND,
3942       lead_out, parse->priv->lead_out_ts / GST_MSECOND);
3943 }
3944
3945 /**
3946  * gst_base_parse_set_has_timing_info:
3947  * @parse: a #GstBaseParse
3948  * @has_timing: whether frames carry timing information
3949  *
3950  * Set if frames carry timing information which the subclass can (generally)
3951  * parse and provide.  In particular, intrinsic (rather than estimated) time
3952  * can be obtained following a seek.
3953  */
3954 void
3955 gst_base_parse_set_has_timing_info (GstBaseParse * parse, gboolean has_timing)
3956 {
3957   parse->priv->has_timing_info = has_timing;
3958   GST_INFO_OBJECT (parse, "has_timing: %s", (has_timing) ? "yes" : "no");
3959 }
3960
3961 /**
3962  * gst_base_parse_set_syncable:
3963  * @parse: a #GstBaseParse
3964  * @syncable: set if frame starts can be identified
3965  *
3966  * Set if frame starts can be identified. This is set by default and
3967  * determines whether seeking based on bitrate averages
3968  * is possible for a format/stream.
3969  */
3970 void
3971 gst_base_parse_set_syncable (GstBaseParse * parse, gboolean syncable)
3972 {
3973   parse->priv->syncable = syncable;
3974   GST_INFO_OBJECT (parse, "syncable: %s", (syncable) ? "yes" : "no");
3975 }
3976
3977 /**
3978  * gst_base_parse_set_passthrough:
3979  * @parse: a #GstBaseParse
3980  * @passthrough: %TRUE if parser should run in passthrough mode
3981  *
3982  * Set if the nature of the format or configuration does not allow (much)
3983  * parsing, and the parser should operate in passthrough mode (which only
3984  * applies when operating in push mode). That is, incoming buffers are
3985  * pushed through unmodified, i.e. no @check_valid_frame or @parse_frame
3986  * callbacks will be invoked, but @pre_push_frame will still be invoked,
3987  * so subclass can perform as much or as little is appropriate for
3988  * passthrough semantics in @pre_push_frame.
3989  */
3990 void
3991 gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough)
3992 {
3993   parse->priv->passthrough = passthrough;
3994   GST_INFO_OBJECT (parse, "passthrough: %s", (passthrough) ? "yes" : "no");
3995 }
3996
3997 /**
3998  * gst_base_parse_set_pts_interpolation:
3999  * @parse: a #GstBaseParse
4000  * @pts_interpolate: %TRUE if parser should interpolate PTS timestamps
4001  *
4002  * By default, the base class will guess PTS timestamps using a simple
4003  * interpolation (previous timestamp + duration), which is incorrect for
4004  * data streams with reordering, where PTS can go backward. Sub-classes
4005  * implementing such formats should disable PTS interpolation.
4006  */
4007 void
4008 gst_base_parse_set_pts_interpolation (GstBaseParse * parse,
4009     gboolean pts_interpolate)
4010 {
4011   parse->priv->pts_interpolate = pts_interpolate;
4012   GST_INFO_OBJECT (parse, "PTS interpolation: %s",
4013       (pts_interpolate) ? "yes" : "no");
4014 }
4015
4016 /**
4017  * gst_base_parse_set_infer_ts:
4018  * @parse: a #GstBaseParse
4019  * @infer_ts: %TRUE if parser should infer DTS/PTS from each other
4020  *
4021  * By default, the base class might try to infer PTS from DTS and vice
4022  * versa.  While this is generally correct for audio data, it may not
4023  * be otherwise. Sub-classes implementing such formats should disable
4024  * timestamp inferring.
4025  */
4026 void
4027 gst_base_parse_set_infer_ts (GstBaseParse * parse, gboolean infer_ts)
4028 {
4029   parse->priv->infer_ts = infer_ts;
4030   GST_INFO_OBJECT (parse, "TS inferring: %s", (infer_ts) ? "yes" : "no");
4031 }
4032
4033 /**
4034  * gst_base_parse_set_latency:
4035  * @parse: a #GstBaseParse
4036  * @min_latency: minimum parse latency
4037  * @max_latency: maximum parse latency
4038  *
4039  * Sets the minimum and maximum (which may likely be equal) latency introduced
4040  * by the parsing process.  If there is such a latency, which depends on the
4041  * particular parsing of the format, it typically corresponds to 1 frame duration.
4042  */
4043 void
4044 gst_base_parse_set_latency (GstBaseParse * parse, GstClockTime min_latency,
4045     GstClockTime max_latency)
4046 {
4047   g_return_if_fail (min_latency != GST_CLOCK_TIME_NONE);
4048   g_return_if_fail (min_latency <= max_latency);
4049
4050   GST_OBJECT_LOCK (parse);
4051   parse->priv->min_latency = min_latency;
4052   parse->priv->max_latency = max_latency;
4053   GST_OBJECT_UNLOCK (parse);
4054   GST_INFO_OBJECT (parse, "min/max latency %" GST_TIME_FORMAT ", %"
4055       GST_TIME_FORMAT, GST_TIME_ARGS (min_latency),
4056       GST_TIME_ARGS (max_latency));
4057 }
4058
4059 static gboolean
4060 gst_base_parse_get_duration (GstBaseParse * parse, GstFormat format,
4061     GstClockTime * duration)
4062 {
4063   gboolean res = FALSE;
4064
4065   g_return_val_if_fail (duration != NULL, FALSE);
4066
4067   *duration = GST_CLOCK_TIME_NONE;
4068   if (parse->priv->duration != -1 && format == parse->priv->duration_fmt) {
4069     GST_LOG_OBJECT (parse, "using provided duration");
4070     *duration = parse->priv->duration;
4071     res = TRUE;
4072   } else if (parse->priv->duration != -1) {
4073     GST_LOG_OBJECT (parse, "converting provided duration");
4074     res = gst_base_parse_convert (parse, parse->priv->duration_fmt,
4075         parse->priv->duration, format, (gint64 *) duration);
4076   } else if (format == GST_FORMAT_TIME && parse->priv->estimated_duration != -1) {
4077     GST_LOG_OBJECT (parse, "using estimated duration");
4078     *duration = parse->priv->estimated_duration;
4079     res = TRUE;
4080   } else {
4081     GST_LOG_OBJECT (parse, "cannot estimate duration");
4082   }
4083
4084   GST_LOG_OBJECT (parse, "res: %d, duration %" GST_TIME_FORMAT, res,
4085       GST_TIME_ARGS (*duration));
4086   return res;
4087 }
4088
4089 static gboolean
4090 gst_base_parse_src_query_default (GstBaseParse * parse, GstQuery * query)
4091 {
4092   gboolean res = FALSE;
4093   GstPad *pad;
4094
4095   pad = GST_BASE_PARSE_SRC_PAD (parse);
4096
4097   switch (GST_QUERY_TYPE (query)) {
4098     case GST_QUERY_POSITION:
4099     {
4100       gint64 dest_value;
4101       GstFormat format;
4102
4103       GST_DEBUG_OBJECT (parse, "position query");
4104       gst_query_parse_position (query, &format, NULL);
4105
4106       /* try upstream first */
4107       res = gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query);
4108       if (!res) {
4109         /* Fall back on interpreting segment */
4110         GST_OBJECT_LOCK (parse);
4111         /* Only reply BYTES if upstream is in BYTES already, otherwise
4112          * we're not in charge */
4113         if (format == GST_FORMAT_BYTES
4114             && parse->priv->upstream_format == GST_FORMAT_BYTES) {
4115           dest_value = parse->priv->offset;
4116           res = TRUE;
4117         } else if (format == parse->segment.format &&
4118             GST_CLOCK_TIME_IS_VALID (parse->segment.position)) {
4119           dest_value = gst_segment_to_stream_time (&parse->segment,
4120               parse->segment.format, parse->segment.position);
4121           res = TRUE;
4122         }
4123         GST_OBJECT_UNLOCK (parse);
4124         if (!res && parse->priv->upstream_format == GST_FORMAT_BYTES) {
4125           /* no precise result, upstream no idea either, then best estimate */
4126           /* priv->offset is updated in both PUSH/PULL modes, *iff* we're
4127            * in charge of things */
4128           res = gst_base_parse_convert (parse,
4129               GST_FORMAT_BYTES, parse->priv->offset, format, &dest_value);
4130         }
4131         if (res)
4132           gst_query_set_position (query, format, dest_value);
4133       }
4134       break;
4135     }
4136     case GST_QUERY_DURATION:
4137     {
4138       GstFormat format;
4139       GstClockTime duration;
4140
4141       GST_DEBUG_OBJECT (parse, "duration query");
4142       gst_query_parse_duration (query, &format, NULL);
4143
4144       /* consult upstream */
4145       res = gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query);
4146
4147       /* otherwise best estimate from us */
4148       if (!res) {
4149         res = gst_base_parse_get_duration (parse, format, &duration);
4150         if (res)
4151           gst_query_set_duration (query, format, duration);
4152       }
4153       break;
4154     }
4155     case GST_QUERY_SEEKING:
4156     {
4157       GstFormat fmt;
4158       GstClockTime duration = GST_CLOCK_TIME_NONE;
4159       gboolean seekable = FALSE;
4160
4161       GST_DEBUG_OBJECT (parse, "seeking query");
4162       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
4163
4164       /* consult upstream */
4165       res = gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query);
4166
4167       /* we may be able to help if in TIME */
4168       if (fmt == GST_FORMAT_TIME && gst_base_parse_is_seekable (parse)) {
4169         gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4170         /* already OK if upstream takes care */
4171         GST_LOG_OBJECT (parse, "upstream handled %d, seekable %d",
4172             res, seekable);
4173         if (!(res && seekable)) {
4174           if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &duration)
4175               || duration == -1) {
4176             /* seekable if we still have a chance to get duration later on */
4177             seekable =
4178                 parse->priv->upstream_seekable && parse->priv->update_interval;
4179           } else {
4180             seekable = parse->priv->upstream_seekable;
4181             GST_LOG_OBJECT (parse, "already determine upstream seekabled: %d",
4182                 seekable);
4183           }
4184           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
4185           res = TRUE;
4186         }
4187       }
4188       break;
4189     }
4190     case GST_QUERY_FORMATS:
4191       gst_query_set_formatsv (query, 3, fmtlist);
4192       res = TRUE;
4193       break;
4194     case GST_QUERY_CONVERT:
4195     {
4196       GstFormat src_format, dest_format;
4197       gint64 src_value, dest_value;
4198
4199       gst_query_parse_convert (query, &src_format, &src_value,
4200           &dest_format, &dest_value);
4201
4202       res = gst_base_parse_convert (parse, src_format, src_value,
4203           dest_format, &dest_value);
4204       if (res) {
4205         gst_query_set_convert (query, src_format, src_value,
4206             dest_format, dest_value);
4207       }
4208       break;
4209     }
4210     case GST_QUERY_LATENCY:
4211     {
4212       if ((res = gst_pad_peer_query (parse->sinkpad, query))) {
4213         gboolean live;
4214         GstClockTime min_latency, max_latency;
4215
4216         gst_query_parse_latency (query, &live, &min_latency, &max_latency);
4217         GST_DEBUG_OBJECT (parse, "Peer latency: live %d, min %"
4218             GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4219             GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
4220
4221         GST_OBJECT_LOCK (parse);
4222         /* add our latency */
4223         min_latency += parse->priv->min_latency;
4224         if (max_latency == -1 || parse->priv->max_latency == -1)
4225           max_latency = -1;
4226         else
4227           max_latency += parse->priv->max_latency;
4228         GST_OBJECT_UNLOCK (parse);
4229
4230         gst_query_set_latency (query, live, min_latency, max_latency);
4231       }
4232       break;
4233     }
4234     case GST_QUERY_SEGMENT:
4235     {
4236       GstFormat format;
4237       gint64 start, stop;
4238
4239       format = parse->segment.format;
4240
4241       start =
4242           gst_segment_to_stream_time (&parse->segment, format,
4243           parse->segment.start);
4244       if ((stop = parse->segment.stop) == -1)
4245         stop = parse->segment.duration;
4246       else
4247         stop = gst_segment_to_stream_time (&parse->segment, format, stop);
4248
4249       gst_query_set_segment (query, parse->segment.rate, format, start, stop);
4250       res = TRUE;
4251       break;
4252     }
4253     default:
4254       res = gst_pad_query_default (pad, GST_OBJECT_CAST (parse), query);
4255       break;
4256   }
4257   return res;
4258 }
4259
4260 /* scans for a cluster start from @pos,
4261  * return GST_FLOW_OK and frame position/time in @pos/@time if found */
4262 static GstFlowReturn
4263 gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos,
4264     GstClockTime * time, GstClockTime * duration)
4265 {
4266   GstBaseParseClass *klass;
4267   gint64 orig_offset;
4268   gboolean orig_drain, orig_discont;
4269   GstFlowReturn ret = GST_FLOW_OK;
4270   GstBuffer *buf = NULL;
4271   GstBaseParseFrame *sframe = NULL;
4272
4273   g_return_val_if_fail (pos != NULL, GST_FLOW_ERROR);
4274   g_return_val_if_fail (time != NULL, GST_FLOW_ERROR);
4275   g_return_val_if_fail (duration != NULL, GST_FLOW_ERROR);
4276
4277   klass = GST_BASE_PARSE_GET_CLASS (parse);
4278
4279   *time = GST_CLOCK_TIME_NONE;
4280   *duration = GST_CLOCK_TIME_NONE;
4281
4282   /* save state */
4283   orig_offset = parse->priv->offset;
4284   orig_discont = parse->priv->discont;
4285   orig_drain = parse->priv->drain;
4286
4287   GST_DEBUG_OBJECT (parse, "scanning for frame starting at %" G_GINT64_FORMAT
4288       " (%#" G_GINT64_MODIFIER "x)", *pos, *pos);
4289
4290   /* jump elsewhere and locate next frame */
4291   parse->priv->offset = *pos;
4292   /* mark as scanning so frames don't get processed all the way */
4293   parse->priv->scanning = TRUE;
4294   ret = gst_base_parse_scan_frame (parse, klass);
4295   parse->priv->scanning = FALSE;
4296   /* retrieve frame found during scan */
4297   sframe = parse->priv->scanned_frame;
4298   parse->priv->scanned_frame = NULL;
4299
4300   if (ret != GST_FLOW_OK || !sframe)
4301     goto done;
4302
4303   /* get offset first, subclass parsing might dump other stuff in there */
4304   *pos = sframe->offset;
4305   buf = sframe->buffer;
4306   g_assert (buf);
4307
4308   /* but it should provide proper time */
4309   *time = GST_BUFFER_TIMESTAMP (buf);
4310   *duration = GST_BUFFER_DURATION (buf);
4311
4312   GST_LOG_OBJECT (parse,
4313       "frame with time %" GST_TIME_FORMAT " at offset %" G_GINT64_FORMAT,
4314       GST_TIME_ARGS (*time), *pos);
4315
4316 done:
4317   if (sframe)
4318     gst_base_parse_frame_free (sframe);
4319
4320   /* restore state */
4321   parse->priv->offset = orig_offset;
4322   parse->priv->discont = orig_discont;
4323   parse->priv->drain = orig_drain;
4324
4325   return ret;
4326 }
4327
4328 /* bisect and scan through file for frame starting before @time,
4329  * returns OK and @time/@offset if found, NONE and/or error otherwise
4330  * If @time == G_MAXINT64, scan for duration ( == last frame) */
4331 static GstFlowReturn
4332 gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time,
4333     gint64 * _offset)
4334 {
4335   GstFlowReturn ret = GST_FLOW_OK;
4336   gint64 lpos, hpos, newpos;
4337   GstClockTime time, ltime, htime, newtime, dur;
4338   gboolean cont = TRUE;
4339   const GstClockTime tolerance = TARGET_DIFFERENCE;
4340   const guint chunk = 4 * 1024;
4341
4342   g_return_val_if_fail (_time != NULL, GST_FLOW_ERROR);
4343   g_return_val_if_fail (_offset != NULL, GST_FLOW_ERROR);
4344
4345   GST_DEBUG_OBJECT (parse, "Bisecting for time %" GST_TIME_FORMAT,
4346       GST_TIME_ARGS (*_time));
4347
4348   /* TODO also make keyframe aware if useful some day */
4349
4350   time = *_time;
4351
4352   /* basic cases */
4353   if (time == 0) {
4354     *_offset = 0;
4355     return GST_FLOW_OK;
4356   }
4357
4358   if (time == -1) {
4359     *_offset = -1;
4360     return GST_FLOW_OK;
4361   }
4362
4363   /* do not know at first */
4364   *_offset = -1;
4365   *_time = GST_CLOCK_TIME_NONE;
4366
4367   /* need initial positions; start and end */
4368   lpos = parse->priv->first_frame_offset;
4369   ltime = parse->priv->first_frame_pts;
4370   /* try other one if no luck */
4371   if (!GST_CLOCK_TIME_IS_VALID (ltime))
4372     ltime = parse->priv->first_frame_dts;
4373   if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &htime)) {
4374     GST_DEBUG_OBJECT (parse, "Unknown time duration, cannot bisect");
4375     return GST_FLOW_ERROR;
4376   }
4377   hpos = parse->priv->upstream_size;
4378
4379   GST_DEBUG_OBJECT (parse,
4380       "Bisection initial bounds: bytes %" G_GINT64_FORMAT " %" G_GINT64_FORMAT
4381       ", times %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, lpos, hpos,
4382       GST_TIME_ARGS (ltime), GST_TIME_ARGS (htime));
4383
4384   /* check preconditions are satisfied;
4385    * start and end are needed, except for special case where we scan for
4386    * last frame to determine duration */
4387   if (parse->priv->pad_mode != GST_PAD_MODE_PULL || !hpos ||
4388       !GST_CLOCK_TIME_IS_VALID (ltime) ||
4389       (!GST_CLOCK_TIME_IS_VALID (htime) && time != G_MAXINT64)) {
4390     return GST_FLOW_OK;
4391   }
4392
4393   /* shortcut cases */
4394   if (time < ltime) {
4395     goto exit;
4396   } else if (time < ltime + tolerance) {
4397     *_offset = lpos;
4398     *_time = ltime;
4399     goto exit;
4400   } else if (time >= htime) {
4401     *_offset = hpos;
4402     *_time = htime;
4403     goto exit;
4404   }
4405
4406   while (htime > ltime && cont) {
4407     GST_LOG_OBJECT (parse,
4408         "lpos: %" G_GUINT64_FORMAT ", ltime: %" GST_TIME_FORMAT, lpos,
4409         GST_TIME_ARGS (ltime));
4410     GST_LOG_OBJECT (parse,
4411         "hpos: %" G_GUINT64_FORMAT ", htime: %" GST_TIME_FORMAT, hpos,
4412         GST_TIME_ARGS (htime));
4413     if (G_UNLIKELY (time == G_MAXINT64)) {
4414       newpos = hpos;
4415     } else if (G_LIKELY (hpos > lpos)) {
4416       newpos =
4417           gst_util_uint64_scale (hpos - lpos, time - ltime, htime - ltime) +
4418           lpos - chunk;
4419     } else {
4420       /* should mean lpos == hpos, since lpos <= hpos is invariant */
4421       newpos = lpos;
4422       /* we check this case once, but not forever, so break loop */
4423       cont = FALSE;
4424     }
4425
4426     /* ensure */
4427     newpos = CLAMP (newpos, lpos, hpos);
4428     GST_LOG_OBJECT (parse,
4429         "estimated _offset for %" GST_TIME_FORMAT ": %" G_GINT64_FORMAT,
4430         GST_TIME_ARGS (time), newpos);
4431
4432     ret = gst_base_parse_find_frame (parse, &newpos, &newtime, &dur);
4433     if (ret == GST_FLOW_EOS) {
4434       /* heuristic HACK */
4435       hpos = MAX (lpos, hpos - chunk);
4436       continue;
4437     } else if (ret != GST_FLOW_OK) {
4438       goto exit;
4439     }
4440
4441     if (newtime == -1 || newpos == -1) {
4442       GST_DEBUG_OBJECT (parse, "subclass did not provide metadata; aborting");
4443       break;
4444     }
4445
4446     if (G_UNLIKELY (time == G_MAXINT64)) {
4447       *_offset = newpos;
4448       *_time = newtime;
4449       if (GST_CLOCK_TIME_IS_VALID (dur))
4450         *_time += dur;
4451       break;
4452     } else if (newtime > time) {
4453       /* overshoot */
4454       hpos = (newpos >= hpos) ? MAX (lpos, hpos - chunk) : MAX (lpos, newpos);
4455       htime = newtime;
4456     } else if (newtime + tolerance > time) {
4457       /* close enough undershoot */
4458       *_offset = newpos;
4459       *_time = newtime;
4460       break;
4461     } else if (newtime < ltime) {
4462       /* so a position beyond lpos resulted in earlier time than ltime ... */
4463       GST_DEBUG_OBJECT (parse, "non-ascending time; aborting");
4464       break;
4465     } else {
4466       /* undershoot too far */
4467       newpos += newpos == lpos ? chunk : 0;
4468       lpos = CLAMP (newpos, lpos, hpos);
4469       ltime = newtime;
4470     }
4471   }
4472
4473 exit:
4474   GST_LOG_OBJECT (parse, "return offset %" G_GINT64_FORMAT ", time %"
4475       GST_TIME_FORMAT, *_offset, GST_TIME_ARGS (*_time));
4476   return ret;
4477 }
4478
4479 static gint64
4480 gst_base_parse_find_offset (GstBaseParse * parse, GstClockTime time,
4481     gboolean before, GstClockTime * _ts)
4482 {
4483   gint64 bytes = 0, ts = 0;
4484   GstIndexEntry *entry = NULL;
4485
4486   if (time == GST_CLOCK_TIME_NONE) {
4487     ts = time;
4488     bytes = -1;
4489     goto exit;
4490   }
4491
4492   GST_BASE_PARSE_INDEX_LOCK (parse);
4493   if (parse->priv->index) {
4494     /* Let's check if we have an index entry for that time */
4495     entry = gst_index_get_assoc_entry (parse->priv->index,
4496         parse->priv->index_id,
4497         before ? GST_INDEX_LOOKUP_BEFORE : GST_INDEX_LOOKUP_AFTER,
4498         GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
4499   }
4500
4501   if (entry) {
4502     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
4503     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &ts);
4504
4505     GST_DEBUG_OBJECT (parse, "found index entry for %" GST_TIME_FORMAT
4506         " at %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT,
4507         GST_TIME_ARGS (time), GST_TIME_ARGS (ts), bytes);
4508   } else {
4509     GST_DEBUG_OBJECT (parse, "no index entry found for %" GST_TIME_FORMAT,
4510         GST_TIME_ARGS (time));
4511     if (!before) {
4512       bytes = -1;
4513       ts = GST_CLOCK_TIME_NONE;
4514     }
4515   }
4516   GST_BASE_PARSE_INDEX_UNLOCK (parse);
4517
4518 exit:
4519   if (_ts)
4520     *_ts = ts;
4521
4522   return bytes;
4523 }
4524
4525 /* returns TRUE if seek succeeded */
4526 static gboolean
4527 gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event)
4528 {
4529   gdouble rate;
4530   GstFormat format;
4531   GstSeekFlags flags;
4532   GstSeekType start_type = GST_SEEK_TYPE_NONE, stop_type;
4533   gboolean flush, update, res = TRUE, accurate;
4534   gint64 start, stop, seekpos, seekstop;
4535   GstSegment seeksegment = { 0, };
4536   GstClockTime start_ts;
4537   guint32 seqnum;
4538   GstEvent *segment_event;
4539
4540   /* try upstream first, unless we're driving the streaming thread ourselves */
4541   if (parse->priv->pad_mode != GST_PAD_MODE_PULL) {
4542     res = gst_pad_push_event (parse->sinkpad, gst_event_ref (event));
4543     if (res)
4544       goto done;
4545   }
4546
4547   gst_event_parse_seek (event, &rate, &format, &flags,
4548       &start_type, &start, &stop_type, &stop);
4549   seqnum = gst_event_get_seqnum (event);
4550
4551   GST_DEBUG_OBJECT (parse, "seek to format %s, rate %f, "
4552       "start type %d at %" GST_TIME_FORMAT ", end type %d at %"
4553       GST_TIME_FORMAT, gst_format_get_name (format), rate,
4554       start_type, GST_TIME_ARGS (start), stop_type, GST_TIME_ARGS (stop));
4555
4556   /* we can only handle TIME, so check if subclass can convert
4557    * to TIME format if it's some other format (such as DEFAULT) */
4558   if (format != GST_FORMAT_TIME) {
4559     if (!gst_base_parse_convert (parse, format, start, GST_FORMAT_TIME, &start)
4560         || !gst_base_parse_convert (parse, format, stop, GST_FORMAT_TIME,
4561             &stop))
4562       goto no_convert_to_time;
4563
4564     GST_INFO_OBJECT (parse, "converted %s format to start time "
4565         "%" GST_TIME_FORMAT " and stop time %" GST_TIME_FORMAT,
4566         gst_format_get_name (format), GST_TIME_ARGS (start),
4567         GST_TIME_ARGS (stop));
4568
4569     format = GST_FORMAT_TIME;
4570   }
4571
4572   /* no negative rates in push mode (unless upstream takes care of that, but
4573    * we've already tried upstream and it didn't handle the seek request) */
4574   if (rate < 0.0 && parse->priv->pad_mode == GST_PAD_MODE_PUSH)
4575     goto negative_rate;
4576
4577   if (start_type != GST_SEEK_TYPE_SET ||
4578       (stop_type != GST_SEEK_TYPE_SET && stop_type != GST_SEEK_TYPE_NONE))
4579     goto wrong_type;
4580
4581   /* get flush flag */
4582   flush = flags & GST_SEEK_FLAG_FLUSH;
4583
4584   /* copy segment, we need this because we still need the old
4585    * segment when we close the current segment. */
4586   gst_segment_copy_into (&parse->segment, &seeksegment);
4587
4588   GST_DEBUG_OBJECT (parse, "configuring seek");
4589   gst_segment_do_seek (&seeksegment, rate, format, flags,
4590       start_type, start, stop_type, stop, &update);
4591
4592   /* accurate seeking implies seek tables are used to obtain position,
4593    * and the requested segment is maintained exactly, not adjusted any way */
4594   accurate = flags & GST_SEEK_FLAG_ACCURATE;
4595
4596   /* maybe we can be accurate for (almost) free */
4597   gst_base_parse_find_offset (parse, seeksegment.position, TRUE, &start_ts);
4598 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
4599   if (parse->priv->accurate_index_seek) {
4600     if (seeksegment.position <= start_ts + TARGET_DIFFERENCE) {
4601       GST_DEBUG_OBJECT (parse, "accurate seek possible");
4602       accurate = TRUE;
4603     }
4604   } else {
4605     GST_DEBUG_OBJECT (parse, "accurate seek NOT possible");
4606     accurate = FALSE;
4607   }
4608 #else
4609   if (seeksegment.position <= start_ts + TARGET_DIFFERENCE) {
4610     GST_DEBUG_OBJECT (parse, "accurate seek possible");
4611     accurate = TRUE;
4612   }
4613 #endif
4614
4615   if (accurate) {
4616     GstClockTime startpos;
4617     if (rate >= 0)
4618       startpos = seeksegment.position;
4619     else
4620       startpos = start;
4621
4622     /* accurate requested, so ... seek a bit before target */
4623     if (startpos < parse->priv->lead_in_ts)
4624       startpos = 0;
4625     else
4626       startpos -= parse->priv->lead_in_ts;
4627
4628     if (seeksegment.stop == -1 && seeksegment.duration != -1)
4629       seeksegment.stop = seeksegment.start + seeksegment.duration;
4630
4631     seekpos = gst_base_parse_find_offset (parse, startpos, TRUE, &start_ts);
4632     seekstop = gst_base_parse_find_offset (parse, seeksegment.stop, FALSE,
4633         NULL);
4634   } else {
4635     if (rate >= 0)
4636       start_ts = seeksegment.position;
4637     else
4638       start_ts = start;
4639
4640     if (seeksegment.stop == -1 && seeksegment.duration != -1)
4641       seeksegment.stop = seeksegment.start + seeksegment.duration;
4642
4643     if (!gst_base_parse_convert (parse, format, start_ts,
4644             GST_FORMAT_BYTES, &seekpos))
4645       goto convert_failed;
4646     if (!gst_base_parse_convert (parse, format, seeksegment.stop,
4647             GST_FORMAT_BYTES, &seekstop))
4648       goto convert_failed;
4649   }
4650
4651   GST_DEBUG_OBJECT (parse,
4652       "seek position %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT,
4653       start_ts, seekpos);
4654   GST_DEBUG_OBJECT (parse,
4655       "seek stop %" G_GINT64_FORMAT " in bytes: %" G_GINT64_FORMAT,
4656       seeksegment.stop, seekstop);
4657
4658   if (parse->priv->pad_mode == GST_PAD_MODE_PULL) {
4659     gint64 last_stop;
4660
4661     GST_DEBUG_OBJECT (parse, "seek in PULL mode");
4662
4663     if (flush) {
4664       if (parse->srcpad) {
4665         GstEvent *fevent = gst_event_new_flush_start ();
4666         GST_DEBUG_OBJECT (parse, "sending flush start");
4667
4668         gst_event_set_seqnum (fevent, seqnum);
4669
4670         gst_pad_push_event (parse->srcpad, gst_event_ref (fevent));
4671         /* unlock upstream pull_range */
4672         gst_pad_push_event (parse->sinkpad, fevent);
4673       }
4674     } else {
4675       gst_pad_pause_task (parse->sinkpad);
4676     }
4677
4678     /* we should now be able to grab the streaming thread because we stopped it
4679      * with the above flush/pause code */
4680     GST_PAD_STREAM_LOCK (parse->sinkpad);
4681
4682     /* save current position */
4683     last_stop = parse->segment.position;
4684     GST_DEBUG_OBJECT (parse, "stopped streaming at %" G_GINT64_FORMAT,
4685         last_stop);
4686
4687     /* now commit to new position */
4688
4689     /* prepare for streaming again */
4690     if (flush) {
4691       GstEvent *fevent = gst_event_new_flush_stop (TRUE);
4692       GST_DEBUG_OBJECT (parse, "sending flush stop");
4693       gst_event_set_seqnum (fevent, seqnum);
4694       gst_pad_push_event (parse->srcpad, gst_event_ref (fevent));
4695       gst_pad_push_event (parse->sinkpad, fevent);
4696       gst_base_parse_clear_queues (parse);
4697     }
4698
4699     memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));
4700
4701     /* store the newsegment event so it can be sent from the streaming thread. */
4702     /* This will be sent later in _loop() */
4703     segment_event = gst_event_new_segment (&parse->segment);
4704     gst_event_set_seqnum (segment_event, seqnum);
4705     parse->priv->pending_events =
4706         g_list_prepend (parse->priv->pending_events, segment_event);
4707
4708     GST_DEBUG_OBJECT (parse, "Created newseg format %d, "
4709         "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
4710         ", time = %" GST_TIME_FORMAT, format,
4711         GST_TIME_ARGS (parse->segment.start),
4712         GST_TIME_ARGS (parse->segment.stop),
4713         GST_TIME_ARGS (parse->segment.time));
4714
4715     /* one last chance in pull mode to stay accurate;
4716      * maybe scan and subclass can find where to go */
4717     if (!accurate) {
4718       gint64 scanpos;
4719       GstClockTime ts = seeksegment.position;
4720
4721       gst_base_parse_locate_time (parse, &ts, &scanpos);
4722       if (scanpos >= 0) {
4723         accurate = TRUE;
4724         seekpos = scanpos;
4725         /* running collected index now consists of several intervals,
4726          * so optimized check no longer possible */
4727         parse->priv->index_last_valid = FALSE;
4728         parse->priv->index_last_offset = 0;
4729         parse->priv->index_last_ts = 0;
4730       }
4731     }
4732
4733     /* mark discont if we are going to stream from another position. */
4734     if (seekpos != parse->priv->offset) {
4735       GST_DEBUG_OBJECT (parse,
4736           "mark DISCONT, we did a seek to another position");
4737       parse->priv->offset = seekpos;
4738       parse->priv->last_offset = seekpos;
4739       parse->priv->seen_keyframe = FALSE;
4740       parse->priv->discont = TRUE;
4741       parse->priv->next_dts = start_ts;
4742       parse->priv->next_pts = GST_CLOCK_TIME_NONE;
4743       parse->priv->last_dts = GST_CLOCK_TIME_NONE;
4744       parse->priv->last_pts = GST_CLOCK_TIME_NONE;
4745       parse->priv->sync_offset = seekpos;
4746       parse->priv->exact_position = accurate;
4747     }
4748
4749     /* Start streaming thread if paused */
4750     gst_pad_start_task (parse->sinkpad,
4751         (GstTaskFunction) gst_base_parse_loop, parse->sinkpad, NULL);
4752
4753     GST_PAD_STREAM_UNLOCK (parse->sinkpad);
4754
4755     /* handled seek */
4756     res = TRUE;
4757   } else {
4758     GstEvent *new_event;
4759     GstBaseParseSeek *seek;
4760     GstSeekFlags flags = (flush ? GST_SEEK_FLAG_FLUSH : GST_SEEK_FLAG_NONE);
4761
4762     /* The only thing we need to do in PUSH-mode is to send the
4763        seek event (in bytes) to upstream. Segment / flush handling happens
4764        in corresponding src event handlers */
4765     GST_DEBUG_OBJECT (parse, "seek in PUSH mode");
4766     if (seekstop >= 0 && seekstop <= seekpos)
4767       seekstop = seekpos;
4768     new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
4769         GST_SEEK_TYPE_SET, seekpos, stop_type, seekstop);
4770     gst_event_set_seqnum (new_event, seqnum);
4771
4772     /* store segment info so its precise details can be reconstructed when
4773      * receiving newsegment;
4774      * this matters for all details when accurate seeking,
4775      * is most useful to preserve NONE stop time otherwise */
4776     seek = g_new0 (GstBaseParseSeek, 1);
4777     seek->segment = seeksegment;
4778     seek->accurate = accurate;
4779     seek->offset = seekpos;
4780     seek->start_ts = start_ts;
4781     GST_OBJECT_LOCK (parse);
4782     /* less optimal, but preserves order */
4783     parse->priv->pending_seeks =
4784         g_slist_append (parse->priv->pending_seeks, seek);
4785     GST_OBJECT_UNLOCK (parse);
4786
4787     res = gst_pad_push_event (parse->sinkpad, new_event);
4788
4789     if (!res) {
4790       GST_OBJECT_LOCK (parse);
4791       parse->priv->pending_seeks =
4792           g_slist_remove (parse->priv->pending_seeks, seek);
4793       GST_OBJECT_UNLOCK (parse);
4794       g_free (seek);
4795     }
4796   }
4797
4798 done:
4799   gst_event_unref (event);
4800   return res;
4801
4802   /* ERRORS */
4803 negative_rate:
4804   {
4805     GST_DEBUG_OBJECT (parse, "negative playback rates delegated upstream.");
4806     res = FALSE;
4807     goto done;
4808   }
4809 wrong_type:
4810   {
4811     GST_DEBUG_OBJECT (parse, "unsupported seek type.");
4812     res = FALSE;
4813     goto done;
4814   }
4815 no_convert_to_time:
4816   {
4817     GST_DEBUG_OBJECT (parse, "seek in %s format was requested, but subclass "
4818         "couldn't convert that into TIME format", gst_format_get_name (format));
4819     res = FALSE;
4820     goto done;
4821   }
4822 convert_failed:
4823   {
4824     GST_DEBUG_OBJECT (parse, "conversion TIME to BYTES failed.");
4825     res = FALSE;
4826     goto done;
4827   }
4828 }
4829
4830 static void
4831 gst_base_parse_set_upstream_tags (GstBaseParse * parse, GstTagList * taglist)
4832 {
4833   if (taglist == parse->priv->upstream_tags)
4834     return;
4835
4836   if (parse->priv->upstream_tags) {
4837     gst_tag_list_unref (parse->priv->upstream_tags);
4838     parse->priv->upstream_tags = NULL;
4839   }
4840
4841   GST_INFO_OBJECT (parse, "upstream tags: %" GST_PTR_FORMAT, taglist);
4842
4843   if (taglist != NULL)
4844     parse->priv->upstream_tags = gst_tag_list_ref (taglist);
4845
4846   gst_base_parse_check_bitrate_tags (parse);
4847 }
4848
4849 #if 0
4850 static void
4851 gst_base_parse_set_index (GstElement * element, GstIndex * index)
4852 {
4853   GstBaseParse *parse = GST_BASE_PARSE (element);
4854
4855   GST_BASE_PARSE_INDEX_LOCK (parse);
4856   if (parse->priv->index)
4857     gst_object_unref (parse->priv->index);
4858   if (index) {
4859     parse->priv->index = gst_object_ref (index);
4860     gst_index_get_writer_id (index, GST_OBJECT_CAST (element),
4861         &parse->priv->index_id);
4862     parse->priv->own_index = FALSE;
4863   } else {
4864     parse->priv->index = NULL;
4865   }
4866   GST_BASE_PARSE_INDEX_UNLOCK (parse);
4867 }
4868
4869 static GstIndex *
4870 gst_base_parse_get_index (GstElement * element)
4871 {
4872   GstBaseParse *parse = GST_BASE_PARSE (element);
4873   GstIndex *result = NULL;
4874
4875   GST_BASE_PARSE_INDEX_LOCK (parse);
4876   if (parse->priv->index)
4877     result = gst_object_ref (parse->priv->index);
4878   GST_BASE_PARSE_INDEX_UNLOCK (parse);
4879
4880   return result;
4881 }
4882 #endif
4883
4884 static GstStateChangeReturn
4885 gst_base_parse_change_state (GstElement * element, GstStateChange transition)
4886 {
4887   GstBaseParse *parse;
4888   GstStateChangeReturn result;
4889
4890   parse = GST_BASE_PARSE (element);
4891
4892   switch (transition) {
4893     case GST_STATE_CHANGE_READY_TO_PAUSED:
4894       /* If this is our own index destroy it as the
4895        * old entries might be wrong for the new stream */
4896       GST_BASE_PARSE_INDEX_LOCK (parse);
4897       if (parse->priv->own_index) {
4898         gst_object_unref (parse->priv->index);
4899         parse->priv->index = NULL;
4900         parse->priv->own_index = FALSE;
4901       }
4902
4903       /* If no index was created, generate one */
4904       if (G_UNLIKELY (!parse->priv->index)) {
4905         GST_DEBUG_OBJECT (parse, "no index provided creating our own");
4906
4907         parse->priv->index = g_object_new (gst_mem_index_get_type (), NULL);
4908         gst_index_get_writer_id (parse->priv->index, GST_OBJECT (parse),
4909             &parse->priv->index_id);
4910         parse->priv->own_index = TRUE;
4911       }
4912       GST_BASE_PARSE_INDEX_UNLOCK (parse);
4913       break;
4914     default:
4915       break;
4916   }
4917
4918   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4919
4920   switch (transition) {
4921     case GST_STATE_CHANGE_PAUSED_TO_READY:
4922       gst_base_parse_reset (parse);
4923       break;
4924     default:
4925       break;
4926   }
4927
4928   return result;
4929 }
4930
4931 /**
4932  * gst_base_parse_set_ts_at_offset:
4933  * @parse: a #GstBaseParse
4934  * @offset: offset into current buffer
4935  *
4936  * This function should only be called from a @handle_frame implementation.
4937  *
4938  * #GstBaseParse creates initial timestamps for frames by using the last
4939  * timestamp seen in the stream before the frame starts.  In certain
4940  * cases, the correct timestamps will occur in the stream after the
4941  * start of the frame, but before the start of the actual picture data.
4942  * This function can be used to set the timestamps based on the offset
4943  * into the frame data that the picture starts.
4944  *
4945  * Since: 1.2
4946  */
4947 void
4948 gst_base_parse_set_ts_at_offset (GstBaseParse * parse, gsize offset)
4949 {
4950   GstClockTime pts, dts;
4951
4952   g_return_if_fail (GST_IS_BASE_PARSE (parse));
4953
4954   pts = gst_adapter_prev_pts_at_offset (parse->priv->adapter, offset, NULL);
4955   dts = gst_adapter_prev_dts_at_offset (parse->priv->adapter, offset, NULL);
4956
4957   if (!GST_CLOCK_TIME_IS_VALID (pts) || !GST_CLOCK_TIME_IS_VALID (dts)) {
4958     GST_DEBUG_OBJECT (parse,
4959         "offset adapter timestamps dts=%" GST_TIME_FORMAT " pts=%"
4960         GST_TIME_FORMAT, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts));
4961   }
4962   if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts))
4963     parse->priv->prev_pts = parse->priv->next_pts = pts;
4964
4965   if (GST_CLOCK_TIME_IS_VALID (dts) && (parse->priv->prev_dts != dts)) {
4966     parse->priv->prev_dts = parse->priv->next_dts = dts;
4967     parse->priv->prev_dts_from_pts = FALSE;
4968   }
4969 }
4970
4971 /**
4972  * gst_base_parse_merge_tags:
4973  * @parse: a #GstBaseParse
4974  * @tags: (allow-none): a #GstTagList to merge, or NULL to unset
4975  *     previously-set tags
4976  * @mode: the #GstTagMergeMode to use, usually #GST_TAG_MERGE_REPLACE
4977  *
4978  * Sets the parser subclass's tags and how they should be merged with any
4979  * upstream stream tags. This will override any tags previously-set
4980  * with gst_base_parse_merge_tags().
4981  *
4982  * Note that this is provided for convenience, and the subclass is
4983  * not required to use this and can still do tag handling on its own.
4984  *
4985  * Since: 1.6
4986  */
4987 void
4988 gst_base_parse_merge_tags (GstBaseParse * parse, GstTagList * tags,
4989     GstTagMergeMode mode)
4990 {
4991   g_return_if_fail (GST_IS_BASE_PARSE (parse));
4992   g_return_if_fail (tags == NULL || GST_IS_TAG_LIST (tags));
4993   g_return_if_fail (tags == NULL || mode != GST_TAG_MERGE_UNDEFINED);
4994
4995   GST_OBJECT_LOCK (parse);
4996
4997   if (tags != parse->priv->parser_tags) {
4998     if (parse->priv->parser_tags) {
4999       gst_tag_list_unref (parse->priv->parser_tags);
5000       parse->priv->parser_tags = NULL;
5001       parse->priv->parser_tags_merge_mode = GST_TAG_MERGE_APPEND;
5002     }
5003     if (tags) {
5004       parse->priv->parser_tags = gst_tag_list_ref (tags);
5005       parse->priv->parser_tags_merge_mode = mode;
5006     }
5007
5008     GST_DEBUG_OBJECT (parse, "setting parser tags to %" GST_PTR_FORMAT
5009         " (mode %d)", tags, parse->priv->parser_tags_merge_mode);
5010
5011     gst_base_parse_check_bitrate_tags (parse);
5012     parse->priv->tags_changed = TRUE;
5013   }
5014
5015   GST_OBJECT_UNLOCK (parse);
5016 }
5017
5018 #ifdef TIZEN_FEATURE_BASEPARSE_MODIFICATION
5019 void
5020 gst_base_parse_get_upstream_size (GstBaseParse * parse,
5021     gint64 * upstream_size)
5022 {
5023   GST_BASE_PARSE_INDEX_LOCK (parse);
5024   *upstream_size = parse->priv->upstream_size;
5025   GST_INFO_OBJECT (parse, "get upstream_size for child parser : (%"G_GUINT64_FORMAT")",
5026     parse->priv->upstream_size);
5027   GST_BASE_PARSE_INDEX_UNLOCK (parse);
5028 }
5029
5030 void
5031 gst_base_parse_get_index_last_offset (GstBaseParse * parse,
5032     gint64 * index_last_offset)
5033 {
5034   GST_BASE_PARSE_INDEX_LOCK (parse);
5035   *index_last_offset = parse->priv->index_last_offset;
5036   GST_INFO_OBJECT (parse, "get index_last_offset for child parser : (%"G_GUINT64_FORMAT")",
5037     parse->priv->index_last_offset);
5038   GST_BASE_PARSE_INDEX_UNLOCK (parse);
5039 }
5040
5041 void
5042 gst_base_parse_get_index_last_ts (GstBaseParse * parse,
5043     GstClockTime * index_last_ts)
5044 {
5045   GST_BASE_PARSE_INDEX_LOCK (parse);
5046   *index_last_ts = parse->priv->index_last_ts;
5047   GST_INFO_OBJECT (parse, "get index_last_ts for child parser : (%"GST_TIME_FORMAT")",
5048     GST_TIME_ARGS(parse->priv->index_last_ts));
5049   GST_BASE_PARSE_INDEX_UNLOCK (parse);
5050 }
5051
5052 void
5053 gst_base_parse_get_pad_mode (GstBaseParse * parse,
5054     GstPadMode * pad_mode)
5055 {
5056   GST_BASE_PARSE_INDEX_LOCK (parse);
5057   *pad_mode = parse->priv->expected_pad_mode;
5058   GST_INFO_OBJECT (parse, "get pad_mode for child parse: mode num (%d)",
5059     parse->priv->expected_pad_mode);
5060   GST_BASE_PARSE_INDEX_UNLOCK (parse);
5061 }
5062 /*
5063  * Checks if accurate seek mode are avilable from sub-parse
5064  */
5065 void
5066 gst_base_parse_set_seek_mode (GstBaseParse * parse, gboolean seek_mode)
5067 {
5068   g_return_if_fail (parse != NULL);
5069   parse->priv->accurate_index_seek = seek_mode;
5070   if (seek_mode)
5071     GST_INFO_OBJECT (parse, "accurate seek mode ON");
5072   else
5073     GST_INFO_OBJECT (parse, "accurate seek mode OFF - for HTTP SEEK");
5074 }
5075 #endif