From: Xidorn Quan <[email protected]>

Fix a buffer leak when seeking occurs.
Add a flag in struct vda_context for backward compatibility.
If the flag is not set, the hwaccel will behave like before.

Signed-off-by: Luca Barbato <[email protected]>
---

Anton comments aren't really addressed, I'd push it if somebody doesn't
have a better idea soon. Leaking is worse than an vaguely hacky solution.

 libavcodec/vda.h      | 11 +++++++++++
 libavcodec/vda_h264.c | 38 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/libavcodec/vda.h b/libavcodec/vda.h
index 987b94f..5d6af5c 100644
--- a/libavcodec/vda.h
+++ b/libavcodec/vda.h
@@ -125,6 +125,17 @@ struct vda_context {
      * The reference size used for fast reallocation.
      */
     int                 priv_allocated_size;
+
+    /**
+     * Use av_buffer to manage buffer.
+     * When the flag is set, the CVPixelBuffers returned by the decoder will
+     * be released automatically, so you have to retain them if necessary.
+     * Not setting this flag may cause a memory leak.
+     *
+     * encoding: unused
+     * decoding: Set by user.
+     */
+    int                 use_ref_buffer;
 };

 /** Create the video decoder. */
diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c
index 6c1845a..b0d95a8 100644
--- a/libavcodec/vda_h264.c
+++ b/libavcodec/vda_h264.c
@@ -107,12 +107,19 @@ static int vda_h264_decode_slice(AVCodecContext *avctx,
     return 0;
 }

+static void vda_h264_release_buffer(void *opaque, uint8_t *data)
+{
+    CVPixelBufferRef cv_buffer = opaque;
+    CVPixelBufferRelease(cv_buffer);
+}
+
 static int vda_h264_end_frame(AVCodecContext *avctx)
 {
     H264Context *h                      = avctx->priv_data;
     struct vda_context *vda_ctx         = avctx->hwaccel_context;
     AVFrame *frame                      = &h->cur_pic_ptr->f;
-    int status;
+    AVBufferRef *buffer;
+    int status, i;

     if (!vda_ctx->decoder || !vda_ctx->priv_bitstream)
         return -1;
@@ -123,6 +130,35 @@ static int vda_h264_end_frame(AVCodecContext *avctx)
     if (status)
         av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);

+    if (!vda_ctx->use_ref_buffer || status)
+        return status;
+
+    buffer = NULL;
+
+    /* VDA workaround to properly release each core video buffer:
+     * we need to create an extra av_buffer with a custom freeing callback.
+     * This extra buffer should not be reference-counted to avoid potential
+     * memory leaks. That's why we put it after the first free entry of
+     * AVFrame.buf to not reference this extra buffer in
+     * AVFrame.av_frame_ref(). */
+    for (i = 1; i < AV_NUM_DATA_POINTERS; i++) {
+        if (!frame->buf[i] && !frame->buf[i-1]) {
+            buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer,
+                                      vda_ctx->cv_buffer, 0);
+            if (!buffer) {
+                CVPixelBufferRelease(vda_ctx->cv_buffer);
+                return -1;
+            }
+            frame->buf[i] = buffer;
+            break;
+        }
+    }
+
+    if (!buffer) {
+        CVPixelBufferRelease(vda_ctx->cv_buffer);
+        return -1;
+    }
+
     return status;
 }

--
1.8.2.1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to