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