[FFmpeg-cvslog] vp8: fix overflow in segmentation map caching.

Ronald S. Bultje git at videolan.org
Sun Oct 30 02:04:11 CEST 2011


ffmpeg | branch: master | Ronald S. Bultje <rsbultje at gmail.com> | Fri Oct 28 23:48:43 2011 -0700| [bfa0f96586fe2c257cfa574ffb991da493a54da1] | committer: Ronald S. Bultje

vp8: fix overflow in segmentation map caching.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=bfa0f96586fe2c257cfa574ffb991da493a54da1
---

 libavcodec/vp8.c |   48 ++++++++++++++++++++++++++++++------------------
 1 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index 95755e3..836176d 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -50,7 +50,8 @@ static int vp8_alloc_frame(VP8Context *s, AVFrame *f)
     int ret;
     if ((ret = ff_thread_get_buffer(s->avctx, f)) < 0)
         return ret;
-    if (!s->maps_are_invalid && s->num_maps_to_be_freed) {
+    if (s->num_maps_to_be_freed) {
+        assert(!s->maps_are_invalid);
         f->ref_index[0] = s->segmentation_maps[--s->num_maps_to_be_freed];
     } else if (!(f->ref_index[0] = av_mallocz(s->mb_width * s->mb_height))) {
         ff_thread_release_buffer(s->avctx, f);
@@ -59,39 +60,50 @@ static int vp8_alloc_frame(VP8Context *s, AVFrame *f)
     return 0;
 }
 
-static void vp8_release_frame(VP8Context *s, AVFrame *f, int is_close)
+static void vp8_release_frame(VP8Context *s, AVFrame *f, int prefer_delayed_free, int can_direct_free)
 {
-    if (!is_close) {
-        if (f->ref_index[0]) {
-            assert(s->num_maps_to_be_freed < FF_ARRAY_ELEMS(s->segmentation_maps));
-            s->segmentation_maps[s->num_maps_to_be_freed++] = f->ref_index[0];
+    if (f->ref_index[0]) {
+        if (prefer_delayed_free) {
+            /* Upon a size change, we want to free the maps but other threads may still
+             * be using them, so queue them. Upon a seek, all threads are inactive so
+             * we want to cache one to prevent re-allocation in the next decoding
+             * iteration, but the rest we can free directly. */
+            int max_queued_maps = can_direct_free ? 1 : FF_ARRAY_ELEMS(s->segmentation_maps);
+            if (s->num_maps_to_be_freed < max_queued_maps) {
+                s->segmentation_maps[s->num_maps_to_be_freed++] = f->ref_index[0];
+            } else if (can_direct_free) /* vp8_decode_flush(), but our queue is full */ {
+                av_free(f->ref_index[0]);
+            } /* else: MEMLEAK (should never happen, but better that than crash) */
             f->ref_index[0] = NULL;
+        } else /* vp8_decode_free() */ {
+            av_free(f->ref_index[0]);
         }
-    } else {
-        av_freep(&f->ref_index[0]);
     }
     ff_thread_release_buffer(s->avctx, f);
 }
 
-static void vp8_decode_flush_impl(AVCodecContext *avctx, int force, int is_close)
+static void vp8_decode_flush_impl(AVCodecContext *avctx,
+                                  int prefer_delayed_free, int can_direct_free, int free_mem)
 {
     VP8Context *s = avctx->priv_data;
     int i;
 
-    if (!avctx->is_copy || force) {
+    if (!avctx->is_copy) {
         for (i = 0; i < 5; i++)
             if (s->frames[i].data[0])
-                vp8_release_frame(s, &s->frames[i], is_close);
+                vp8_release_frame(s, &s->frames[i], prefer_delayed_free, can_direct_free);
     }
     memset(s->framep, 0, sizeof(s->framep));
 
-    free_buffers(s);
-    s->maps_are_invalid = 1;
+    if (free_mem) {
+        free_buffers(s);
+        s->maps_are_invalid = 1;
+    }
 }
 
 static void vp8_decode_flush(AVCodecContext *avctx)
 {
-    vp8_decode_flush_impl(avctx, 0, 0);
+    vp8_decode_flush_impl(avctx, 1, 1, 0);
 }
 
 static int update_dimensions(VP8Context *s, int width, int height)
@@ -101,7 +113,7 @@ static int update_dimensions(VP8Context *s, int width, int height)
         if (av_image_check_size(width, height, 0, s->avctx))
             return AVERROR_INVALIDDATA;
 
-        vp8_decode_flush_impl(s->avctx, 1, 0);
+        vp8_decode_flush_impl(s->avctx, 1, 0, 1);
 
         avcodec_set_dimensions(s->avctx, width, height);
     }
@@ -1580,7 +1592,7 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
             &s->frames[i] != s->framep[VP56_FRAME_PREVIOUS] &&
             &s->frames[i] != s->framep[VP56_FRAME_GOLDEN] &&
             &s->frames[i] != s->framep[VP56_FRAME_GOLDEN2])
-            vp8_release_frame(s, &s->frames[i], 0);
+            vp8_release_frame(s, &s->frames[i], 1, 0);
 
     // find a free buffer
     for (i = 0; i < 5; i++)
@@ -1596,7 +1608,7 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
         abort();
     }
     if (curframe->data[0])
-        ff_thread_release_buffer(avctx, curframe);
+        vp8_release_frame(s, curframe, 1, 0);
 
     curframe->key_frame = s->keyframe;
     curframe->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
@@ -1777,7 +1789,7 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx)
 
 static av_cold int vp8_decode_free(AVCodecContext *avctx)
 {
-    vp8_decode_flush_impl(avctx, 0, 1);
+    vp8_decode_flush_impl(avctx, 0, 1, 1);
     release_queued_segmaps(avctx->priv_data, 1);
     return 0;
 }



More information about the ffmpeg-cvslog mailing list