Currently we set timestamps as buffer's PTS, this value may be changed by the pipeline in some cases and cause an unexpected buffer warnings (when GstVideoOverlay is not used). Use GstReferenceTimestampMeta when synchronization is made by spice. Before applying this patch you can reproduce the warnings by runing with DISABLE_GSTVIDEOOVERLAY=1 and starting some audio playback in the guest. Signed-off-by: Snir Sheriber <ssheribe@xxxxxxxxxx> --- Changes from v2: -Use buffer's PTS value, if GstReferenceTimestampMeta exists, use its timestamp instead. --- src/channel-display-gst.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c index 2f556fe..a281032 100644 --- a/src/channel-display-gst.c +++ b/src/channel-display-gst.c @@ -33,6 +33,10 @@ typedef struct SpiceGstFrame SpiceGstFrame; /* GStreamer decoder implementation */ +#if GST_CHECK_VERSION(1,14,0) +static GstStaticCaps stream_reference = GST_STATIC_CAPS("timestamp/spice-stream"); +#endif + typedef struct SpiceGstDecoder { VideoDecoder base; @@ -86,7 +90,16 @@ struct SpiceGstFrame { static SpiceGstFrame *create_gst_frame(GstBuffer *buffer, SpiceFrame *frame) { SpiceGstFrame *gstframe = g_new(SpiceGstFrame, 1); + gstframe->timestamp = GST_BUFFER_PTS(buffer); +#if GST_CHECK_VERSION(1,14,0) + GstReferenceTimestampMeta *time_meta; + + time_meta = gst_buffer_get_reference_timestamp_meta(buffer, gst_static_caps_get(&stream_reference)); + if (time_meta) { + gstframe->timestamp = time_meta->timestamp; + } +#endif gstframe->frame = frame; gstframe->sample = NULL; return gstframe; @@ -211,6 +224,15 @@ static void fetch_pending_sample(SpiceGstDecoder *decoder) decoder->pending_samples--; GstBuffer *buffer = gst_sample_get_buffer(sample); + GstClockTime buffer_ts = GST_BUFFER_PTS(buffer); +#if GST_CHECK_VERSION(1,14,0) + GstReferenceTimestampMeta *time_meta; + + time_meta = gst_buffer_get_reference_timestamp_meta(buffer, gst_static_caps_get(&stream_reference)); + if (time_meta) { + buffer_ts = time_meta->timestamp; + } +#endif /* gst_app_sink_pull_sample() sometimes returns the same buffer twice * or buffers that have a modified, and thus unrecognizable, PTS. @@ -223,7 +245,7 @@ static void fetch_pending_sample(SpiceGstDecoder *decoder) GList *l = g_queue_peek_head_link(decoder->decoding_queue); while (l) { gstframe = l->data; - if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) { + if (gstframe->timestamp == buffer_ts) { /* The frame is now ready for display */ gstframe->sample = sample; decoder->display_frame = gstframe; @@ -232,7 +254,7 @@ static void fetch_pending_sample(SpiceGstDecoder *decoder) * frames from the decoding queue. */ while ((gstframe = g_queue_pop_head(decoder->decoding_queue))) { - if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) { + if (gstframe->timestamp == buffer_ts) { break; } /* The GStreamer pipeline dropped the corresponding @@ -626,9 +648,13 @@ static gboolean spice_gst_decoder_queue_frame(VideoDecoder *video_decoder, frame->data, frame->size, 0, frame->size, frame->data_opaque, frame->unref_data); + GstClockTime pts = gst_clock_get_time(decoder->clock) - gst_element_get_base_time(decoder->pipeline) + ((uint64_t)MAX(0, latency)) * 1000 * 1000; GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DTS(buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_PTS(buffer) = gst_clock_get_time(decoder->clock) - gst_element_get_base_time(decoder->pipeline) + ((uint64_t)MAX(0, latency)) * 1000 * 1000; + GST_BUFFER_PTS(buffer) = pts; +#if GST_CHECK_VERSION(1,14,0) + gst_buffer_add_reference_timestamp_meta(buffer, gst_static_caps_get (&stream_reference), pts, GST_CLOCK_TIME_NONE); +#endif if (decoder->appsink != NULL) { SpiceGstFrame *gst_frame = create_gst_frame(buffer, frame); -- 2.19.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel