[Spice-devel] [PATCH v5 18/20] spice-gtk: Avoid copying the compressed message data in the GStreamer decoder.
Christophe Fergeau
cfergeau at redhat.com
Mon Sep 21 08:07:51 PDT 2015
On Thu, Aug 27, 2015 at 09:03:09PM +0200, Francois Gouget wrote:
> Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
> ---
>
> Changes since take 2:
> - None.
>
> src/channel-display-gst.c | 89 ++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 84 insertions(+), 5 deletions(-)
>
> diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
> index 3024356..59ce3e1 100644
> --- a/src/channel-display-gst.c
> +++ b/src/channel-display-gst.c
> @@ -48,11 +48,43 @@ struct GstDecoder {
>
> /* ---------- Output frame data ---------- */
>
> + GMutex pipeline_mutex;
> + GCond pipeline_cond;
> + int pipeline_wait;
Could be a gboolean from the look of it.
> + uint32_t samples_count;
> +
> GstSample *sample;
> GstMapInfo mapinfo;
> };
>
>
> +/* Signals that the pipeline is done processing the last buffer we gave it.
> + *
> + * @decoder: The video decoder object.
> + * @samples: How many samples to add to the available samples count.
> + */
> +static void signal_pipeline(GstDecoder *decoder, uint32_t samples)
> +{
> + g_mutex_lock(&decoder->pipeline_mutex);
> + decoder->pipeline_wait = 0;
> + decoder->samples_count += samples;
> + g_cond_signal(&decoder->pipeline_cond);
> + g_mutex_unlock(&decoder->pipeline_mutex);
> +}
> +
> +static void appsrc_need_data_cb(GstAppSrc *src, guint length, gpointer user_data)
> +{
> + GstDecoder *decoder = (GstDecoder*)user_data;
> + signal_pipeline(decoder, 0);
> +}
> +
> +static GstFlowReturn appsink_new_sample_cb(GstAppSink *appsrc, gpointer user_data)
> +{
> + GstDecoder *decoder = (GstDecoder*)user_data;
> + signal_pipeline(decoder, 1);
> + return GST_FLOW_OK;
> +}
> +
> /* ---------- GStreamer pipeline ---------- */
>
> static void reset_pipeline(GstDecoder *decoder)
> @@ -66,10 +98,18 @@ static void reset_pipeline(GstDecoder *decoder)
> gst_object_unref(decoder->appsink);
> gst_object_unref(decoder->pipeline);
> decoder->pipeline = NULL;
> +
> + g_mutex_clear(&decoder->pipeline_mutex);
> + g_cond_clear(&decoder->pipeline_cond);
> }
>
> static gboolean construct_pipeline(GstDecoder *decoder)
> {
> + g_mutex_init(&decoder->pipeline_mutex);
> + g_cond_init(&decoder->pipeline_cond);
These symbols are not available in el6 glib2, so we'll need to add a compat
implementation for them somehow, but we can fix it later.
> + decoder->pipeline_wait = 1;
> + decoder->samples_count = 0;
> +
> const gchar *src_caps, *gstdec_name;
> switch (decoder->base.codec_type) {
> case SPICE_VIDEO_CODEC_TYPE_MJPEG:
> @@ -101,7 +141,12 @@ static gboolean construct_pipeline(GstDecoder *decoder)
> }
>
> decoder->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "src"));
> + GstAppSrcCallbacks appsrc_cbs = {&appsrc_need_data_cb, NULL, NULL};
> + gst_app_src_set_callbacks(decoder->appsrc, &appsrc_cbs, decoder, NULL);
> +
> decoder->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "sink"));
> + GstAppSinkCallbacks appsink_cbs = {NULL, NULL, &appsink_new_sample_cb};
> + gst_app_sink_set_callbacks(decoder->appsink, &appsink_cbs, decoder, NULL);
>
> if (gst_element_set_state(decoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
> SPICE_DEBUG("GStreamer error: Unable to set the pipeline to the playing state.");
> @@ -112,6 +157,11 @@ static gboolean construct_pipeline(GstDecoder *decoder)
> return TRUE;
> }
>
> +static void release_msg_in(gpointer data)
> +{
> + spice_msg_in_unref((SpiceMsgIn*)data);
> +}
> +
> static gboolean push_compressed_buffer(GstDecoder *decoder,
> SpiceMsgIn *frame_msg)
> {
> @@ -122,10 +172,11 @@ static gboolean push_compressed_buffer(GstDecoder *decoder,
> return FALSE;
> }
>
> - // TODO. Grr. Seems like a wasted alloc
> - gpointer d = g_malloc(size);
> - memcpy(d, data, size);
> - GstBuffer *buffer = gst_buffer_new_wrapped(d, size);
> + /* Reference frame_msg so it stays around until our 'deallocator' releases it */
> + spice_msg_in_ref(frame_msg);
> + GstBuffer *buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY,
> + data, size, 0, size,
> + frame_msg, &release_msg_in);
>
> if (gst_app_src_push_buffer(decoder->appsrc, buffer) != GST_FLOW_OK) {
> SPICE_DEBUG("GStreamer error: unable to push frame of size %d", size);
> @@ -195,8 +246,36 @@ static uint8_t* gst_decoder_decode_frame(GstDecoder *decoder,
> */
> release_last_frame(decoder);
>
> + /* The pipeline may have called appsrc_need_data_cb() after we got the last
> + * output frame. This would cause us to return prematurely so reset
> + * pipeline_wait so we do wait for it to process this buffer.
> + */
> + g_mutex_lock(&decoder->pipeline_mutex);
> + decoder->pipeline_wait = 1;
> + g_mutex_unlock(&decoder->pipeline_mutex);
> + /* Note that it's possible for appsrc_need_data_cb() to get called between
> + * now and the pipeline wait. But this will at most cause a one frame delay.
> + */
> +
> if (push_compressed_buffer(decoder, frame_msg)) {
> - return pull_raw_frame(decoder);
> + /* Wait for the pipeline to either produce a decoded frame, or ask
> + * for more data which means an error happened.
> + */
> + g_mutex_lock(&decoder->pipeline_mutex);
> + while (decoder->pipeline_wait) {
> + g_cond_wait(&decoder->pipeline_cond, &decoder->pipeline_mutex);
> + }
> + decoder->pipeline_wait = 1;
> + uint32_t samples = decoder->samples_count;
> + if (samples) {
> + decoder->samples_count--;
> + }
> + g_mutex_unlock(&decoder->pipeline_mutex);
> +
> + /* If a decoded frame waits for us, return it */
> + if (samples) {
> + return pull_raw_frame(decoder);
> + }
> }
> return NULL;
Always worried to add some threading, but looks ok :)
Christophe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20150921/ada1f963/attachment.sig>
More information about the Spice-devel
mailing list