X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libs%2Fgst%2Fbase%2Fgstbaseparse.c;h=99283b8e85a5bfe639ab7e87063b95de459273f0;hb=91798e16cc09420163684d13779f13f374164ea2;hp=ff9c6d2fa1f69dee4afb1f2093134fb5678bf1f8;hpb=2e579a7c1bfd555fbbf5b27142bf16bc93429670;p=platform%2Fupstream%2Fgstreamer.git diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index ff9c6d2..99283b8 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -23,6 +23,7 @@ /** * SECTION:gstbaseparse + * @title: GstBaseParse * @short_description: Base class for stream parsers * @see_also: #GstBaseTransform * @@ -30,109 +31,88 @@ * into separate audio/video/whatever frames. * * It provides for: - * - * provides one sink pad and one source pad - * handles state changes - * can operate in pull mode or push mode - * handles seeking in both modes - * handles events (SEGMENT/EOS/FLUSH) - * - * handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT) - * - * handles flushing - * + * + * * provides one sink pad and one source pad + * * handles state changes + * * can operate in pull mode or push mode + * * handles seeking in both modes + * * handles events (SEGMENT/EOS/FLUSH) + * * handles queries (POSITION/DURATION/SEEKING/FORMAT/CONVERT) + * * handles flushing * * The purpose of this base class is to provide the basic functionality of * a parser and share a lot of rather complex code. * - * Description of the parsing mechanism: - * - * - * Set-up phase - * - * #GstBaseParse calls @start to inform subclass that data processing is - * about to start now. - * - * - * #GstBaseParse class calls @set_sink_caps to inform the subclass about - * incoming sinkpad caps. Subclass could already set the srcpad caps - * accordingly, but this might be delayed until calling - * gst_base_parse_finish_frame() with a non-queued frame. - * - * - * At least at this point subclass needs to tell the #GstBaseParse class - * how big data chunks it wants to receive (min_frame_size). It can do - * this with gst_base_parse_set_min_frame_size(). - * - * - * #GstBaseParse class sets up appropriate data passing mode (pull/push) - * and starts to process the data. - * - * - * - * - * - * Parsing phase - * - * #GstBaseParse gathers at least min_frame_size bytes of data either - * by pulling it from upstream or collecting buffers in an internal - * #GstAdapter. - * - * - * A buffer of (at least) min_frame_size bytes is passed to subclass with - * @handle_frame. Subclass checks the contents and can optionally - * return GST_FLOW_OK along with an amount of data to be skipped to find - * a valid frame (which will result in a subsequent DISCONT). - * If, otherwise, the buffer does not hold a complete frame, - * @handle_frame can merely return and will be called again when additional - * data is available. In push mode this amounts to an - * additional input buffer (thus minimal additional latency), in pull mode - * this amounts to some arbitrary reasonable buffer size increase. - * Of course, gst_base_parse_set_min_frame_size() could also be used if a - * very specific known amount of additional data is required. - * If, however, the buffer holds a complete valid frame, it can pass - * the size of this frame to gst_base_parse_finish_frame(). - * If acting as a converter, it can also merely indicate consumed input data - * while simultaneously providing custom output data. - * Note that baseclass performs some processing (such as tracking - * overall consumed data rate versus duration) for each finished frame, - * but other state is only updated upon each call to @handle_frame - * (such as tracking upstream input timestamp). - * - * Subclass is also responsible for setting the buffer metadata - * (e.g. buffer timestamp and duration, or keyframe if applicable). - * (although the latter can also be done by #GstBaseParse if it is - * appropriately configured, see below). Frame is provided with - * timestamp derived from upstream (as much as generally possible), - * duration obtained from configuration (see below), and offset - * if meaningful (in pull mode). - * - * Note that @check_valid_frame might receive any small - * amount of input data when leftover data is being drained (e.g. at EOS). - * - * - * As part of finish frame processing, - * just prior to actually pushing the buffer in question, - * it is passed to @pre_push_frame which gives subclass yet one - * last chance to examine buffer metadata, or to send some custom (tag) - * events, or to perform custom (segment) filtering. - * - * - * During the parsing process #GstBaseParseClass will handle both srcpad - * and sinkpad events. They will be passed to subclass if @event or - * @src_event callbacks have been provided. - * - * - * - * - * Shutdown phase - * - * #GstBaseParse class calls @stop to inform the subclass that data - * parsing will be stopped. - * - * - * - * + * # Description of the parsing mechanism: + * + * ## Set-up phase + * + * * #GstBaseParse calls @start to inform subclass that data processing is + * about to start now. + * + * * #GstBaseParse class calls @set_sink_caps to inform the subclass about + * incoming sinkpad caps. Subclass could already set the srcpad caps + * accordingly, but this might be delayed until calling + * gst_base_parse_finish_frame() with a non-queued frame. + * + * * At least at this point subclass needs to tell the #GstBaseParse class + * how big data chunks it wants to receive (min_frame_size). It can do + * this with gst_base_parse_set_min_frame_size(). + * + * * #GstBaseParse class sets up appropriate data passing mode (pull/push) + * and starts to process the data. + * + * ## Parsing phase + * + * * #GstBaseParse gathers at least min_frame_size bytes of data either + * by pulling it from upstream or collecting buffers in an internal + * #GstAdapter. + * + * * A buffer of (at least) min_frame_size bytes is passed to subclass with + * @handle_frame. Subclass checks the contents and can optionally + * return GST_FLOW_OK along with an amount of data to be skipped to find + * a valid frame (which will result in a subsequent DISCONT). + * If, otherwise, the buffer does not hold a complete frame, + * @handle_frame can merely return and will be called again when additional + * data is available. In push mode this amounts to an + * additional input buffer (thus minimal additional latency), in pull mode + * this amounts to some arbitrary reasonable buffer size increase. + * Of course, gst_base_parse_set_min_frame_size() could also be used if a + * very specific known amount of additional data is required. + * If, however, the buffer holds a complete valid frame, it can pass + * the size of this frame to gst_base_parse_finish_frame(). + * If acting as a converter, it can also merely indicate consumed input data + * while simultaneously providing custom output data. + * Note that baseclass performs some processing (such as tracking + * overall consumed data rate versus duration) for each finished frame, + * but other state is only updated upon each call to @handle_frame + * (such as tracking upstream input timestamp). + * + * Subclass is also responsible for setting the buffer metadata + * (e.g. buffer timestamp and duration, or keyframe if applicable). + * (although the latter can also be done by #GstBaseParse if it is + * appropriately configured, see below). Frame is provided with + * timestamp derived from upstream (as much as generally possible), + * duration obtained from configuration (see below), and offset + * if meaningful (in pull mode). + * + * Note that @check_valid_frame might receive any small + * amount of input data when leftover data is being drained (e.g. at EOS). + * + * * As part of finish frame processing, + * just prior to actually pushing the buffer in question, + * it is passed to @pre_push_frame which gives subclass yet one + * last chance to examine buffer metadata, or to send some custom (tag) + * events, or to perform custom (segment) filtering. + * + * * During the parsing process #GstBaseParseClass will handle both srcpad + * and sinkpad events. They will be passed to subclass if @event or + * @src_event callbacks have been provided. + * + * ## Shutdown phase + * + * * #GstBaseParse class calls @stop to inform the subclass that data + * parsing will be stopped. * * Subclass is responsible for providing pad template caps for * source and sink pads. The pads need to be named "sink" and "src". It also @@ -151,44 +131,30 @@ * and end of data processing. * * Things that subclass need to take care of: - * - * Provide pad templates - * - * Fixate the source pad caps when appropriate - * - * - * Inform base class how big data chunks should be retrieved. This is - * done with gst_base_parse_set_min_frame_size() function. - * - * - * Examine data chunks passed to subclass with @handle_frame and pass - * proper frame(s) to gst_base_parse_finish_frame(), and setting src pad - * caps and timestamps on frame. - * - * Provide conversion functions - * - * Update the duration information with gst_base_parse_set_duration() - * - * - * Optionally passthrough using gst_base_parse_set_passthrough() - * - * - * Configure various baseparse parameters using - * gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable() - * and gst_base_parse_set_frame_rate(). - * - * - * In particular, if subclass is unable to determine a duration, but - * parsing (or specs) yields a frames per seconds rate, then this can be - * provided to #GstBaseParse to enable it to cater for - * buffer time metadata (which will be taken from upstream as much as - * possible). Internally keeping track of frame durations and respective - * sizes that have been pushed provides #GstBaseParse with an estimated - * bitrate. A default @convert (used if not overridden) will then use these - * rates to perform obvious conversions. These rates are also used to - * update (estimated) duration at regular frame intervals. - * - * + * + * * Provide pad templates + * * Fixate the source pad caps when appropriate + * * Inform base class how big data chunks should be retrieved. This is + * done with gst_base_parse_set_min_frame_size() function. + * * Examine data chunks passed to subclass with @handle_frame and pass + * proper frame(s) to gst_base_parse_finish_frame(), and setting src pad + * caps and timestamps on frame. + * * Provide conversion functions + * * Update the duration information with gst_base_parse_set_duration() + * * Optionally passthrough using gst_base_parse_set_passthrough() + * * Configure various baseparse parameters using + * gst_base_parse_set_average_bitrate(), gst_base_parse_set_syncable() + * and gst_base_parse_set_frame_rate(). + * + * * In particular, if subclass is unable to determine a duration, but + * parsing (or specs) yields a frames per seconds rate, then this can be + * provided to #GstBaseParse to enable it to cater for + * buffer time metadata (which will be taken from upstream as much as + * possible). Internally keeping track of frame durations and respective + * sizes that have been pushed provides #GstBaseParse with an estimated + * bitrate. A default @convert (used if not overridden) will then use these + * rates to perform obvious conversions. These rates are also used to + * update (estimated) duration at regular frame intervals. * */ @@ -689,7 +655,7 @@ gst_base_parse_get_property (GObject * object, guint prop_id, GValue * value, } } -static GstBaseParseFrame * +GstBaseParseFrame * gst_base_parse_frame_copy (GstBaseParseFrame * frame) { GstBaseParseFrame *copy; @@ -1118,7 +1084,8 @@ gst_base_parse_negotiate_default_caps (GstBaseParse * parse) GST_INFO_OBJECT (parse, "Chose default caps %" GST_PTR_FORMAT " for initial gap", default_caps); - gst_caps_unref (sinkcaps); + if (sinkcaps) + gst_caps_unref (sinkcaps); gst_caps_unref (caps); return default_caps; @@ -1829,7 +1796,9 @@ static void gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame) { guint64 data_len, frame_dur; - gint overhead, frame_bitrate; + gint overhead; + guint frame_bitrate; + guint64 frame_bitrate64; GstBuffer *buffer = frame->buffer; overhead = frame->overhead; @@ -1842,11 +1811,17 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame) /* duration should be valid by now, * either set by subclass or maybe based on fps settings */ if (GST_BUFFER_DURATION_IS_VALID (buffer) && parse->priv->acc_duration != 0) { + guint64 avg_bitrate; + /* Calculate duration of a frame from buffer properties */ frame_dur = GST_BUFFER_DURATION (buffer); - parse->priv->avg_bitrate = (8 * parse->priv->data_bytecount * GST_SECOND) / - parse->priv->acc_duration; + avg_bitrate = gst_util_uint64_scale (GST_SECOND, + 8 * parse->priv->data_bytecount, parse->priv->acc_duration); + + if (avg_bitrate > G_MAXUINT) + return; + parse->priv->avg_bitrate = avg_bitrate; } else { /* No way to figure out frame duration (is this even possible?) */ return; @@ -1856,15 +1831,21 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame) if (parse->priv->bitrate) { parse->priv->avg_bitrate = parse->priv->bitrate; /* spread this (confirmed) info ASAP */ - if (parse->priv->posted_avg_bitrate != parse->priv->avg_bitrate) + if (parse->priv->post_avg_bitrate && + parse->priv->posted_avg_bitrate != parse->priv->avg_bitrate) parse->priv->tags_changed = TRUE; } - if (frame_dur) - frame_bitrate = (8 * data_len * GST_SECOND) / frame_dur; - else + if (!frame_dur) return; + frame_bitrate64 = gst_util_uint64_scale (GST_SECOND, 8 * data_len, frame_dur); + + if (frame_bitrate64 > G_MAXUINT) + return; + + frame_bitrate = (guint) frame_bitrate64; + GST_LOG_OBJECT (parse, "frame bitrate %u, avg bitrate %u", frame_bitrate, parse->priv->avg_bitrate); @@ -2783,6 +2764,12 @@ gst_base_parse_send_buffers (GstBaseParse * parse) if (first) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); first = FALSE; + } else { + /* likewise, subsequent buffers should never have DISCONT + * according to the "reverse fragment protocol", or such would + * confuse a downstream decoder + * (could be DISCONT due to aggregating upstream fragments by parsing) */ + GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); } /* iterate output queue an push downstream */ @@ -3265,7 +3252,8 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) ret = old_ret; goto done; } - old_ret = ret; + if (old_ret == GST_FLOW_OK) + old_ret = ret; } done: @@ -3885,7 +3873,11 @@ gst_base_parse_set_frame_rate (GstBaseParse * parse, guint fps_num, gst_util_uint64_scale (GST_SECOND, fps_den * lead_out, fps_num); /* aim for about 1.5s to estimate duration */ if (parse->priv->update_interval < 0) { - parse->priv->update_interval = fps_num * 3 / (fps_den * 2); + guint64 interval = gst_util_uint64_scale (fps_num, 3, + G_GUINT64_CONSTANT (2) * fps_den); + + parse->priv->update_interval = MIN (interval, G_MAXINT); + GST_LOG_OBJECT (parse, "estimated update interval to %d frames", parse->priv->update_interval); } @@ -4130,8 +4122,8 @@ gst_base_parse_src_query_default (GstBaseParse * parse, GstQuery * query) if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &duration) || duration == -1) { /* seekable if we still have a chance to get duration later on */ - seekable = - parse->priv->upstream_seekable && parse->priv->update_interval; + seekable = parse->priv->upstream_seekable && + (parse->priv->update_interval > 0); } else { seekable = parse->priv->upstream_seekable; GST_LOG_OBJECT (parse, "already determine upstream seekabled: %d", @@ -4638,10 +4630,6 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) gst_pad_push_event (parse->srcpad, gst_event_ref (fevent)); gst_pad_push_event (parse->sinkpad, fevent); gst_base_parse_clear_queues (parse); - } else { - /* keep track of our position */ - seeksegment.base = gst_segment_to_running_time (&seeksegment, - seeksegment.format, parse->segment.position); } memcpy (&parse->segment, &seeksegment, sizeof (GstSegment));