X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Felements%2Fgstidentity.c;h=a3eb5cd1ceade6156b67f6a6730d2dba0e0dd148;hb=4fc4ad87d55b6045217a0fa0bebbdbbe2c31a006;hp=2a3350d486c477338d294081dee054fb5da929a0;hpb=81ce8b76d0b31c130ea4a49ea10eb7718490ba6e;p=platform%2Fupstream%2Fgstreamer.git diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index 2a3350d..a3eb5cd 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -17,11 +17,12 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** * SECTION:element-identity + * @title: identity * * Dummy element that passes incoming data through unmodified. It has some * useful diagnostic functions, such as offset and timestamp checking. @@ -34,9 +35,9 @@ #include #include +#include "gstelements_private.h" #include "../../gst/gst-i18n-lib.h" #include "gstidentity.h" -#include static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -63,15 +64,17 @@ enum #define DEFAULT_DUPLICATE 1 #define DEFAULT_ERROR_AFTER -1 #define DEFAULT_DROP_PROBABILITY 0.0 +#define DEFAULT_DROP_BUFFER_FLAGS 0 #define DEFAULT_DATARATE 0 -#define DEFAULT_SILENT FALSE +#define DEFAULT_SILENT TRUE #define DEFAULT_SINGLE_SEGMENT FALSE #define DEFAULT_DUMP FALSE #define DEFAULT_SYNC FALSE -#define DEFAULT_CHECK_PERFECT FALSE #define DEFAULT_CHECK_IMPERFECT_TIMESTAMP FALSE #define DEFAULT_CHECK_IMPERFECT_OFFSET FALSE #define DEFAULT_SIGNAL_HANDOFFS TRUE +#define DEFAULT_TS_OFFSET 0 +#define DEFAULT_DROP_ALLOCATION FALSE enum { @@ -79,16 +82,18 @@ enum PROP_SLEEP_TIME, PROP_ERROR_AFTER, PROP_DROP_PROBABILITY, + PROP_DROP_BUFFER_FLAGS, PROP_DATARATE, PROP_SILENT, PROP_SINGLE_SEGMENT, PROP_LAST_MESSAGE, PROP_DUMP, PROP_SYNC, - PROP_CHECK_PERFECT, + PROP_TS_OFFSET, PROP_CHECK_IMPERFECT_TIMESTAMP, PROP_CHECK_IMPERFECT_OFFSET, - PROP_SIGNAL_HANDOFFS + PROP_SIGNAL_HANDOFFS, + PROP_DROP_ALLOCATION }; @@ -108,12 +113,14 @@ static gboolean gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event); static GstFlowReturn gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf); -static GstFlowReturn gst_identity_prepare_output_buffer (GstBaseTransform * - trans, GstBuffer * in_buf, GstBuffer ** out_buf); static gboolean gst_identity_start (GstBaseTransform * trans); static gboolean gst_identity_stop (GstBaseTransform * trans); static GstStateChangeReturn gst_identity_change_state (GstElement * element, GstStateChange transition); +static gboolean gst_identity_accept_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps); +static gboolean gst_identity_query (GstBaseTransform * base, + GstPadDirection direction, GstQuery * query); static guint gst_identity_signals[LAST_SIGNAL] = { 0 }; @@ -127,42 +134,11 @@ gst_identity_finalize (GObject * object) identity = GST_IDENTITY (object); g_free (identity->last_message); - -#if !GLIB_CHECK_VERSION(2,26,0) - g_static_rec_mutex_free (&identity->notify_lock); -#endif + g_cond_clear (&identity->blocked_cond); G_OBJECT_CLASS (parent_class)->finalize (object); } -/* fixme: do something about this */ -static void -marshal_VOID__MINIOBJECT (GClosure * closure, GValue * return_value, - guint n_param_values, const GValue * param_values, gpointer invocation_hint, - gpointer marshal_data) -{ - typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, - gpointer data2); - register marshalfunc_VOID__MINIOBJECT callback; - register GCClosure *cc = (GCClosure *) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 2); - - if (G_CCLOSURE_SWAP_DATA (closure)) { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } else { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = - (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : - cc->callback); - - callback (data1, g_value_get_boxed (param_values + 1), data2); -} - static void gst_identity_class_init (GstIdentityClass * klass) { @@ -190,6 +166,19 @@ gst_identity_class_init (GstIdentityClass * klass) "The Probability a buffer is dropped", 0.0, 1.0, DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstIdentity:drop-buffer-flags: + * + * Drop buffers with the given flags. + * + * Since: 1.8 + **/ + g_object_class_install_property (gobject_class, PROP_DROP_BUFFER_FLAGS, + g_param_spec_flags ("drop-buffer-flags", "Check flags to drop buffers", + "Drop buffers with the given flags", + GST_TYPE_BUFFER_FLAGS, DEFAULT_DROP_BUFFER_FLAGS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DATARATE, g_param_spec_int ("datarate", "Datarate", "(Re)timestamps buffers with number of bytes per second (0 = inactive)", @@ -213,12 +202,11 @@ gst_identity_class_init (GstIdentityClass * klass) g_param_spec_boolean ("sync", "Synchronize", "Synchronize to pipeline clock", DEFAULT_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_CHECK_PERFECT, - g_param_spec_boolean ("check-perfect", "Check For Perfect Stream", - "Verify that the stream is time- and data-contiguous. " - "This only logs in the debug log. This will be deprecated in favor " - "of the check-imperfect-timestamp/offset properties.", - DEFAULT_CHECK_PERFECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TS_OFFSET, + g_param_spec_int64 ("ts-offset", "Timestamp offset for synchronisation", + "Timestamp offset in nanoseconds for synchronisation, negative for earlier sync", + G_MININT64, G_MAXINT64, DEFAULT_TS_OFFSET, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_CHECK_IMPERFECT_TIMESTAMP, g_param_spec_boolean ("check-imperfect-timestamp", @@ -236,16 +224,19 @@ gst_identity_class_init (GstIdentityClass * klass) /** * GstIdentity:signal-handoffs * - * If set to #TRUE, the identity will emit a handoff signal when handling a buffer. - * When set to #FALSE, no signal will be emited, which might improve performance. - * - * Since: 0.10.16 + * If set to %TRUE, the identity will emit a handoff signal when handling a buffer. + * When set to %FALSE, no signal will be emitted, which might improve performance. */ g_object_class_install_property (gobject_class, PROP_SIGNAL_HANDOFFS, g_param_spec_boolean ("signal-handoffs", "Signal handoffs", "Send a signal before pushing the buffer", DEFAULT_SIGNAL_HANDOFFS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DROP_ALLOCATION, + g_param_spec_boolean ("drop-allocation", "Drop allocation query", + "Don't forward allocation queries", DEFAULT_DROP_ALLOCATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstIdentity::handoff: * @identity: the identity instance @@ -257,28 +248,29 @@ gst_identity_class_init (GstIdentityClass * klass) gst_identity_signals[SIGNAL_HANDOFF] = g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstIdentityClass, handoff), NULL, NULL, - marshal_VOID__MINIOBJECT, G_TYPE_NONE, 1, GST_TYPE_BUFFER); + g_cclosure_marshal_generic, G_TYPE_NONE, 1, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE); gobject_class->finalize = gst_identity_finalize; - gst_element_class_set_details_simple (gstelement_class, + gst_element_class_set_static_metadata (gstelement_class, "Identity", "Generic", "Pass data without modification", "Erik Walthinsen "); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&srctemplate)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sinktemplate)); + gst_element_class_add_static_pad_template (gstelement_class, &srctemplate); + gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_identity_change_state); + gstbasetrans_class->sink_event = GST_DEBUG_FUNCPTR (gst_identity_sink_event); gstbasetrans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_identity_transform_ip); - gstbasetrans_class->prepare_output_buffer = - GST_DEBUG_FUNCPTR (gst_identity_prepare_output_buffer); gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_identity_start); gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_identity_stop); + gstbasetrans_class->accept_caps = + GST_DEBUG_FUNCPTR (gst_identity_accept_caps); + gstbasetrans_class->query = gst_identity_query; } static void @@ -287,20 +279,18 @@ gst_identity_init (GstIdentity * identity) identity->sleep_time = DEFAULT_SLEEP_TIME; identity->error_after = DEFAULT_ERROR_AFTER; identity->drop_probability = DEFAULT_DROP_PROBABILITY; + identity->drop_buffer_flags = DEFAULT_DROP_BUFFER_FLAGS; identity->datarate = DEFAULT_DATARATE; identity->silent = DEFAULT_SILENT; identity->single_segment = DEFAULT_SINGLE_SEGMENT; identity->sync = DEFAULT_SYNC; - identity->check_perfect = DEFAULT_CHECK_PERFECT; identity->check_imperfect_timestamp = DEFAULT_CHECK_IMPERFECT_TIMESTAMP; identity->check_imperfect_offset = DEFAULT_CHECK_IMPERFECT_OFFSET; identity->dump = DEFAULT_DUMP; identity->last_message = NULL; identity->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; - -#if !GLIB_CHECK_VERSION(2,26,0) - g_static_rec_mutex_init (&identity->notify_lock); -#endif + identity->ts_offset = DEFAULT_TS_OFFSET; + g_cond_init (&identity->blocked_cond); gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM_CAST (identity), TRUE); } @@ -308,19 +298,67 @@ gst_identity_init (GstIdentity * identity) static void gst_identity_notify_last_message (GstIdentity * identity) { - /* FIXME: this hacks around a bug in GLib/GObject: doing concurrent - * g_object_notify() on the same object might lead to crashes, see - * http://bugzilla.gnome.org/show_bug.cgi?id=166020#c60 and follow-ups. - * So we really don't want to do a g_object_notify() here for out-of-band - * events with the streaming thread possibly also doing a g_object_notify() - * for an in-band buffer or event. This is fixed in GLib >= 2.26 */ -#if !GLIB_CHECK_VERSION(2,26,0) - g_static_rec_mutex_lock (&identity->notify_lock); - g_object_notify ((GObject *) identity, "last-message"); - g_static_rec_mutex_unlock (&identity->notify_lock); -#else g_object_notify_by_pspec ((GObject *) identity, pspec_last_message); -#endif +} + +static GstFlowReturn +gst_identity_do_sync (GstIdentity * identity, GstClockTime running_time) +{ + GstFlowReturn ret = GST_FLOW_OK; + + if (identity->sync && + GST_BASE_TRANSFORM_CAST (identity)->segment.format == GST_FORMAT_TIME) { + GstClock *clock; + + GST_OBJECT_LOCK (identity); + + if (identity->flushing) { + GST_OBJECT_UNLOCK (identity); + return GST_FLOW_FLUSHING; + } + + while (identity->blocked) + g_cond_wait (&identity->blocked_cond, GST_OBJECT_GET_LOCK (identity)); + + if (identity->flushing) { + GST_OBJECT_UNLOCK (identity); + return GST_FLOW_FLUSHING; + } + + if ((clock = GST_ELEMENT (identity)->clock)) { + GstClockReturn cret; + GstClockTime timestamp; + GstClockTimeDiff ts_offset = identity->ts_offset; + + timestamp = running_time + GST_ELEMENT (identity)->base_time + + identity->upstream_latency; + if (ts_offset < 0) { + ts_offset = -ts_offset; + if (ts_offset < timestamp) + timestamp -= ts_offset; + else + timestamp = 0; + } else + timestamp += ts_offset; + + /* save id if we need to unlock */ + identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp); + GST_OBJECT_UNLOCK (identity); + + cret = gst_clock_id_wait (identity->clock_id, NULL); + + GST_OBJECT_LOCK (identity); + if (identity->clock_id) { + gst_clock_id_unref (identity->clock_id); + identity->clock_id = NULL; + } + if (cret == GST_CLOCK_UNSCHEDULED || identity->flushing) + ret = GST_FLOW_FLUSHING; + } + GST_OBJECT_UNLOCK (identity); + } + + return ret; } static gboolean @@ -333,20 +371,22 @@ gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) if (!identity->silent) { const GstStructure *s; + const gchar *tstr; gchar *sstr; GST_OBJECT_LOCK (identity); g_free (identity->last_message); + tstr = gst_event_type_get_name (GST_EVENT_TYPE (event)); if ((s = gst_event_get_structure (event))) sstr = gst_structure_to_string (s); else sstr = g_strdup (""); identity->last_message = - g_strdup_printf ("event ******* (%s:%s) E (type: %d, %s) %p", - GST_DEBUG_PAD_NAME (trans->sinkpad), GST_EVENT_TYPE (event), sstr, - event); + g_strdup_printf ("event ******* (%s:%s) E (type: %s (%d), %s) %p", + GST_DEBUG_PAD_NAME (trans->sinkpad), tstr, GST_EVENT_TYPE (event), + sstr, event); g_free (sstr); GST_OBJECT_UNLOCK (identity); @@ -354,7 +394,7 @@ gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) } if (identity->single_segment && (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT)) { - if (trans->have_segment == FALSE) { + if (!trans->have_segment) { GstEvent *news; GstSegment segment; @@ -367,10 +407,32 @@ gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) news = gst_event_new_segment (&segment); gst_pad_event_default (trans->sinkpad, GST_OBJECT_CAST (trans), news); + } else { + /* need to track segment for proper running time */ + gst_event_copy_segment (event, &trans->segment); } } - /* Reset previous timestamp, duration and offsets on NEWSEGMENT + if (GST_EVENT_TYPE (event) == GST_EVENT_GAP && + trans->have_segment && trans->segment.format == GST_FORMAT_TIME) { + GstClockTime start, dur; + + gst_event_parse_gap (event, &start, &dur); + if (GST_CLOCK_TIME_IS_VALID (start)) { + start = gst_segment_to_running_time (&trans->segment, + GST_FORMAT_TIME, start); + + gst_identity_do_sync (identity, start); + + /* also transform GAP timestamp similar to buffer timestamps */ + if (identity->single_segment) { + gst_event_unref (event); + event = gst_event_new_gap (start, dur); + } + } + } + + /* Reset previous timestamp, duration and offsets on SEGMENT * to prevent false warnings when checking for perfect streams */ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { identity->prev_timestamp = identity->prev_duration = GST_CLOCK_TIME_NONE; @@ -384,13 +446,16 @@ gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) } else { if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) { GST_OBJECT_LOCK (identity); + identity->flushing = TRUE; if (identity->clock_id) { GST_DEBUG_OBJECT (identity, "unlock clock wait"); gst_clock_id_unschedule (identity->clock_id); - gst_clock_id_unref (identity->clock_id); - identity->clock_id = NULL; } GST_OBJECT_UNLOCK (identity); + } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { + GST_OBJECT_LOCK (identity); + identity->flushing = FALSE; + GST_OBJECT_UNLOCK (identity); } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); @@ -399,72 +464,6 @@ gst_identity_sink_event (GstBaseTransform * trans, GstEvent * event) return ret; } -static GstFlowReturn -gst_identity_prepare_output_buffer (GstBaseTransform * trans, - GstBuffer * in_buf, GstBuffer ** out_buf) -{ - GstIdentity *identity = GST_IDENTITY (trans); - - /* only bother if we may have to alter metadata */ - if (identity->datarate > 0 || identity->single_segment) { - if (gst_buffer_is_writable (in_buf)) - /* reuse */ - *out_buf = in_buf; - else { - /* copy */ - *out_buf = gst_buffer_copy (in_buf); - } - } else - *out_buf = in_buf; - - return GST_FLOW_OK; -} - -static void -gst_identity_check_perfect (GstIdentity * identity, GstBuffer * buf) -{ - GstClockTime timestamp; - - timestamp = GST_BUFFER_TIMESTAMP (buf); - - /* see if we need to do perfect stream checking */ - /* invalid timestamp drops us out of check. FIXME: maybe warn ? */ - if (timestamp != GST_CLOCK_TIME_NONE) { - /* check if we had a previous buffer to compare to */ - if (identity->prev_timestamp != GST_CLOCK_TIME_NONE && - identity->prev_duration != GST_CLOCK_TIME_NONE) { - guint64 offset, t_expected; - gint64 dt; - - t_expected = identity->prev_timestamp + identity->prev_duration; - dt = timestamp - t_expected; - if (dt != 0) { - GST_WARNING_OBJECT (identity, - "Buffer not time-contiguous with previous one: " "prev ts %" - GST_TIME_FORMAT ", prev dur %" GST_TIME_FORMAT ", new ts %" - GST_TIME_FORMAT " (expected ts %" GST_TIME_FORMAT ", delta=%c%" - GST_TIME_FORMAT ")", GST_TIME_ARGS (identity->prev_timestamp), - GST_TIME_ARGS (identity->prev_duration), GST_TIME_ARGS (timestamp), - GST_TIME_ARGS (t_expected), (dt < 0) ? '-' : '+', - GST_TIME_ARGS ((dt < 0) ? (GstClockTime) (-dt) : dt)); - } - - offset = GST_BUFFER_OFFSET (buf); - if (identity->prev_offset_end != offset && - identity->prev_offset_end != GST_BUFFER_OFFSET_NONE && - offset != GST_BUFFER_OFFSET_NONE) { - GST_WARNING_OBJECT (identity, - "Buffer not data-contiguous with previous one: " - "prev offset_end %" G_GINT64_FORMAT ", new offset %" - G_GINT64_FORMAT, identity->prev_offset_end, offset); - } - } else { - GST_DEBUG_OBJECT (identity, "can't check time-contiguity, no timestamp " - "and/or duration were set on previous buffer"); - } - } -} - static void gst_identity_check_imperfect_timestamp (GstIdentity * identity, GstBuffer * buf) { @@ -484,6 +483,7 @@ gst_identity_check_imperfect_timestamp (GstIdentity * identity, GstBuffer * buf) /* * "imperfect-timestamp" bus message: * @identity: the identity instance + * @delta: the GST_CLOCK_DIFF to the prev timestamp * @prev-timestamp: the previous buffer timestamp * @prev-duration: the previous buffer duration * @prev-offset: the previous buffer offset @@ -500,6 +500,7 @@ gst_identity_check_imperfect_timestamp (GstIdentity * identity, GstBuffer * buf) gst_element_post_message (GST_ELEMENT (identity), gst_message_new_element (GST_OBJECT (identity), gst_structure_new ("imperfect-timestamp", + "delta", G_TYPE_INT64, dt, "prev-timestamp", G_TYPE_UINT64, identity->prev_timestamp, "prev-duration", G_TYPE_UINT64, identity->prev_duration, "prev-offset", G_TYPE_UINT64, @@ -574,40 +575,26 @@ static void gst_identity_update_last_message_for_buffer (GstIdentity * identity, const gchar * action, GstBuffer * buf, gsize size) { - gchar ts_str[64], dur_str[64]; - gchar flag_str[100]; + gchar dts_str[64], pts_str[64], dur_str[64]; + gchar *flag_str, *meta_str; GST_OBJECT_LOCK (identity); - { - const char *flag_list[15] = { - "", "", "", "", "live", "decode-only", "discont", "resync", "corrupted", - "marker", "header", "gap", "droppable", "delta-unit", "in-caps" - }; - int i; - char *end = flag_str; - end[0] = '\0'; - for (i = 0; i < G_N_ELEMENTS (flag_list); i++) { - if (GST_MINI_OBJECT_CAST (buf)->flags & (1 << i)) { - strcpy (end, flag_list[i]); - end += strlen (end); - end[0] = ' '; - end[1] = '\0'; - end++; - } - } - } + flag_str = gst_buffer_get_flags_string (buf); + meta_str = gst_buffer_get_meta_string (buf); g_free (identity->last_message); identity->last_message = g_strdup_printf ("%s ******* (%s:%s) " - "(%" G_GSIZE_FORMAT " bytes, timestamp: %s, duration: %s, offset: %" + "(%" G_GSIZE_FORMAT " bytes, dts: %s, pts: %s, duration: %s, offset: %" G_GINT64_FORMAT ", " "offset_end: % " G_GINT64_FORMAT - ", flags: %d %s) %p", action, + ", flags: %08x %s, meta: %s) %p", action, GST_DEBUG_PAD_NAME (GST_BASE_TRANSFORM_CAST (identity)->sinkpad), size, - print_pretty_time (ts_str, sizeof (ts_str), GST_BUFFER_TIMESTAMP (buf)), + print_pretty_time (dts_str, sizeof (dts_str), GST_BUFFER_DTS (buf)), + print_pretty_time (pts_str, sizeof (pts_str), GST_BUFFER_PTS (buf)), print_pretty_time (dur_str, sizeof (dur_str), GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), - GST_BUFFER_FLAGS (buf), flag_str, buf); + GST_BUFFER_FLAGS (buf), flag_str, meta_str ? meta_str : "none", buf); + g_free (flag_str); GST_OBJECT_UNLOCK (identity); @@ -619,14 +606,13 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstIdentity *identity = GST_IDENTITY (trans); - GstClockTime runtimestamp = G_GINT64_CONSTANT (0); - guint8 *data; + GstClockTime rundts = GST_CLOCK_TIME_NONE; + GstClockTime runpts = GST_CLOCK_TIME_NONE; + GstClockTime ts, duration, runtimestamp; gsize size; - data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); + size = gst_buffer_get_size (buf); - if (identity->check_perfect) - gst_identity_check_perfect (identity, buf); if (identity->check_imperfect_timestamp) gst_identity_check_imperfect_timestamp (identity, buf); if (identity->check_imperfect_offset) @@ -649,8 +635,16 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) goto dropped; } + if (GST_BUFFER_FLAG_IS_SET (buf, identity->drop_buffer_flags)) + goto dropped; + if (identity->dump) { - gst_util_dump_mem (data, size); + GstMapInfo info; + + if (gst_buffer_map (buf, &info, GST_MAP_READ)) { + gst_util_dump_mem (info.data, info.size); + gst_buffer_unmap (buf, &info); + } } if (!identity->silent) { @@ -661,44 +655,28 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) GstClockTime time = gst_util_uint64_scale_int (identity->offset, GST_SECOND, identity->datarate); - GST_BUFFER_TIMESTAMP (buf) = time; + GST_BUFFER_PTS (buf) = GST_BUFFER_DTS (buf) = time; GST_BUFFER_DURATION (buf) = size * GST_SECOND / identity->datarate; } if (identity->signal_handoffs) g_signal_emit (identity, gst_identity_signals[SIGNAL_HANDOFF], 0, buf); - if (trans->segment.format == GST_FORMAT_TIME) - runtimestamp = gst_segment_to_running_time (&trans->segment, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); - - if ((identity->sync) && (trans->segment.format == GST_FORMAT_TIME)) { - GstClock *clock; - - GST_OBJECT_LOCK (identity); - if ((clock = GST_ELEMENT (identity)->clock)) { - GstClockReturn cret; - GstClockTime timestamp; - - timestamp = runtimestamp + GST_ELEMENT (identity)->base_time; - - /* save id if we need to unlock */ - identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp); - GST_OBJECT_UNLOCK (identity); - - cret = gst_clock_id_wait (identity->clock_id, NULL); - - GST_OBJECT_LOCK (identity); - if (identity->clock_id) { - gst_clock_id_unref (identity->clock_id); - identity->clock_id = NULL; - } - if (cret == GST_CLOCK_UNSCHEDULED) - ret = GST_FLOW_EOS; - } - GST_OBJECT_UNLOCK (identity); + if (trans->segment.format == GST_FORMAT_TIME) { + rundts = gst_segment_to_running_time (&trans->segment, + GST_FORMAT_TIME, GST_BUFFER_DTS (buf)); + runpts = gst_segment_to_running_time (&trans->segment, + GST_FORMAT_TIME, GST_BUFFER_PTS (buf)); } + if (GST_CLOCK_TIME_IS_VALID (rundts)) + runtimestamp = rundts; + else if (GST_CLOCK_TIME_IS_VALID (runpts)) + runtimestamp = runpts; + else + runtimestamp = 0; + ret = gst_identity_do_sync (identity, runtimestamp); + identity->offset += size; if (identity->sleep_time && ret == GST_FLOW_OK) @@ -706,13 +684,12 @@ gst_identity_transform_ip (GstBaseTransform * trans, GstBuffer * buf) if (identity->single_segment && (trans->segment.format == GST_FORMAT_TIME) && (ret == GST_FLOW_OK)) { - GST_BUFFER_TIMESTAMP (buf) = runtimestamp; + GST_BUFFER_DTS (buf) = rundts; + GST_BUFFER_PTS (buf) = runpts; GST_BUFFER_OFFSET (buf) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET_END (buf) = GST_CLOCK_TIME_NONE; } - gst_buffer_unmap (buf, data, size); - return ret; /* ERRORS */ @@ -720,7 +697,6 @@ error_after: { GST_ELEMENT_ERROR (identity, CORE, FAILED, (_("Failed after iterations as requested.")), (NULL)); - gst_buffer_unmap (buf, data, size); return GST_FLOW_ERROR; } dropped: @@ -729,7 +705,14 @@ dropped: gst_identity_update_last_message_for_buffer (identity, "dropping", buf, size); } - gst_buffer_unmap (buf, data, size); + + ts = GST_BUFFER_TIMESTAMP (buf); + if (GST_CLOCK_TIME_IS_VALID (ts)) { + duration = GST_BUFFER_DURATION (buf); + gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (identity), + gst_event_new_gap (ts, duration)); + } + /* return DROPPED to basetransform. */ return GST_BASE_TRANSFORM_FLOW_DROPPED; } @@ -762,14 +745,17 @@ gst_identity_set_property (GObject * object, guint prop_id, case PROP_DROP_PROBABILITY: identity->drop_probability = g_value_get_float (value); break; + case PROP_DROP_BUFFER_FLAGS: + identity->drop_buffer_flags = g_value_get_flags (value); + break; case PROP_DATARATE: identity->datarate = g_value_get_int (value); break; case PROP_SYNC: identity->sync = g_value_get_boolean (value); break; - case PROP_CHECK_PERFECT: - identity->check_perfect = g_value_get_boolean (value); + case PROP_TS_OFFSET: + identity->ts_offset = g_value_get_int64 (value); break; case PROP_CHECK_IMPERFECT_TIMESTAMP: identity->check_imperfect_timestamp = g_value_get_boolean (value); @@ -780,10 +766,17 @@ gst_identity_set_property (GObject * object, guint prop_id, case PROP_SIGNAL_HANDOFFS: identity->signal_handoffs = g_value_get_boolean (value); break; + case PROP_DROP_ALLOCATION: + identity->drop_allocation = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } + if (identity->datarate > 0 || identity->single_segment) + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), FALSE); + else + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (identity), TRUE); } static void @@ -804,6 +797,9 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DROP_PROBABILITY: g_value_set_float (value, identity->drop_probability); break; + case PROP_DROP_BUFFER_FLAGS: + g_value_set_flags (value, identity->drop_buffer_flags); + break; case PROP_DATARATE: g_value_set_int (value, identity->datarate); break; @@ -824,8 +820,8 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SYNC: g_value_set_boolean (value, identity->sync); break; - case PROP_CHECK_PERFECT: - g_value_set_boolean (value, identity->check_perfect); + case PROP_TS_OFFSET: + identity->ts_offset = g_value_get_int64 (value); break; case PROP_CHECK_IMPERFECT_TIMESTAMP: g_value_set_boolean (value, identity->check_imperfect_timestamp); @@ -836,6 +832,9 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SIGNAL_HANDOFFS: g_value_set_boolean (value, identity->signal_handoffs); break; + case PROP_DROP_ALLOCATION: + g_value_set_boolean (value, identity->drop_allocation); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -873,27 +872,105 @@ gst_identity_stop (GstBaseTransform * trans) return TRUE; } +static gboolean +gst_identity_accept_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps) +{ + gboolean ret; + GstPad *pad; + + /* Proxy accept-caps */ + + if (direction == GST_PAD_SRC) + pad = GST_BASE_TRANSFORM_SINK_PAD (base); + else + pad = GST_BASE_TRANSFORM_SRC_PAD (base); + + ret = gst_pad_peer_query_accept_caps (pad, caps); + + return ret; +} + +static gboolean +gst_identity_query (GstBaseTransform * base, GstPadDirection direction, + GstQuery * query) +{ + GstIdentity *identity; + gboolean ret; + + identity = GST_IDENTITY (base); + + if (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION && + identity->drop_allocation) { + GST_DEBUG_OBJECT (identity, "Dropping allocation query."); + return FALSE; + } + + ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (base, direction, query); + + if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) { + gboolean live = FALSE; + GstClockTime min = 0, max = 0; + + if (ret) { + gst_query_parse_latency (query, &live, &min, &max); + + if (identity->sync && max < min) { + GST_ELEMENT_WARNING (base, CORE, CLOCK, (NULL), + ("Impossible to configure latency before identity sync=true:" + " max %" GST_TIME_FORMAT " < min %" + GST_TIME_FORMAT ". Add queues or other buffering elements.", + GST_TIME_ARGS (max), GST_TIME_ARGS (min))); + } + } + + /* Ignore the upstream latency if it is not live */ + GST_OBJECT_LOCK (identity); + if (live) + identity->upstream_latency = min; + else + identity->upstream_latency = 0; + GST_OBJECT_UNLOCK (identity); + + gst_query_set_latency (query, live || identity->sync, min, max); + ret = TRUE; + } + return ret; +} + static GstStateChangeReturn gst_identity_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstIdentity *identity = GST_IDENTITY (element); + gboolean no_preroll = FALSE; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_OBJECT_LOCK (identity); + identity->flushing = FALSE; + identity->blocked = TRUE; + GST_OBJECT_UNLOCK (identity); + if (identity->sync) + no_preroll = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_OBJECT_LOCK (identity); + identity->blocked = FALSE; + g_cond_broadcast (&identity->blocked_cond); + GST_OBJECT_UNLOCK (identity); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (identity); + identity->flushing = TRUE; if (identity->clock_id) { GST_DEBUG_OBJECT (identity, "unlock clock wait"); gst_clock_id_unschedule (identity->clock_id); - gst_clock_id_unref (identity->clock_id); - identity->clock_id = NULL; } + identity->blocked = FALSE; + g_cond_broadcast (&identity->blocked_cond); GST_OBJECT_UNLOCK (identity); break; default: @@ -904,6 +981,12 @@ gst_identity_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_OBJECT_LOCK (identity); + identity->upstream_latency = 0; + identity->blocked = TRUE; + GST_OBJECT_UNLOCK (identity); + if (identity->sync) + no_preroll = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; @@ -913,5 +996,8 @@ gst_identity_change_state (GstElement * element, GstStateChange transition) break; } + if (no_preroll && ret == GST_STATE_CHANGE_SUCCESS) + ret = GST_STATE_CHANGE_NO_PREROLL; + return ret; }