[Spice-devel] [PATCH spice-gtk 2/3] channel-display-gst: factor out get_decoded_frame

Frediano Ziglio fziglio at redhat.com
Wed Jan 23 13:11:17 UTC 2019


> 
> Hi,
> 
> On Wed, Jan 23, 2019 at 12:08:53AM +0000, Frediano Ziglio wrote:
> > Separate the code from fetch_pending_sample that extracts the
> > SpiceGstFrame relative to a give GstBuffer.
> > This new function will be reused later.
> > 
> > Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> > ---
> >  src/channel-display-gst.c | 84 ++++++++++++++++++++++++---------------
> >  1 file changed, 53 insertions(+), 31 deletions(-)
> > 
> > diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
> > index 1ad06f15..08c9f8fb 100644
> > --- a/src/channel-display-gst.c
> > +++ b/src/channel-display-gst.c
> > @@ -107,6 +107,7 @@ static void free_gst_frame(SpiceGstFrame *gstframe)
> >  
> >  static void schedule_frame(SpiceGstDecoder *decoder);
> >  static void fetch_pending_sample(SpiceGstDecoder *decoder);
> > +static SpiceGstFrame *get_decoded_frame(SpiceGstDecoder *decoder,
> > GstBuffer *buffer);
> >  
> >  static int spice_gst_buffer_get_stride(GstBuffer *buffer)
> >  {
> > @@ -204,6 +205,52 @@ static void schedule_frame(SpiceGstDecoder *decoder)
> >      g_mutex_unlock(&decoder->queues_mutex);
> >  }
> >  
> > +/* Get the decoded frame relative to buffer or NULL if not found.
> > + * Dequeue the frame from decoding_queue and return it, caller
> > + * is responsible to free the pointer.
> > + * queues_mutex must be held.
> > + */
> > +static SpiceGstFrame *get_decoded_frame(SpiceGstDecoder *decoder,
> > GstBuffer *buffer)
> > +{
> > +    guint num_frames_dropped = 0;
> > +
> > +    /* Gstreamer sometimes returns the same buffer twice
> > +     * or buffers that have a modified, and thus unrecognizable, PTS.
> > +     * Blindly removing frames from the decoding_queue until we find a
> > +     * match would only empty the queue, resulting in later buffers not
> > +     * finding a match either, etc. So check the buffer has a matching
> > +     * frame first.
> > +     */
> > +    SpiceGstFrame *gstframe = NULL;
> > +    GList *l = g_queue_peek_head_link(decoder->decoding_queue);
> 
> (1)
> I'm a bit confused. Here, g_queue_peek_head_link() gives the
> pointer to the head, without removing it from the queue.
> 
> > +    while (l) {
> > +        gstframe = l->data;
> > +        if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) {
> 
> (2)
> Here we check if payload of the queue. If yes, then
> 
> > +            /* Now that we know there is a match, remove it and the older
> > +             * frames from the decoding queue.
> > +             */
> > +            while ((gstframe = g_queue_pop_head(decoder->decoding_queue)))
> > {
> 
> It gets the same pointer, because still is the head as it was not
> popped above on (1).
> 
> > +                if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) {
> > +                    break;
> 
> It should reach this break for the same reason we are in this
> code path due check on (2)
> 

All these are not changed, I just factored out a function.
Yes, can be surely be optimized or changed.

> > +                }
> > +                /* The GStreamer pipeline dropped the corresponding
> > +                 * buffer.
> > +                 */
> > +                num_frames_dropped++;
> > +                free_gst_frame(gstframe);
> > +            }
> > +            break;
> 
> Considering that gstframe might have changed after entering in
> (2), we are breaking the while (l) loop with dangling pointer and
> returning that.
> 

No, see the "queues_mutex must be held" comment.

> > +        }
> > +        gstframe = NULL;
> > +        l = l->next;
> > +    }
> > +    if (num_frames_dropped != 0) {
> > +        SPICE_DEBUG("the GStreamer pipeline dropped %u frames",
> > num_frames_dropped);
> > +    }
> > +    return gstframe;
> > +}
> > +
> >  static void fetch_pending_sample(SpiceGstDecoder *decoder)
> >  {
> >      GstSample *sample = gst_app_sink_pull_sample(decoder->appsink);
> > @@ -212,7 +259,6 @@ static void fetch_pending_sample(SpiceGstDecoder
> > *decoder)
> >          decoder->pending_samples--;
> >  
> >          GstBuffer *buffer = gst_sample_get_buffer(sample);
> > -        guint num_frames_dropped = 0;
> >  
> >          /* gst_app_sink_pull_sample() sometimes returns the same buffer
> >          twice
> >           * or buffers that have a modified, and thus unrecognizable, PTS.
> > @@ -221,36 +267,12 @@ static void fetch_pending_sample(SpiceGstDecoder
> > *decoder)
> >           * finding a match either, etc. So check the buffer has a matching
> >           * frame first.
> >           */
> > -        SpiceGstFrame *gstframe;
> > -        GList *l = g_queue_peek_head_link(decoder->decoding_queue);
> 
> You did not introduced what I consider to be my confusion (as this
> code seems to be working fine).
> 
> > -        while (l) {
> > -            gstframe = l->data;
> > -            if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) {
> > -                /* The frame is now ready for display */
> > -                gstframe->decoded_sample = sample;
> > -                decoder->display_frame = gstframe;
> > -
> > -                /* Now that we know there is a match, remove it and the
> > older
> > -                 * frames from the decoding queue.
> > -                 */
> > -                while ((gstframe =
> > g_queue_pop_head(decoder->decoding_queue))) {
> > -                    if (gstframe->timestamp == GST_BUFFER_PTS(buffer)) {
> > -                        break;
> > -                    }
> 
> Same
> 
> > -                    /* The GStreamer pipeline dropped the corresponding
> > -                     * buffer.
> > -                     */
> > -                    num_frames_dropped++;
> > -                    free_gst_frame(gstframe);
> > -                }
> > -                break;
> > -            }
> > -            l = l->next;
> > -        }
> > -        if (num_frames_dropped != 0) {
> > -            SPICE_DEBUG("the GStreamer pipeline dropped %u frames",
> > num_frames_dropped);
> > -        }
> > -        if (!l) {
> > +        SpiceGstFrame *gstframe = get_decoded_frame(decoder, buffer);
> > +        if (gstframe) {
> > +            /* The frame is now ready for display */
> > +            gstframe->decoded_sample = sample;
> > +            decoder->display_frame = gstframe;
> > +        } else {
> 
> Cheers,
> Victor
> 


More information about the Spice-devel mailing list