Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavcodec / vp8.c
index 2643b34..b374fa4 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "libavutil/imgutils.h"
 #include "avcodec.h"
+#include "internal.h"
 #include "vp8.h"
 #include "vp8data.h"
 #include "rectangle.h"
@@ -41,24 +42,69 @@ static void free_buffers(VP8Context *s)
     av_freep(&s->top_nnz);
     av_freep(&s->edge_emu_buffer);
     av_freep(&s->top_border);
-    av_freep(&s->segmentation_map);
 
     s->macroblocks = NULL;
 }
 
-static void vp8_decode_flush(AVCodecContext *avctx)
+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->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);
+        return AVERROR(ENOMEM);
+    }
+    return 0;
+}
+
+static void vp8_release_frame(VP8Context *s, AVFrame *f, int prefer_delayed_free, int can_direct_free)
+{
+    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]);
+        }
+    }
+    ff_thread_release_buffer(s->avctx, f);
+}
+
+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) {
+    if (!avctx->internal->is_copy) {
         for (i = 0; i < 5; i++)
             if (s->frames[i].data[0])
-                ff_thread_release_buffer(avctx, &s->frames[i]);
+                vp8_release_frame(s, &s->frames[i], prefer_delayed_free, can_direct_free);
     }
     memset(s->framep, 0, sizeof(s->framep));
 
-    free_buffers(s);
+    if (free_mem) {
+        free_buffers(s);
+        s->maps_are_invalid = 1;
+    }
+}
+
+static void vp8_decode_flush(AVCodecContext *avctx)
+{
+    vp8_decode_flush_impl(avctx, 1, 1, 0);
 }
 
 static int update_dimensions(VP8Context *s, int width, int height)
@@ -68,7 +114,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(s->avctx);
+        vp8_decode_flush_impl(s->avctx, 1, 0, 1);
 
         avcodec_set_dimensions(s->avctx, width, height);
     }
@@ -81,10 +127,9 @@ static int update_dimensions(VP8Context *s, int width, int height)
     s->intra4x4_pred_mode_top  = av_mallocz(s->mb_width*4);
     s->top_nnz                 = av_mallocz(s->mb_width*sizeof(*s->top_nnz));
     s->top_border              = av_mallocz((s->mb_width+1)*sizeof(*s->top_border));
-    s->segmentation_map        = av_mallocz(s->mb_width*s->mb_height);
 
     if (!s->macroblocks_base || !s->filter_strength || !s->intra4x4_pred_mode_top ||
-        !s->top_nnz || !s->top_border || !s->segmentation_map)
+        !s->top_nnz || !s->top_border)
         return AVERROR(ENOMEM);
 
     s->macroblocks        = s->macroblocks_base + 1;
@@ -595,9 +640,10 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y, uint8_
 {
     VP56RangeCoder *c = &s->c;
 
-    if (s->segmentation.update_map)
-        *segment = vp8_rac_get_tree(c, vp8_segmentid_tree, s->prob->segmentid);
-    else
+    if (s->segmentation.update_map) {
+        int bit  = vp56_rac_get_prob(c, s->prob->segmentid[0]);
+        *segment = vp56_rac_get_prob(c, s->prob->segmentid[1+bit]) + 2*bit;
+    } else
         *segment = ref ? *ref : *segment;
     s->segment = *segment;
 
@@ -1508,6 +1554,14 @@ static void filter_mb_row_simple(VP8Context *s, AVFrame *curframe, int mb_y)
     }
 }
 
+static void release_queued_segmaps(VP8Context *s, int is_close)
+{
+    int leave_behind = is_close ? 0 : !s->maps_are_invalid;
+    while (s->num_maps_to_be_freed > leave_behind)
+        av_freep(&s->segmentation_maps[--s->num_maps_to_be_freed]);
+    s->maps_are_invalid = 0;
+}
+
 static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                             AVPacket *avpkt)
 {
@@ -1516,6 +1570,8 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
     enum AVDiscard skip_thresh;
     AVFrame *av_uninit(curframe), *prev_frame = s->framep[VP56_FRAME_CURRENT];
 
+    release_queued_segmaps(s, 0);
+
     if ((ret = decode_frame_header(s, avpkt->data, avpkt->size)) < 0)
         return ret;
 
@@ -1538,7 +1594,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])
-            ff_thread_release_buffer(avctx, &s->frames[i]);
+            vp8_release_frame(s, &s->frames[i], 1, 0);
 
     // find a free buffer
     for (i = 0; i < 5; i++)
@@ -1554,13 +1610,12 @@ 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;
     curframe->reference = referenced ? 3 : 0;
-    curframe->ref_index[0] = s->segmentation_map;
-    if ((ret = ff_thread_get_buffer(avctx, curframe))) {
+    if ((ret = vp8_alloc_frame(s, curframe))) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed!\n");
         return ret;
     }
@@ -1652,8 +1707,8 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
             s->dsp.prefetch(dst[0] + (mb_x&3)*4*s->linesize + 64, s->linesize, 4);
             s->dsp.prefetch(dst[1] + (mb_x&7)*s->uvlinesize + 64, dst[2] - dst[1], 2);
 
-            decode_mb_mode(s, mb, mb_x, mb_y, s->segmentation_map + mb_xy,
-                           prev_frame ? prev_frame->ref_index[0] + mb_xy : NULL);
+            decode_mb_mode(s, mb, mb_x, mb_y, curframe->ref_index[0] + mb_xy,
+                           prev_frame && prev_frame->ref_index[0] ? prev_frame->ref_index[0] + mb_xy : NULL);
 
             prefetch_motion(s, mb, mb_x, mb_y, mb_xy, VP56_FRAME_PREVIOUS);
 
@@ -1736,7 +1791,8 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx)
 
 static av_cold int vp8_decode_free(AVCodecContext *avctx)
 {
-    vp8_decode_flush(avctx);
+    vp8_decode_flush_impl(avctx, 0, 1, 1);
+    release_queued_segmaps(avctx->priv_data, 1);
     return 0;
 }