X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libs%2Fgst%2Fbase%2Fgstbasesink.c;h=e94a1e2cda25eadbd27bf380a5988c8383043a98;hb=6f295dc2390d850ca321ccf78ddf4392d4c4bce9;hp=d60ba6fdfd6b1560497de9c658ccadd760a1c462;hpb=9f0e066102676bb3ce142b8f70d1609e950e457c;p=platform%2Fupstream%2Fgstreamer.git diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index d60ba6f..e94a1e2 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -36,12 +36,12 @@ * * #GstBaseSink provides support for exactly one sink pad, which should be * named "sink". A sink implementation (subclass of #GstBaseSink) should - * install a pad template in its base_init function, like so: + * install a pad template in its class_init function, like so: * |[ * static void - * my_element_base_init (gpointer g_class) + * my_element_class_init (GstMyElementClass *klass) * { - * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); * * // sinktemplate should be a #GstStaticPadTemplate with direction * // #GST_PAD_SINK and name "sink" @@ -105,10 +105,6 @@ * very specific elements (such as file sinks) which need to handle the * newsegment event specially. * - * #GstBaseSink provides an overridable #GstBaseSinkClass.buffer_alloc() - * function that can be used by sinks that want to do reverse negotiation or to - * provide custom buffers (hardware buffers for example) to upstream elements. - * * The #GstBaseSinkClass.unlock() method is called when the elements should * unblock any blocking operations they perform in the * #GstBaseSinkClass.render() method. This is mostly useful when the @@ -231,6 +227,8 @@ struct _GstBaseSinkPrivate /* if we already commited the state */ gboolean commited; + /* state change to playing ongoing */ + gboolean to_playing; /* when we received EOS */ gboolean received_eos; @@ -266,6 +264,8 @@ struct _GstBaseSinkPrivate /* for throttling and QoS */ GstClockTime earliest_in_time; GstClockTime throttle_time; + + gboolean reset_time; }; #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size)) @@ -364,13 +364,11 @@ static void gst_base_sink_get_property (GObject * object, guint prop_id, static gboolean gst_base_sink_send_event (GstElement * element, GstEvent * event); -static gboolean gst_base_sink_query (GstElement * element, GstQuery * query); +static gboolean default_element_query (GstElement * element, GstQuery * query); static const GstQueryType *gst_base_sink_get_query_types (GstElement * element); -static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink); +static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink, GstCaps * caps); static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps); -static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink, - guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer, GstClockTime * start, GstClockTime * end); static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink, @@ -385,6 +383,7 @@ static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, GstStateChange transition); +static gboolean gst_base_sink_sink_query (GstPad * pad, GstQuery * query); static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, GstBufferList * list); @@ -395,13 +394,11 @@ static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active); static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active); static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event); +static gboolean default_sink_query (GstBaseSink * sink, GstQuery * query); + static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink); -static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad); -static gboolean gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps); +static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad, GstCaps * filter); static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps); -static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad, - guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); - /* check if an object was too late */ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, @@ -505,7 +502,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) * Since: 0.10.15 */ g_object_class_install_property (gobject_class, PROP_LAST_BUFFER, - gst_param_spec_mini_object ("last-buffer", "Last Buffer", + g_param_spec_boxed ("last-buffer", "Last Buffer", "The last buffer received in the sink", GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** @@ -550,22 +547,20 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_base_sink_change_state); gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event); - gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query); + gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query); gstelement_class->get_query_types = GST_DEBUG_FUNCPTR (gst_base_sink_get_query_types); klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps); klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps); - klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc); klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times); klass->activate_pull = GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull); + klass->query = GST_DEBUG_FUNCPTR (default_sink_query); /* Registering debug symbols for function pointers */ GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_getcaps); - GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_setcaps); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_fixate); - GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_buffer_alloc); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_push); GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_pull); @@ -575,7 +570,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) } static GstCaps * -gst_base_sink_pad_getcaps (GstPad * pad) +gst_base_sink_pad_getcaps (GstPad * pad, GstCaps * filter) { GstBaseSinkClass *bclass; GstBaseSink *bsink; @@ -586,14 +581,11 @@ gst_base_sink_pad_getcaps (GstPad * pad) if (bsink->pad_mode == GST_ACTIVATE_PULL) { /* if we are operating in pull mode we only accept the negotiated caps */ - GST_OBJECT_LOCK (pad); - if ((caps = GST_PAD_CAPS (pad))) - gst_caps_ref (caps); - GST_OBJECT_UNLOCK (pad); + caps = gst_pad_get_current_caps (pad); } if (caps == NULL) { if (bclass->get_caps) - caps = bclass->get_caps (bsink); + caps = bclass->get_caps (bsink, filter); if (caps == NULL) { GstPadTemplate *pad_template; @@ -602,7 +594,16 @@ gst_base_sink_pad_getcaps (GstPad * pad) gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); if (pad_template != NULL) { - caps = gst_caps_ref (gst_pad_template_get_caps (pad_template)); + caps = gst_pad_template_get_caps (pad_template); + + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } } } } @@ -611,24 +612,6 @@ gst_base_sink_pad_getcaps (GstPad * pad) return caps; } -static gboolean -gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps) -{ - GstBaseSinkClass *bclass; - GstBaseSink *bsink; - gboolean res = TRUE; - - bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); - bclass = GST_BASE_SINK_GET_CLASS (bsink); - - if (res && bclass->set_caps) - res = bclass->set_caps (bsink, caps); - - gst_object_unref (bsink); - - return res; -} - static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps) { @@ -644,29 +627,6 @@ gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps) gst_object_unref (bsink); } -static GstFlowReturn -gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstBaseSinkClass *bclass; - GstBaseSink *bsink; - GstFlowReturn result = GST_FLOW_OK; - - bsink = GST_BASE_SINK (gst_pad_get_parent (pad)); - if (G_UNLIKELY (bsink == NULL)) - return GST_FLOW_WRONG_STATE; - bclass = GST_BASE_SINK_GET_CLASS (bsink); - - if (bclass->buffer_alloc) - result = bclass->buffer_alloc (bsink, offset, size, caps, buf); - else - *buf = NULL; /* fallback in gstpad.c will allocate generic buffer */ - - gst_object_unref (bsink); - - return result; -} - static void gst_base_sink_init (GstBaseSink * basesink, gpointer g_class) { @@ -682,30 +642,29 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class) basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink"); gst_pad_set_getcaps_function (basesink->sinkpad, gst_base_sink_pad_getcaps); - gst_pad_set_setcaps_function (basesink->sinkpad, gst_base_sink_pad_setcaps); gst_pad_set_fixatecaps_function (basesink->sinkpad, gst_base_sink_pad_fixate); - gst_pad_set_bufferalloc_function (basesink->sinkpad, - gst_base_sink_pad_buffer_alloc); gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate); gst_pad_set_activatepush_function (basesink->sinkpad, gst_base_sink_pad_activate_push); gst_pad_set_activatepull_function (basesink->sinkpad, gst_base_sink_pad_activate_pull); + gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query); gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event); gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain); gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list); gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad); basesink->pad_mode = GST_ACTIVATE_NONE; + basesink->preroll_lock = g_mutex_new (); + basesink->preroll_cond = g_cond_new (); basesink->preroll_queue = g_queue_new (); - basesink->abidata.ABI.clip_segment = gst_segment_new (); priv->have_latency = FALSE; basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH; basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL; basesink->sync = DEFAULT_SYNC; - basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS; + basesink->max_lateness = DEFAULT_MAX_LATENESS; g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS); priv->async_enabled = DEFAULT_ASYNC; priv->ts_offset = DEFAULT_TS_OFFSET; @@ -725,8 +684,9 @@ gst_base_sink_finalize (GObject * object) basesink = GST_BASE_SINK (object); + g_mutex_free (basesink->preroll_lock); + g_cond_free (basesink->preroll_cond); g_queue_free (basesink->preroll_queue); - gst_segment_free (basesink->abidata.ABI.clip_segment); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -797,7 +757,7 @@ gst_base_sink_set_max_lateness (GstBaseSink * sink, gint64 max_lateness) g_return_if_fail (GST_IS_BASE_SINK (sink)); GST_OBJECT_LOCK (sink); - sink->abidata.ABI.max_lateness = max_lateness; + sink->max_lateness = max_lateness; GST_OBJECT_UNLOCK (sink); } @@ -822,7 +782,7 @@ gst_base_sink_get_max_lateness (GstBaseSink * sink) g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1); GST_OBJECT_LOCK (sink); - res = sink->abidata.ABI.max_lateness; + res = sink->max_lateness; GST_OBJECT_UNLOCK (sink); return res; @@ -885,10 +845,10 @@ gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled) { g_return_if_fail (GST_IS_BASE_SINK (sink)); - GST_PAD_PREROLL_LOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (sink); g_atomic_int_set (&sink->priv->async_enabled, enabled); GST_LOG_OBJECT (sink, "set async enabled to %d", enabled); - GST_PAD_PREROLL_UNLOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (sink); } /** @@ -1364,9 +1324,9 @@ gst_base_sink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_PREROLL_QUEUE_LEN: /* preroll lock necessary to serialize with finish_preroll */ - GST_PAD_PREROLL_LOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (sink); g_atomic_int_set (&sink->preroll_queue_max_len, g_value_get_uint (value)); - GST_PAD_PREROLL_UNLOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (sink); break; case PROP_SYNC: gst_base_sink_set_sync (sink, g_value_get_boolean (value)); @@ -1449,7 +1409,7 @@ gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value, static GstCaps * -gst_base_sink_get_caps (GstBaseSink * sink) +gst_base_sink_get_caps (GstBaseSink * sink, GstCaps * filter) { return NULL; } @@ -1460,14 +1420,6 @@ gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps) return TRUE; } -static GstFlowReturn -gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - *buf = NULL; - return GST_FLOW_OK; -} - /* with PREROLL_LOCK, STREAM_LOCK */ static void gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad) @@ -1495,7 +1447,7 @@ gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad) GST_OBJECT_UNLOCK (basesink); } /* and signal any waiters now */ - GST_PAD_PREROLL_SIGNAL (pad); + GST_BASE_SINK_PREROLL_SIGNAL (basesink); } /* with STREAM_LOCK, configures given segment with the event information. */ @@ -1503,43 +1455,15 @@ static void gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad, GstEvent * event, GstSegment * segment) { - gboolean update; - gdouble rate, arate; - GstFormat format; - gint64 start; - gint64 stop; - gint64 time; - - /* the newsegment event is needed to bring the buffer timestamps to the - * stream time and to drop samples outside of the playback segment. */ - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - /* The segment is protected with both the STREAM_LOCK and the OBJECT_LOCK. * We protect with the OBJECT_LOCK so that we can use the values to * safely answer a POSITION query. */ GST_OBJECT_LOCK (basesink); - gst_segment_set_newsegment_full (segment, update, rate, arate, format, start, - stop, time); - - if (format == GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (basesink, - "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, " - "format GST_FORMAT_TIME, " - "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT - ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - update, rate, arate, GST_TIME_ARGS (segment->start), - GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time), - GST_TIME_ARGS (segment->accum)); - } else { - GST_DEBUG_OBJECT (basesink, - "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, " - "format %d, " - "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" - G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate, - segment->format, segment->start, segment->stop, segment->time, - segment->accum); - } + /* the newsegment event is needed to bring the buffer timestamps to the + * stream time and to drop samples outside of the playback segment. */ + gst_event_copy_segment (event, segment); + GST_DEBUG_OBJECT (basesink, "configured SEGMENT %" GST_SEGMENT_FORMAT, + segment); GST_OBJECT_UNLOCK (basesink); } @@ -1552,6 +1476,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink) gboolean post_paused = FALSE; gboolean post_async_done = FALSE; gboolean post_playing = FALSE; + gboolean reset_time; /* we are certainly not playing async anymore now */ basesink->playing_async = FALSE; @@ -1561,15 +1486,12 @@ gst_base_sink_commit_state (GstBaseSink * basesink) next = GST_STATE_NEXT (basesink); pending = GST_STATE_PENDING (basesink); post_pending = pending; + reset_time = basesink->priv->reset_time; + basesink->priv->reset_time = FALSE; switch (pending) { case GST_STATE_PLAYING: { - GstBaseSinkClass *bclass; - GstStateChangeReturn ret; - - bclass = GST_BASE_SINK_GET_CLASS (basesink); - GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING"); basesink->need_preroll = FALSE; @@ -1580,14 +1502,6 @@ gst_base_sink_commit_state (GstBaseSink * basesink) if (current == GST_STATE_READY) { post_paused = TRUE; } - - /* make sure we notify the subclass of async playing */ - if (bclass->async_play) { - GST_WARNING_OBJECT (basesink, "deprecated async_play"); - ret = bclass->async_play (basesink); - if (ret == GST_STATE_CHANGE_FAILURE) - goto async_failed; - } break; } case GST_STATE_PAUSED: @@ -1624,7 +1538,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink) if (post_async_done) { GST_DEBUG_OBJECT (basesink, "posting async-done message"); gst_element_post_message (GST_ELEMENT_CAST (basesink), - gst_message_new_async_done (GST_OBJECT_CAST (basesink))); + gst_message_new_async_done (GST_OBJECT_CAST (basesink), reset_time)); } if (post_playing) { GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message"); @@ -1672,13 +1586,6 @@ stopping: GST_OBJECT_UNLOCK (basesink); return FALSE; } -async_failed: - { - GST_DEBUG_OBJECT (basesink, "async commit failed"); - GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_FAILURE; - GST_OBJECT_UNLOCK (basesink); - return FALSE; - } } static void @@ -1709,7 +1616,6 @@ start_stepping (GstBaseSink * sink, GstSegment * segment, /* set the new rate for the remainder of the segment */ current->start_rate = segment->rate; segment->rate *= current->rate; - segment->abs_rate = ABS (segment->rate); /* save values */ if (segment->rate > 0.0) @@ -1723,27 +1629,19 @@ start_stepping (GstBaseSink * sink, GstSegment * segment, /* update the segment clipping regions for non-flushing seeks */ if (segment->rate > 0.0) { segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end); - segment->last_stop = segment->stop; + segment->position = segment->stop; } else { gint64 position; position = gst_segment_to_position (segment, GST_FORMAT_TIME, end); segment->time = position; segment->start = position; - segment->last_stop = position; + segment->position = position; } } } - GST_DEBUG_OBJECT (sink, - "segment now rate %lf, applied rate %lf, " - "format GST_FORMAT_TIME, " - "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT - ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT, - segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start), - GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time), - GST_TIME_ARGS (segment->accum)); - + GST_DEBUG_OBJECT (sink, "segment now %" GST_SEGMENT_FORMAT, segment); GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (current->start)); @@ -1788,8 +1686,8 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment, gst_segment_set_running_time (segment, GST_FORMAT_TIME, position); if (current->flush) { - /* and remove the accumulated time we flushed, start time did not change */ - segment->accum = current->start; + /* and remove the time we flushed, start time did not change */ + segment->base = current->start; } else { /* start time is now the stepped position */ gst_element_set_start_time (GST_ELEMENT_CAST (sink), position); @@ -1797,7 +1695,6 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment, /* restore the previous rate */ segment->rate = current->start_rate; - segment->abs_rate = ABS (segment->rate); if (segment->rate > 0.0) segment->stop = current->start_stop; @@ -1805,7 +1702,7 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment, segment->start = current->start_start; /* the clip segment is used for position report in paused... */ - memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment)); + gst_segment_copy_into (segment, &sink->clip_segment); /* post the step done when we know the stepped duration in TIME */ message = @@ -1824,8 +1721,8 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment, static gboolean handle_stepping (GstBaseSink * sink, GstSegment * segment, - GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart, - gint64 * rstop) + GstStepInfo * current, guint64 * cstart, guint64 * cstop, guint64 * rstart, + guint64 * rstop) { gboolean step_end = FALSE; @@ -1834,7 +1731,8 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment, case GST_FORMAT_TIME: { guint64 end; - gint64 first, last; + guint64 first, last; + gdouble abs_rate; if (segment->rate > 0.0) { if (segment->stop == *cstop) @@ -1853,8 +1751,9 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment, end = current->start + current->amount; current->position = first - current->start; - if (G_UNLIKELY (segment->abs_rate != 1.0)) - current->position /= segment->abs_rate; + abs_rate = ABS (segment->rate); + if (G_UNLIKELY (abs_rate != 1.0)) + current->position /= abs_rate; GST_DEBUG_OBJECT (sink, "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, @@ -1924,8 +1823,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, GstBaseSinkClass *bclass; GstBuffer *buffer; GstClockTime start, stop; /* raw start/stop timestamps */ - gint64 cstart, cstop; /* clipped raw timestamps */ - gint64 rstart, rstop; /* clipped timestamps converted to running time */ + guint64 cstart, cstop; /* clipped raw timestamps */ + guint64 rstart, rstop; /* clipped timestamps converted to running time */ GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */ GstFormat format; GstBaseSinkPrivate *priv; @@ -1970,11 +1869,6 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj, } default: /* other events do not need syncing */ - /* FIXME, maybe NEWSEGMENT might need synchronisation - * since the POSITION query depends on accumulated times and - * we cannot accumulate the current segment before the previous - * one completed. - */ return FALSE; } } @@ -2008,19 +1902,9 @@ again: /* collect segment and format for code clarity */ format = segment->format; - /* no timestamp clipping if we did not get a TIME segment format */ - if (G_UNLIKELY (format != GST_FORMAT_TIME)) { - cstart = start; - cstop = stop; - /* do running and stream time in TIME format */ - format = GST_FORMAT_TIME; - GST_LOG_OBJECT (basesink, "not time format, don't clip"); - goto do_times; - } - - /* clip, only when we know about time */ - if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME, - (gint64) start, (gint64) stop, &cstart, &cstop))) { + /* clip */ + if (G_UNLIKELY (!gst_segment_clip (segment, format, + start, stop, &cstart, &cstop))) { if (step->valid) { GST_DEBUG_OBJECT (basesink, "step out of segment"); /* when we are stepping, pretend we're at the end of the segment */ @@ -2044,9 +1928,9 @@ again: /* set last stop position */ if (G_LIKELY (stop != GST_CLOCK_TIME_NONE && cstop != GST_CLOCK_TIME_NONE)) - gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop); + segment->position = cstop; else - gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart); + segment->position = cstart; do_times: rstart = gst_segment_to_running_time (segment, format, cstart); @@ -2189,8 +2073,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, /* FIXME: Casting to GstClockEntry only works because the types * are the same */ if (G_LIKELY (sink->priv->cached_clock_id != NULL - && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink-> - priv->cached_clock_id) == clock)) { + && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv-> + cached_clock_id) == clock)) { if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, time)) { gst_clock_id_unref (sink->priv->cached_clock_id); @@ -2209,11 +2093,11 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, * entry. */ sink->clock_id = sink->priv->cached_clock_id; /* release the preroll lock while waiting */ - GST_PAD_PREROLL_UNLOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (sink); ret = gst_clock_id_wait (sink->priv->cached_clock_id, jitter); - GST_PAD_PREROLL_LOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (sink); sink->clock_id = NULL; return ret; @@ -2265,7 +2149,7 @@ gst_base_sink_wait_preroll (GstBaseSink * sink) sink->have_preroll = TRUE; GST_DEBUG_OBJECT (sink, "waiting in preroll for flush or PLAYING"); /* block until the state changes, or we get a flush, or something */ - GST_PAD_PREROLL_WAIT (sink->sinkpad); + GST_BASE_SINK_PREROLL_WAIT (sink); sink->have_preroll = FALSE; if (G_UNLIKELY (sink->flushing)) goto stopping; @@ -2641,7 +2525,7 @@ gst_base_sink_send_qos (GstBaseSink * basesink, GstQOSType type, "qos: type %d, proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %" GST_TIME_FORMAT, type, proportion, diff, GST_TIME_ARGS (time)); - event = gst_event_new_qos_full (type, proportion, diff, time); + event = gst_event_new_qos (type, proportion, diff, time); /* send upstream */ res = gst_pad_push_event (basesink->sinkpad, event); @@ -2822,7 +2706,7 @@ gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj, GstClockReturn status, GstClockTimeDiff jitter) { gboolean late; - gint64 max_lateness; + guint64 max_lateness; GstBaseSinkPrivate *priv; priv = basesink->priv; @@ -2833,7 +2717,7 @@ gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj, if (G_LIKELY (status != GST_CLOCK_EARLY)) goto in_time; - max_lateness = basesink->abidata.ABI.max_lateness; + max_lateness = basesink->max_lateness; /* check if frame dropping is enabled */ if (max_lateness == -1) @@ -2961,7 +2845,7 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad, * If buffer list, use the first group buffer within the list * for syncing */ - sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); + sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0); g_assert (NULL != sync_obj); } else { sync_obj = obj; @@ -3076,12 +2960,24 @@ again: gst_element_post_message (GST_ELEMENT_CAST (basesink), message); break; } - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: /* configure the segment */ gst_base_sink_configure_segment (basesink, pad, event, &basesink->segment); break; - case GST_EVENT_SINK_MESSAGE:{ + case GST_EVENT_TAG: + { + GstTagList *taglist; + + gst_event_parse_tag (event, &taglist); + + gst_element_post_message (GST_ELEMENT_CAST (basesink), + gst_message_new_tag (GST_OBJECT_CAST (basesink), + gst_tag_list_copy (taglist))); + break; + } + case GST_EVENT_SINK_MESSAGE: + { GstMessage *msg = NULL; gst_event_parse_sink_message (event, &msg); @@ -3182,7 +3078,7 @@ gst_base_sink_preroll_object (GstBaseSink * basesink, guint8 obj_type, GstClockTime timestamp; if (OBJ_IS_BUFFERLIST (obj_type)) { - buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); + buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0); g_assert (NULL != buf); } else { buf = GST_BUFFER_CAST (obj); @@ -3335,7 +3231,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad, { GstFlowReturn ret; - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); if (G_UNLIKELY (basesink->flushing)) goto flushing; @@ -3345,7 +3241,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad, ret = gst_base_sink_queue_object_unlocked (basesink, pad, _PR_IS_EVENT, obj, prerollable); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); return ret; @@ -3353,7 +3249,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad, flushing: { GST_DEBUG_OBJECT (basesink, "sink is flushing"); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); gst_mini_object_unref (obj); return GST_FLOW_WRONG_STATE; } @@ -3361,7 +3257,7 @@ was_eos: { GST_DEBUG_OBJECT (basesink, "we are EOS, dropping object, return UNEXPECTED"); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); gst_mini_object_unref (obj); return GST_FLOW_UNEXPECTED; } @@ -3385,6 +3281,9 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad) if (basesink->priv->async_enabled) { gst_element_lost_state (GST_ELEMENT_CAST (basesink)); } else { + /* start time reset in above case as well; + * arranges for a.o. proper position reporting when flushing in PAUSED */ + gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0); basesink->priv->have_latency = TRUE; } gst_base_sink_set_last_buffer (basesink, NULL); @@ -3392,7 +3291,8 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad) } static void -gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad) +gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad, + gboolean reset_time) { /* unset flushing so we can accept new data, this also flushes out any EOS * event. */ @@ -3409,9 +3309,12 @@ gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad) if (basesink->pad_mode == GST_ACTIVATE_PUSH) { /* we need new segment info after the flush. */ basesink->have_newsegment = FALSE; - gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); - gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED); + if (reset_time) { + gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); + gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED); + } } + basesink->priv->reset_time = reset_time; GST_OBJECT_UNLOCK (basesink); } @@ -3438,66 +3341,70 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) { GstFlowReturn ret; - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); if (G_UNLIKELY (basesink->flushing)) goto flushing; - if (G_UNLIKELY (basesink->priv->received_eos)) { - /* we can't accept anything when we are EOS */ + if (G_UNLIKELY (basesink->priv->received_eos)) + goto after_eos; + + /* we set the received EOS flag here so that we can use it when testing if + * we are prerolled and to refuse more buffers. */ + basesink->priv->received_eos = TRUE; + + /* EOS is a prerollable object, we call the unlocked version because it + * does not check the received_eos flag. */ + ret = gst_base_sink_queue_object_unlocked (basesink, pad, + _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE); + if (G_UNLIKELY (ret != GST_FLOW_OK)) result = FALSE; - gst_event_unref (event); - } else { - /* we set the received EOS flag here so that we can use it when testing if - * we are prerolled and to refuse more buffers. */ - basesink->priv->received_eos = TRUE; - - /* EOS is a prerollable object, we call the unlocked version because it - * does not check the received_eos flag. */ - ret = gst_base_sink_queue_object_unlocked (basesink, pad, - _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - result = FALSE; - } - GST_PAD_PREROLL_UNLOCK (pad); + + GST_BASE_SINK_PREROLL_UNLOCK (basesink); + break; + } + case GST_EVENT_CAPS: + { + GstCaps *caps; + + GST_DEBUG_OBJECT (basesink, "caps %p", event); + + gst_event_parse_caps (event, &caps); + if (bclass->set_caps) + result = bclass->set_caps (basesink, caps); + + gst_event_unref (event); break; } - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: { GstFlowReturn ret; - gboolean update; - GST_DEBUG_OBJECT (basesink, "newsegment %p", event); + GST_DEBUG_OBJECT (basesink, "segment %p", event); - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); if (G_UNLIKELY (basesink->flushing)) goto flushing; - gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL, NULL, - NULL, NULL); + if (G_UNLIKELY (basesink->priv->received_eos)) + goto after_eos; + + /* the new segment is a non prerollable item and does not block anything, + * we need to configure the current clipping segment and insert the event + * in the queue to serialize it with the buffers for rendering. */ + gst_base_sink_configure_segment (basesink, pad, event, + &basesink->clip_segment); - if (G_UNLIKELY (basesink->priv->received_eos && !update)) { - /* we can't accept anything when we are EOS */ + ret = + gst_base_sink_queue_object_unlocked (basesink, pad, + _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE); + if (G_UNLIKELY (ret != GST_FLOW_OK)) result = FALSE; - gst_event_unref (event); - } else { - /* the new segment is a non prerollable item and does not block anything, - * we need to configure the current clipping segment and insert the event - * in the queue to serialize it with the buffers for rendering. */ - gst_base_sink_configure_segment (basesink, pad, event, - basesink->abidata.ABI.clip_segment); - - ret = - gst_base_sink_queue_object_unlocked (basesink, pad, - _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - result = FALSE; - else { - GST_OBJECT_LOCK (basesink); - basesink->have_newsegment = TRUE; - GST_OBJECT_UNLOCK (basesink); - } + else { + GST_OBJECT_LOCK (basesink); + basesink->have_newsegment = TRUE; + GST_OBJECT_UNLOCK (basesink); } - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); break; } case GST_EVENT_FLUSH_START: @@ -3511,15 +3418,21 @@ gst_base_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); break; case GST_EVENT_FLUSH_STOP: + { + gboolean reset_time; + if (bclass->event) bclass->event (basesink, event); - GST_DEBUG_OBJECT (basesink, "flush-stop %p", event); + gst_event_parse_flush_stop (event, &reset_time); + GST_DEBUG_OBJECT (basesink, "flush-stop %p, reset_time: %d", event, + reset_time); - gst_base_sink_flush_stop (basesink, pad); + gst_base_sink_flush_stop (basesink, pad, reset_time); gst_event_unref (event); break; + } default: /* other events are sent to queue or subclass depending on if they * are serialized. */ @@ -3542,7 +3455,16 @@ done: flushing: { GST_DEBUG_OBJECT (basesink, "we are flushing"); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); + result = FALSE; + gst_event_unref (event); + goto done; + } + +after_eos: + { + GST_DEBUG_OBJECT (basesink, "Event received after EOS, dropping"); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); result = FALSE; gst_event_unref (event); goto done; @@ -3614,14 +3536,14 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, goto was_eos; if (OBJ_IS_BUFFERLIST (obj_type)) { - time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0); + time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0); g_assert (NULL != time_buf); } else { time_buf = GST_BUFFER_CAST (obj); } /* for code clarity */ - clip_segment = basesink->abidata.ABI.clip_segment; + clip_segment = &basesink->clip_segment; if (G_UNLIKELY (!basesink->have_newsegment)) { gboolean sync; @@ -3663,7 +3585,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, if (GST_CLOCK_TIME_IS_VALID (start) && (clip_segment->format == GST_FORMAT_TIME)) { if (G_UNLIKELY (!gst_segment_clip (clip_segment, - GST_FORMAT_TIME, (gint64) start, (gint64) end, NULL, NULL))) + GST_FORMAT_TIME, start, end, NULL, NULL))) goto out_of_segment; } @@ -3706,9 +3628,9 @@ gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) goto wrong_mode; - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); result = gst_base_sink_chain_unlocked (basesink, pad, obj_type, obj); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); done: return result; @@ -3752,32 +3674,21 @@ gst_base_sink_chain_list (GstPad * pad, GstBufferList * list) if (G_LIKELY (bclass->render_list)) { result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFERLIST, list); } else { - GstBufferListIterator *it; - GstBuffer *group; + guint i, len; + GstBuffer *buffer; GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer"); - it = gst_buffer_list_iterate (list); + len = gst_buffer_list_len (list); - if (gst_buffer_list_iterator_next_group (it)) { - do { - group = gst_buffer_list_iterator_merge_group (it); - if (group == NULL) { - group = gst_buffer_new (); - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group"); - } - result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, group); - } while (result == GST_FLOW_OK - && gst_buffer_list_iterator_next_group (it)); - } else { - GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group"); - result = - gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, - gst_buffer_new ()); + result = GST_FLOW_OK; + for (i = 0; i < len; i++) { + buffer = gst_buffer_list_get (list, 0); + result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, + gst_buffer_ref (buffer)); + if (result != GST_FLOW_OK) + break; } - gst_buffer_list_iterator_free (it); gst_buffer_list_unref (list); } return result; @@ -3819,17 +3730,16 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, GstSeekType cur_type, stop_type; gint64 cur, stop; GstSeekFlags flags; - GstFormat seek_format, dest_format; + GstFormat seek_format; gdouble rate; gboolean update; gboolean res = TRUE; gst_event_parse_seek (event, &rate, &seek_format, &flags, &cur_type, &cur, &stop_type, &stop); - dest_format = segment->format; - if (seek_format == dest_format) { - gst_segment_set_seek (segment, rate, seek_format, flags, + if (seek_format == segment->format) { + gst_segment_do_seek (segment, rate, seek_format, flags, cur_type, cur, stop_type, stop, &update); return TRUE; } @@ -3837,7 +3747,7 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, if (cur_type != GST_SEEK_TYPE_NONE) { /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */ res = - gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format, + gst_pad_query_convert (sink->sinkpad, seek_format, cur, segment->format, &cur); cur_type = GST_SEEK_TYPE_SET; } @@ -3845,13 +3755,13 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink, if (res && stop_type != GST_SEEK_TYPE_NONE) { /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */ res = - gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format, - &stop); + gst_pad_query_convert (sink->sinkpad, seek_format, stop, + segment->format, &stop); stop_type = GST_SEEK_TYPE_SET; } /* And finally, configure our output segment in the desired format */ - gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur, + gst_segment_do_seek (segment, rate, segment->format, flags, cur_type, cur, stop_type, stop, &update); if (!res) @@ -3924,7 +3834,7 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event) } else { /* The seek format matches our processing format, no need to ask the * the subclass to configure the segment. */ - gst_segment_set_seek (&seeksegment, rate, seek_format, flags, + gst_segment_do_seek (&seeksegment, rate, seek_format, flags, cur_type, cur, stop_type, stop, &update); } } @@ -3935,22 +3845,22 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event) if (res) { GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT, - seeksegment.start, seeksegment.stop, seeksegment.last_stop); + seeksegment.start, seeksegment.stop, seeksegment.position); - /* do the seek, segment.last_stop contains the new position. */ + /* do the seek, segment.position contains the new position. */ res = gst_base_sink_default_do_seek (sink, &seeksegment); } if (flush) { GST_DEBUG_OBJECT (sink, "stop flushing upstream"); - gst_pad_push_event (pad, gst_event_new_flush_stop ()); - gst_base_sink_flush_stop (sink, pad); - } else if (res && sink->abidata.ABI.running) { + gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE)); + gst_base_sink_flush_stop (sink, pad, TRUE); + } else if (res && sink->running) { /* we are running the current segment and doing a non-flushing seek, - * close the segment first based on the last_stop. */ + * close the segment first based on the position. */ GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop); + " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.position); } /* The subclass must have converted the segment to the processing format @@ -3964,17 +3874,17 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event) /* if successfull seek, we update our real segment and push * out the new segment. */ if (res) { - memcpy (&sink->segment, &seeksegment, sizeof (GstSegment)); + gst_segment_copy_into (&seeksegment, &sink->segment); if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (sink), gst_message_new_segment_start (GST_OBJECT (sink), - sink->segment.format, sink->segment.last_stop)); + sink->segment.format, sink->segment.position)); } } sink->priv->discont = TRUE; - sink->abidata.ABI.running = TRUE; + sink->running = TRUE; GST_PAD_STREAM_UNLOCK (pad); @@ -4037,7 +3947,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) if (bclass->unlock) bclass->unlock (sink); - GST_PAD_PREROLL_LOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (sink); /* now that we have the PREROLL lock, clear our unlock request */ if (bclass->unlock_stop) bclass->unlock_stop (sink); @@ -4052,7 +3962,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) sink->playing_async = TRUE; priv->pending_step.need_preroll = TRUE; sink->need_preroll = FALSE; - gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE); + gst_element_lost_state (GST_ELEMENT_CAST (sink)); } else { sink->priv->have_latency = TRUE; sink->need_preroll = FALSE; @@ -4071,9 +3981,9 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) if (sink->have_preroll) { GST_DEBUG_OBJECT (sink, "signal waiter"); priv->step_unlock = TRUE; - GST_PAD_PREROLL_SIGNAL (sink->sinkpad); + GST_BASE_SINK_PREROLL_SIGNAL (sink); } - GST_PAD_PREROLL_UNLOCK (sink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (sink); } else { /* update the stepinfo and make it valid */ set_step_info (sink, current, pending, seqnum, format, amount, rate, flush, @@ -4101,7 +4011,7 @@ gst_base_sink_loop (GstPad * pad) if ((blocksize = basesink->priv->blocksize) == 0) blocksize = -1; - offset = basesink->segment.last_stop; + offset = basesink->segment.position; GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u", offset, blocksize); @@ -4113,13 +4023,13 @@ gst_base_sink_loop (GstPad * pad) if (G_UNLIKELY (buf == NULL)) goto no_buffer; - offset += GST_BUFFER_SIZE (buf); + offset += gst_buffer_get_size (buf); - gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset); + basesink->segment.position = offset; - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); result = gst_base_sink_chain_unlocked (basesink, pad, _PR_IS_BUFFER, buf); - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); if (G_UNLIKELY (result != GST_FLOW_OK)) goto paused; @@ -4136,7 +4046,7 @@ paused: if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT_CAST (basesink), gst_message_new_segment_done (GST_OBJECT_CAST (basesink), - basesink->segment.format, basesink->segment.last_stop)); + basesink->segment.format, basesink->segment.position)); } else { gst_base_sink_event (pad, gst_event_new_eos ()); } @@ -4179,7 +4089,7 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, bclass->unlock (basesink); } - GST_PAD_PREROLL_LOCK (pad); + GST_BASE_SINK_PREROLL_LOCK (basesink); basesink->flushing = flushing; if (flushing) { /* step 1, now that we have the PREROLL lock, clear our unlock request */ @@ -4201,7 +4111,7 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad, "flushing out data thread, need preroll to TRUE"); gst_base_sink_preroll_queue_flush (basesink, pad); } - GST_PAD_PREROLL_UNLOCK (pad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); return TRUE; } @@ -4228,6 +4138,8 @@ gst_base_sink_pad_activate (GstPad * pad) { gboolean result = FALSE; GstBaseSink *basesink; + GstQuery *query; + gboolean pull_mode; basesink = GST_BASE_SINK (gst_pad_get_parent (pad)); @@ -4242,7 +4154,19 @@ gst_base_sink_pad_activate (GstPad * pad) } /* check if downstreams supports pull mode at all */ - if (!gst_pad_check_pull_range (pad)) { + query = gst_query_new_scheduling (); + + if (!gst_pad_peer_query (pad, query)) { + gst_query_unref (query); + GST_DEBUG_OBJECT (basesink, "peer query faild, no pull mode"); + goto fallback; + } + + /* parse result of the query */ + gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL); + gst_query_unref (query); + + if (!pull_mode) { GST_DEBUG_OBJECT (basesink, "pull mode not supported"); goto fallback; } @@ -4343,10 +4267,8 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink) caps = gst_caps_make_writable (caps); /* get the first (prefered) format */ gst_caps_truncate (caps); - /* try to fixate */ - gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps); - GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (basesink, "have caps: %" GST_PTR_FORMAT, caps); if (gst_caps_is_any (caps)) { GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, " @@ -4354,15 +4276,22 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink) /* neither side has template caps in this case, so they are prepared for pull() without setcaps() */ result = TRUE; - } else if (gst_caps_is_fixed (caps)) { - if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps)) - goto could_not_set_caps; + } else { + /* try to fixate */ + gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps); + GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps); - GST_OBJECT_LOCK (basesink); - gst_caps_replace (&basesink->priv->pull_caps, caps); - GST_OBJECT_UNLOCK (basesink); + if (gst_caps_is_fixed (caps)) { + if (!gst_pad_send_event (GST_BASE_SINK_PAD (basesink), + gst_event_new_caps (caps))) + goto could_not_set_caps; - result = TRUE; + GST_OBJECT_LOCK (basesink); + gst_caps_replace (&basesink->priv->pull_caps, caps); + GST_OBJECT_UNLOCK (basesink); + + result = TRUE; + } } gst_caps_unref (caps); @@ -4397,28 +4326,24 @@ gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active) bclass = GST_BASE_SINK_GET_CLASS (basesink); if (active) { - GstFormat format; gint64 duration; /* we mark we have a newsegment here because pull based * mode works just fine without having a newsegment before the * first buffer */ - format = GST_FORMAT_BYTES; - - gst_segment_init (&basesink->segment, format); - gst_segment_init (basesink->abidata.ABI.clip_segment, format); + gst_segment_init (&basesink->segment, GST_FORMAT_BYTES); + gst_segment_init (&basesink->clip_segment, GST_FORMAT_BYTES); GST_OBJECT_LOCK (basesink); basesink->have_newsegment = TRUE; GST_OBJECT_UNLOCK (basesink); /* get the peer duration in bytes */ - result = gst_pad_query_peer_duration (pad, &format, &duration); + result = gst_pad_query_peer_duration (pad, GST_FORMAT_BYTES, &duration); if (result) { GST_DEBUG_OBJECT (basesink, "setting duration in bytes to %" G_GINT64_FORMAT, duration); - gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format, - duration); - gst_segment_set_duration (&basesink->segment, format, duration); + basesink->clip_segment.duration = duration; + basesink->segment.duration = duration; } else { GST_DEBUG_OBJECT (basesink, "unknown duration"); } @@ -4534,11 +4459,11 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, { GstClock *clock = NULL; gboolean res = FALSE; - GstFormat oformat, tformat; + GstFormat oformat; GstSegment *segment; GstClockTime now, latency; - GstClockTimeDiff base; - gint64 time, accum, duration; + GstClockTimeDiff base_time; + gint64 time, base, duration; gdouble rate; gint64 last; gboolean last_seen, with_clock, in_paused; @@ -4561,12 +4486,10 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, * main segment directly with the new segment values without it having to be * activated by the rendering after preroll */ if (basesink->pad_mode == GST_ACTIVATE_PUSH) - segment = basesink->abidata.ABI.clip_segment; + segment = &basesink->clip_segment; else segment = &basesink->segment; - /* our intermediate time format */ - tformat = GST_FORMAT_TIME; /* get the format in the segment */ oformat = segment->format; @@ -4584,6 +4507,14 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, else gst_object_ref (clock); + /* mainloop might be querying position when going to playing async, + * while (audio) rendering might be quickly advancing stream position, + * so use clock asap rather than last reported position */ + if (in_paused && with_clock && g_atomic_int_get (&basesink->priv->to_playing)) { + GST_DEBUG_OBJECT (basesink, "going to PLAYING, so not PAUSED"); + in_paused = FALSE; + } + /* collect all data we need holding the lock */ if (GST_CLOCK_TIME_IS_VALID (segment->time)) time = segment->time; @@ -4595,7 +4526,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, else duration = 0; - accum = segment->accum; + base = segment->base; rate = segment->rate * segment->applied_rate; latency = basesink->priv->latency; @@ -4620,28 +4551,28 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, } } else { /* convert last stop to stream time */ - last = gst_segment_to_stream_time (segment, oformat, segment->last_stop); + last = gst_segment_to_stream_time (segment, oformat, segment->position); } if (in_paused) { /* in paused, use start_time */ - base = GST_ELEMENT_START_TIME (basesink); + base_time = GST_ELEMENT_START_TIME (basesink); GST_DEBUG_OBJECT (basesink, "in paused, using start time %" GST_TIME_FORMAT, - GST_TIME_ARGS (base)); + GST_TIME_ARGS (base_time)); } else if (with_clock) { /* else use clock when needed */ - base = GST_ELEMENT_CAST (basesink)->base_time; + base_time = GST_ELEMENT_CAST (basesink)->base_time; GST_DEBUG_OBJECT (basesink, "using clock and base time %" GST_TIME_FORMAT, - GST_TIME_ARGS (base)); + GST_TIME_ARGS (base_time)); } else { /* else, no sync or clock -> no base time */ GST_DEBUG_OBJECT (basesink, "no sync or no clock"); - base = -1; + base_time = -1; } - /* no base, we can't calculate running_time, use last seem timestamp to report + /* no base_time, we can't calculate running_time, use last seem timestamp to report * time */ - if (base == -1) + if (base_time == -1) last_seen = TRUE; /* need to release the object lock before we can get the time, @@ -4663,47 +4594,47 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, GST_TIME_ARGS (last)); *cur = last; } else { - if (oformat != tformat) { - /* convert accum, time and duration to time */ - if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat, - &accum)) + if (oformat != GST_FORMAT_TIME) { + /* convert base, time and duration to time */ + if (!gst_pad_query_convert (basesink->sinkpad, oformat, base, + GST_FORMAT_TIME, &base)) goto convert_failed; if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration, - &tformat, &duration)) + GST_FORMAT_TIME, &duration)) goto convert_failed; - if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat, - &time)) + if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, + GST_FORMAT_TIME, &time)) goto convert_failed; - if (!gst_pad_query_convert (basesink->sinkpad, oformat, last, &tformat, - &last)) + if (!gst_pad_query_convert (basesink->sinkpad, oformat, last, + GST_FORMAT_TIME, &last)) goto convert_failed; /* assume time format from now on */ - oformat = tformat; + oformat = GST_FORMAT_TIME; } if (!in_paused && with_clock) { now = gst_clock_get_time (clock); } else { - now = base; - base = 0; + now = base_time; + base_time = 0; } - /* subtract base time and accumulated time from the clock time. + /* subtract base time and base time from the clock time. * Make sure we don't go negative. This is the current time in * the segment which we need to scale with the combined * rate and applied rate. */ - base += accum; - base += latency; - if (GST_CLOCK_DIFF (base, now) < 0) - base = now; + base_time += base; + base_time += latency; + if (GST_CLOCK_DIFF (base_time, now) < 0) + base_time = now; /* for negative rates we need to count back from the segment * duration. */ if (rate < 0.0) time += duration; - *cur = time + gst_guint64_to_gdouble (now - base) * rate; + *cur = time + gst_guint64_to_gdouble (now - base_time) * rate; if (in_paused) { /* never report less than segment values in paused */ @@ -4716,15 +4647,15 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, } GST_DEBUG_OBJECT (basesink, - "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %" + "now %" GST_TIME_FORMAT " - base_time %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " + time %" GST_TIME_FORMAT " last %" GST_TIME_FORMAT, - GST_TIME_ARGS (now), GST_TIME_ARGS (base), GST_TIME_ARGS (accum), + GST_TIME_ARGS (now), GST_TIME_ARGS (base_time), GST_TIME_ARGS (base), GST_TIME_ARGS (time), GST_TIME_ARGS (last)); } if (oformat != format) { /* convert to final format */ - if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur)) + if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, format, cur)) goto convert_failed; } @@ -4765,20 +4696,22 @@ gst_base_sink_get_duration (GstBaseSink * basesink, GstFormat format, gboolean res = FALSE; if (basesink->pad_mode == GST_ACTIVATE_PULL) { - GstFormat uformat = GST_FORMAT_BYTES; gint64 uduration; /* get the duration in bytes, in pull mode that's all we are sure to * know. We have to explicitly get this value from upstream instead of * using our cached value because it might change. Duration caching * should be done at a higher level. */ - res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, &uduration); + res = + gst_pad_query_peer_duration (basesink->sinkpad, GST_FORMAT_BYTES, + &uduration); if (res) { - gst_segment_set_duration (&basesink->segment, uformat, uduration); - if (format != uformat) { + basesink->segment.duration = uduration; + if (format != GST_FORMAT_BYTES) { /* convert to the requested format */ - res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration, - &format, dur); + res = + gst_pad_query_convert (basesink->sinkpad, GST_FORMAT_BYTES, + uduration, format, dur); } else { *dur = uduration; } @@ -4806,7 +4739,7 @@ gst_base_sink_get_query_types (GstElement * element) } static gboolean -gst_base_sink_query (GstElement * element, GstQuery * query) +default_element_query (GstElement * element, GstQuery * query) { gboolean res = FALSE; @@ -4836,20 +4769,21 @@ gst_base_sink_query (GstElement * element, GstQuery * query) /* we can handle a few things if upstream failed */ if (format == GST_FORMAT_PERCENT) { gint64 dur = 0; - GstFormat uformat = GST_FORMAT_TIME; res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur, &upstream); if (!res && upstream) { - res = gst_pad_query_peer_position (basesink->sinkpad, &uformat, + res = + gst_pad_query_peer_position (basesink->sinkpad, GST_FORMAT_TIME, &cur); } if (res) { res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur, &upstream); if (!res && upstream) { - res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, - &dur); + res = + gst_pad_query_peer_duration (basesink->sinkpad, + GST_FORMAT_TIME, &dur); } } if (res) { @@ -4931,6 +4865,56 @@ gst_base_sink_query (GstElement * element, GstQuery * query) return res; } + +static gboolean +default_sink_query (GstBaseSink * basesink, GstQuery * query) +{ + gboolean res; + GstBaseSinkClass *bclass; + + bclass = GST_BASE_SINK_GET_CLASS (basesink); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_ALLOCATION: + { + if (bclass->setup_allocation) + res = bclass->setup_allocation (basesink, query); + else + res = FALSE; + break; + } + default: + res = gst_pad_query_default (basesink->sinkpad, query); + break; + } + return res; +} + +static gboolean +gst_base_sink_sink_query (GstPad * pad, GstQuery * query) +{ + GstBaseSink *basesink; + GstBaseSinkClass *bclass; + gboolean res; + + basesink = GST_BASE_SINK_CAST (gst_pad_get_parent (pad)); + if (G_UNLIKELY (basesink == NULL)) { + gst_query_unref (query); + return FALSE; + } + + bclass = GST_BASE_SINK_GET_CLASS (basesink); + + if (bclass->query) + res = bclass->query (basesink, query); + else + res = FALSE; + + gst_object_unref (basesink); + + return res; +} + static GstStateChangeReturn gst_base_sink_change_state (GstElement * element, GstStateChange transition) { @@ -4952,17 +4936,17 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_READY_TO_PAUSED: /* need to complete preroll before this state change completes, there * is no data flow in READY so we can safely assume we need to preroll. */ - GST_PAD_PREROLL_LOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (basesink); GST_DEBUG_OBJECT (basesink, "READY to PAUSED"); basesink->have_newsegment = FALSE; gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED); - gst_segment_init (basesink->abidata.ABI.clip_segment, - GST_FORMAT_UNDEFINED); + gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED); basesink->offset = 0; basesink->have_preroll = FALSE; priv->step_unlock = FALSE; basesink->need_preroll = TRUE; basesink->playing_async = TRUE; + basesink->priv->reset_time = FALSE; priv->current_sstart = GST_CLOCK_TIME_NONE; priv->current_sstop = GST_CLOCK_TIME_NONE; priv->eos_rtime = GST_CLOCK_TIME_NONE; @@ -4980,14 +4964,15 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) * the state change function */ ret = GST_STATE_CHANGE_ASYNC; gst_element_post_message (GST_ELEMENT_CAST (basesink), - gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE)); + gst_message_new_async_start (GST_OBJECT_CAST (basesink))); } else { priv->have_latency = TRUE; } - GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - GST_PAD_PREROLL_LOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (basesink); + g_atomic_int_set (&basesink->priv->to_playing, TRUE); if (!gst_base_sink_needs_preroll (basesink)) { GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll"); /* no preroll needed anymore now. */ @@ -5003,7 +4988,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) gst_element_post_message (GST_ELEMENT_CAST (basesink), message); } else { GST_DEBUG_OBJECT (basesink, "signal preroll"); - GST_PAD_PREROLL_SIGNAL (basesink->sinkpad); + GST_BASE_SINK_PREROLL_SIGNAL (basesink); } } else { GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled"); @@ -5015,10 +5000,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_DEBUG_OBJECT (basesink, "doing async state change"); ret = GST_STATE_CHANGE_ASYNC; gst_element_post_message (GST_ELEMENT_CAST (basesink), - gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE)); + gst_message_new_async_start (GST_OBJECT_CAST (basesink))); } } - GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); break; default: break; @@ -5033,7 +5018,14 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) } switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + /* completed transition, so need not be marked any longer + * And it should be unmarked, since e.g. losing our position upon flush + * does not really change state to PAUSED ... */ + g_atomic_int_set (&basesink->priv->to_playing, FALSE); + break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + g_atomic_int_set (&basesink->priv->to_playing, FALSE); GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED"); /* FIXME, make sure we cannot enter _render first */ @@ -5042,7 +5034,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) if (bclass->unlock) bclass->unlock (basesink); - GST_PAD_PREROLL_LOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (basesink); GST_DEBUG_OBJECT (basesink, "got preroll lock"); /* now that we have the PREROLL lock, clear our unlock request */ if (bclass->unlock_stop) @@ -5077,8 +5069,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_DEBUG_OBJECT (basesink, "doing async state change"); ret = GST_STATE_CHANGE_ASYNC; gst_element_post_message (GST_ELEMENT_CAST (basesink), - gst_message_new_async_start (GST_OBJECT_CAST (basesink), - FALSE)); + gst_message_new_async_start (GST_OBJECT_CAST (basesink))); } } } @@ -5086,10 +5077,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) ", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped); gst_base_sink_reset_qos (basesink); - GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); break; case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_PAD_PREROLL_LOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_LOCK (basesink); /* start by reseting our position state with the object lock so that the * position query gets the right idea. We do this before we post the * messages so that the message handlers pick this up. */ @@ -5116,13 +5107,13 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition) GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY)); gst_element_post_message (GST_ELEMENT_CAST (basesink), - gst_message_new_async_done (GST_OBJECT_CAST (basesink))); + gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE)); } priv->commited = TRUE; } else { GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll"); } - GST_PAD_PREROLL_UNLOCK (basesink->sinkpad); + GST_BASE_SINK_PREROLL_UNLOCK (basesink); break; case GST_STATE_CHANGE_READY_TO_NULL: if (bclass->stop) {