decoder: fix memory leak when processing interlaced pictures.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 11 Jun 2013 13:11:34 +0000 (15:11 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 15 Jul 2013 12:01:06 +0000 (14:01 +0200)
Fix memory leak when processing interlaced pictures and that occurs
because the first field, represented as a GstVideoCodecFrame, never
gets released. i.e. when the picture is completed, this is generally
the case when the second field is successfully decoded, we need to
propagate the GstVideoCodecFrame of the first field to the original
GstVideoDecoder so that it could reclaim memory.

Otherwise, we keep accumulating the first fields into GstVideoDecoder
private frames list until the end-of-stream is reached. The frames
are eventually released there, but too late, i.e. too much memory
may have been consumed.

https://bugzilla.gnome.org/show_bug.cgi?id=701257

gst-libs/gst/vaapi/gstvaapidecoder_objects.c
gst-libs/gst/vaapi/gstvaapidecoder_objects.h

index 92f0f7bbd9345e81c7447fccb6e81bcc57c13954..4b5213498519bacc68d1329f795a550124375ced 100644 (file)
@@ -86,6 +86,7 @@ gst_vaapi_picture_destroy(GstVaapiPicture *picture)
         gst_video_codec_frame_unref(picture->frame);
         picture->frame = NULL;
     }
+    gst_vaapi_picture_replace(&picture->parent_picture, NULL);
 }
 
 gboolean
@@ -99,6 +100,8 @@ gst_vaapi_picture_create(
     if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) {
         GstVaapiPicture * const parent_picture = GST_VAAPI_PICTURE(args->data);
 
+        picture->parent_picture = gst_vaapi_picture_ref(parent_picture);
+
         picture->proxy   = gst_vaapi_surface_proxy_ref(parent_picture->proxy);
         picture->type    = parent_picture->type;
         picture->pts     = parent_picture->pts;
@@ -300,14 +303,15 @@ gst_vaapi_picture_decode(GstVaapiPicture *picture)
     return TRUE;
 }
 
-gboolean
-gst_vaapi_picture_output(GstVaapiPicture *picture)
+static gboolean
+do_output(GstVaapiPicture *picture)
 {
     GstVideoCodecFrame * const out_frame = picture->frame;
     GstVaapiSurfaceProxy *proxy;
     guint flags = 0;
 
-    g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
+    if (GST_VAAPI_PICTURE_IS_OUTPUT(picture))
+        return TRUE;
 
     if (!picture->proxy)
         return FALSE;
@@ -339,6 +343,30 @@ gst_vaapi_picture_output(GstVaapiPicture *picture)
     return TRUE;
 }
 
+gboolean
+gst_vaapi_picture_output(GstVaapiPicture *picture)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
+
+    if (G_UNLIKELY(picture->parent_picture)) {
+        /* Emit the first field to GstVideoDecoder so that to release
+           the underlying GstVideoCodecFrame. However, mark this
+           picture as skipped so that to not display it */
+        GstVaapiPicture * const parent_picture = picture->parent_picture;
+        do {
+            if (!GST_VAAPI_PICTURE_IS_INTERLACED(parent_picture))
+                break;
+            if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD(parent_picture))
+                break;
+            GST_VAAPI_PICTURE_FLAG_SET(parent_picture,
+                GST_VAAPI_PICTURE_FLAG_SKIPPED);
+            if (!do_output(parent_picture))
+                return FALSE;
+        } while (0);
+    }
+    return do_output(picture);
+}
+
 void
 gst_vaapi_picture_set_crop_rect(GstVaapiPicture *picture,
     const GstVaapiRectangle *crop_rect)
index 9bc2436cf7912305e84fead6530e6a662c0dcea7..90e8f04258412ac49c8a3a6d1d99530de88aa0fe 100644 (file)
@@ -114,6 +114,7 @@ typedef enum {
 struct _GstVaapiPicture {
     /*< private >*/
     GstVaapiCodecObject         parent_instance;
+    GstVaapiPicture            *parent_picture;
     GstVideoCodecFrame         *frame;
     GstVaapiSurface            *surface;
     GstVaapiSurfaceProxy       *proxy;