]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/vp8.c
Remove redundant checks against MIN_CACHE_BITS
[ffmpeg] / libavcodec / vp8.c
index 6e165bdb098854a83fe64e3f8a71bfe6bd22dc28..80d30e8046cafd1bfa422107d216098171098c8a 100644 (file)
@@ -87,12 +87,10 @@ typedef struct {
     VP8Macroblock *macroblocks;
     VP8Macroblock *macroblocks_base;
     VP8FilterStrength *filter_strength;
-    int mb_stride;
 
     uint8_t *intra4x4_pred_mode_top;
     uint8_t intra4x4_pred_mode_left[4];
     uint8_t *segmentation_map;
-    int b4_stride;
 
     /**
      * Cache of the top row needed for intra prediction
@@ -225,7 +223,7 @@ static void vp8_decode_flush(AVCodecContext *avctx)
 
 static int update_dimensions(VP8Context *s, int width, int height)
 {
-    if (av_check_image_size(width, height, 0, s->avctx))
+    if (av_image_check_size(width, height, 0, s->avctx))
         return AVERROR_INVALIDDATA;
 
     vp8_decode_flush(s->avctx);
@@ -235,17 +233,12 @@ static int update_dimensions(VP8Context *s, int width, int height)
     s->mb_width  = (s->avctx->coded_width +15) / 16;
     s->mb_height = (s->avctx->coded_height+15) / 16;
 
-    // we allocate a border around the top/left of intra4x4 modes
-    // this is 4 blocks for intra4x4 to keep 4-byte alignment for fill_rectangle
-    s->mb_stride = s->mb_width+1;
-    s->b4_stride = 4*s->mb_stride;
-
-    s->macroblocks_base        = av_mallocz((s->mb_stride+s->mb_height*2+2)*sizeof(*s->macroblocks));
-    s->filter_strength         = av_mallocz(s->mb_stride*sizeof(*s->filter_strength));
+    s->macroblocks_base        = av_mallocz((s->mb_width+s->mb_height*2+1)*sizeof(*s->macroblocks));
+    s->filter_strength         = av_mallocz(s->mb_width*sizeof(*s->filter_strength));
     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_stride*s->mb_height);
+    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)
@@ -535,7 +528,7 @@ void clamp_mv(VP8Context *s, VP56mv *dst, const VP56mv *src, int mb_x, int mb_y)
 }
 
 static av_always_inline
-void find_near_mvs(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y,
+void find_near_mvs(VP8Context *s, VP8Macroblock *mb,
                    VP56mv near[2], VP56mv *best, uint8_t cnt[4])
 {
     VP8Macroblock *mb_edge[3] = { mb + 2 /* top */,
@@ -767,7 +760,7 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y, uint8_
         s->ref_count[mb->ref_frame-1]++;
 
         // motion vectors, 16.3
-        find_near_mvs(s, mb, mb_x, mb_y, near, &best, cnt);
+        find_near_mvs(s, mb, near, &best, cnt);
         if (vp56_rac_get_prob_branchy(c, vp8_mode_contexts[cnt[0]][0])) {
             if (vp56_rac_get_prob_branchy(c, vp8_mode_contexts[cnt[1]][1])) {
                 if (vp56_rac_get_prob_branchy(c, vp8_mode_contexts[cnt[2]][2])) {
@@ -778,8 +771,8 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y, uint8_
                     } else {
                         mb->mode = VP8_MVMODE_NEW;
                         clamp_mv(s, &mb->mv, &mb->mv, mb_x, mb_y);
-                        mb->mv.y += read_mv_component(c, s->prob->mvc[0]);
-                        mb->mv.x += read_mv_component(c, s->prob->mvc[1]);
+                        mb->mv.y += read_mv_component(c, s->prob->mvc[0]);
+                        mb->mv.x += read_mv_component(c, s->prob->mvc[1]);
                     }
                 } else {
                     mb->mode = VP8_MVMODE_NEAR;
@@ -990,14 +983,91 @@ void xchg_mb_border(uint8_t *top_border, uint8_t *src_y, uint8_t *src_cb, uint8_
 }
 
 static av_always_inline
-int check_intra_pred_mode(int mode, int mb_x, int mb_y)
+int check_dc_pred8x8_mode(int mode, int mb_x, int mb_y)
+{
+    if (!mb_x) {
+        return mb_y ? TOP_DC_PRED8x8 : DC_128_PRED8x8;
+    } else {
+        return mb_y ? mode : LEFT_DC_PRED8x8;
+    }
+}
+
+static av_always_inline
+int check_tm_pred8x8_mode(int mode, int mb_x, int mb_y)
+{
+    if (!mb_x) {
+        return mb_y ? VERT_PRED8x8 : DC_129_PRED8x8;
+    } else {
+        return mb_y ? mode : HOR_PRED8x8;
+    }
+}
+
+static av_always_inline
+int check_intra_pred8x8_mode(int mode, int mb_x, int mb_y)
 {
     if (mode == DC_PRED8x8) {
-        if (!mb_x) {
-            mode = mb_y ? TOP_DC_PRED8x8 : DC_128_PRED8x8;
-        } else if (!mb_y) {
-            mode = LEFT_DC_PRED8x8;
+        return check_dc_pred8x8_mode(mode, mb_x, mb_y);
+    } else {
+        return mode;
+    }
+}
+
+static av_always_inline
+int check_intra_pred8x8_mode_emuedge(int mode, int mb_x, int mb_y)
+{
+    switch (mode) {
+    case DC_PRED8x8:
+        return check_dc_pred8x8_mode(mode, mb_x, mb_y);
+    case VERT_PRED8x8:
+        return !mb_y ? DC_127_PRED8x8 : mode;
+    case HOR_PRED8x8:
+        return !mb_x ? DC_129_PRED8x8 : mode;
+    case PLANE_PRED8x8 /*TM*/:
+        return check_tm_pred8x8_mode(mode, mb_x, mb_y);
+    }
+    return mode;
+}
+
+static av_always_inline
+int check_tm_pred4x4_mode(int mode, int mb_x, int mb_y)
+{
+    if (!mb_x) {
+        return mb_y ? VERT_VP8_PRED : DC_129_PRED;
+    } else {
+        return mb_y ? mode : HOR_VP8_PRED;
+    }
+}
+
+static av_always_inline
+int check_intra_pred4x4_mode_emuedge(int mode, int mb_x, int mb_y, int *copy_buf)
+{
+    switch (mode) {
+    case VERT_PRED:
+        if (!mb_x && mb_y) {
+            *copy_buf = 1;
+            return mode;
+        }
+        /* fall-through */
+    case DIAG_DOWN_LEFT_PRED:
+    case VERT_LEFT_PRED:
+        return !mb_y ? DC_127_PRED : mode;
+    case HOR_PRED:
+        if (!mb_y) {
+            *copy_buf = 1;
+            return mode;
         }
+        /* fall-through */
+    case HOR_UP_PRED:
+        return !mb_x ? DC_129_PRED : mode;
+    case TM_VP8_PRED:
+        return check_tm_pred4x4_mode(mode, mb_x, mb_y);
+    case DC_PRED: // 4x4 DC doesn't use the same "H.264-style" exceptions as 16x16/8x8 DC
+    case DIAG_DOWN_RIGHT_PRED:
+    case VERT_RIGHT_PRED:
+    case HOR_DOWN_PRED:
+        if (!mb_y || !mb_x)
+            *copy_buf = 1;
+        return mode;
     }
     return mode;
 }
@@ -1006,21 +1076,27 @@ static av_always_inline
 void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb,
                    int mb_x, int mb_y)
 {
+    AVCodecContext *avctx = s->avctx;
     int x, y, mode, nnz, tr;
 
     // for the first row, we need to run xchg_mb_border to init the top edge to 127
     // otherwise, skip it if we aren't going to deblock
-    if (s->deblock_filter || !mb_y)
+    if (!(avctx->flags & CODEC_FLAG_EMU_EDGE && !mb_y) && (s->deblock_filter || !mb_y))
         xchg_mb_border(s->top_border[mb_x+1], dst[0], dst[1], dst[2],
                        s->linesize, s->uvlinesize, mb_x, mb_y, s->mb_width,
                        s->filter.simple, 1);
 
     if (mb->mode < MODE_I4x4) {
-        mode = check_intra_pred_mode(mb->mode, mb_x, mb_y);
+        if (avctx->flags & CODEC_FLAG_EMU_EDGE) { // tested
+            mode = check_intra_pred8x8_mode_emuedge(mb->mode, mb_x, mb_y);
+        } else {
+            mode = check_intra_pred8x8_mode(mb->mode, mb_x, mb_y);
+        }
         s->hpc.pred16x16[mode](dst[0], s->linesize);
     } else {
         uint8_t *ptr = dst[0];
         uint8_t *intra4x4 = s->intra4x4_pred_mode_mb;
+        uint8_t tr_top[4] = { 127, 127, 127, 127 };
 
         // all blocks on the right edge of the macroblock use bottom edge
         // the top macroblock for their topright edge
@@ -1028,7 +1104,8 @@ void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb,
 
         // if we're on the right edge of the frame, said edge is extended
         // from the top macroblock
-        if (mb_x == s->mb_width-1) {
+        if (!(!mb_y && avctx->flags & CODEC_FLAG_EMU_EDGE) &&
+            mb_x == s->mb_width-1) {
             tr = tr_right[-1]*0x01010101;
             tr_right = (uint8_t *)&tr;
         }
@@ -1039,10 +1116,53 @@ void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb,
         for (y = 0; y < 4; y++) {
             uint8_t *topright = ptr + 4 - s->linesize;
             for (x = 0; x < 4; x++) {
-                if (x == 3)
+                int copy = 0, linesize = s->linesize;
+                uint8_t *dst = ptr+4*x;
+                DECLARE_ALIGNED(4, uint8_t, copy_dst)[5*8];
+
+                if ((y == 0 || x == 3) && mb_y == 0 && avctx->flags & CODEC_FLAG_EMU_EDGE) {
+                    topright = tr_top;
+                } else if (x == 3)
                     topright = tr_right;
 
-                s->hpc.pred4x4[intra4x4[x]](ptr+4*x, topright, s->linesize);
+                if (avctx->flags & CODEC_FLAG_EMU_EDGE) { // mb_x+x or mb_y+y is a hack but works
+                    mode = check_intra_pred4x4_mode_emuedge(intra4x4[x], mb_x + x, mb_y + y, &copy);
+                    if (copy) {
+                        dst = copy_dst + 12;
+                        linesize = 8;
+                        if (!(mb_y + y)) {
+                            copy_dst[3] = 127U;
+                            * (uint32_t *) (copy_dst + 4) = 127U * 0x01010101U;
+                        } else {
+                            * (uint32_t *) (copy_dst + 4) = * (uint32_t *) (ptr+4*x-s->linesize);
+                            if (!(mb_x + x)) {
+                                copy_dst[3] = 129U;
+                            } else {
+                                copy_dst[3] = ptr[4*x-s->linesize-1];
+                            }
+                        }
+                        if (!(mb_x + x)) {
+                            copy_dst[11] =
+                            copy_dst[19] =
+                            copy_dst[27] =
+                            copy_dst[35] = 129U;
+                        } else {
+                            copy_dst[11] = ptr[4*x              -1];
+                            copy_dst[19] = ptr[4*x+s->linesize  -1];
+                            copy_dst[27] = ptr[4*x+s->linesize*2-1];
+                            copy_dst[35] = ptr[4*x+s->linesize*3-1];
+                        }
+                    }
+                } else {
+                    mode = intra4x4[x];
+                }
+                s->hpc.pred4x4[mode](dst, topright, linesize);
+                if (copy) {
+                    * (uint32_t *) (ptr+4*x)               = * (uint32_t *) (copy_dst + 12);
+                    * (uint32_t *) (ptr+4*x+s->linesize)   = * (uint32_t *) (copy_dst + 20);
+                    * (uint32_t *) (ptr+4*x+s->linesize*2) = * (uint32_t *) (copy_dst + 28);
+                    * (uint32_t *) (ptr+4*x+s->linesize*3) = * (uint32_t *) (copy_dst + 36);
+                }
 
                 nnz = s->non_zero_count_cache[y][x];
                 if (nnz) {
@@ -1059,11 +1179,15 @@ void intra_predict(VP8Context *s, uint8_t *dst[3], VP8Macroblock *mb,
         }
     }
 
-    mode = check_intra_pred_mode(s->chroma_pred_mode, mb_x, mb_y);
+    if (avctx->flags & CODEC_FLAG_EMU_EDGE) {
+        mode = check_intra_pred8x8_mode_emuedge(s->chroma_pred_mode, mb_x, mb_y);
+    } else {
+        mode = check_intra_pred8x8_mode(s->chroma_pred_mode, mb_x, mb_y);
+    }
     s->hpc.pred8x8[mode](dst[1], s->uvlinesize);
     s->hpc.pred8x8[mode](dst[2], s->uvlinesize);
 
-    if (s->deblock_filter || !mb_y)
+    if (!(avctx->flags & CODEC_FLAG_EMU_EDGE && !mb_y) && (s->deblock_filter || !mb_y))
         xchg_mb_border(s->top_border[mb_x+1], dst[0], dst[1], dst[2],
                        s->linesize, s->uvlinesize, mb_x, mb_y, s->mb_width,
                        s->filter.simple, 0);
@@ -1536,11 +1660,14 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
 
     memset(s->top_nnz, 0, s->mb_width*sizeof(*s->top_nnz));
 
-    /* Zero macroblock structures for top/left prediction from outside the frame. */
-    memset(s->macroblocks, 0, (s->mb_width + s->mb_height*2)*sizeof(*s->macroblocks));
+    /* Zero macroblock structures for top/top-left prediction from outside the frame. */
+    memset(s->macroblocks + s->mb_height*2 - 1, 0, (s->mb_width+1)*sizeof(*s->macroblocks));
 
     // top edge of 127 for intra prediction
-    memset(s->top_border, 127, (s->mb_width+1)*sizeof(*s->top_border));
+    if (!(avctx->flags & CODEC_FLAG_EMU_EDGE)) {
+        s->top_border[0][15] = s->top_border[0][23] = 127;
+        memset(s->top_border[1]-1, 127, s->mb_width*sizeof(*s->top_border)+1);
+    }
     memset(s->ref_count, 0, sizeof(s->ref_count));
     if (s->keyframe)
         memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width*4);
@@ -1548,33 +1675,32 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
     for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
         VP56RangeCoder *c = &s->coeff_partition[mb_y & (s->num_coeff_partitions-1)];
         VP8Macroblock *mb = s->macroblocks + (s->mb_height - mb_y - 1)*2;
-        uint8_t *segment_map = s->segmentation_map + mb_y*s->mb_stride;
-        int mb_xy = mb_y * s->mb_stride;
+        int mb_xy = mb_y*s->mb_width;
         uint8_t *dst[3] = {
             curframe->data[0] + 16*mb_y*s->linesize,
             curframe->data[1] +  8*mb_y*s->uvlinesize,
             curframe->data[2] +  8*mb_y*s->uvlinesize
         };
 
+        memset(mb - 1, 0, sizeof(*mb));   // zero left macroblock
         memset(s->left_nnz, 0, sizeof(s->left_nnz));
         AV_WN32A(s->intra4x4_pred_mode_left, DC_PRED*0x01010101);
 
         // left edge of 129 for intra prediction
-        if (!(avctx->flags & CODEC_FLAG_EMU_EDGE))
+        if (!(avctx->flags & CODEC_FLAG_EMU_EDGE)) {
             for (i = 0; i < 3; i++)
                 for (y = 0; y < 16>>!!i; y++)
                     dst[i][y*curframe->linesize[i]-1] = 129;
-        if (mb_y)
-            memset(s->top_border, 129, sizeof(*s->top_border));
+            if (mb_y == 1) // top left edge is also 129
+                s->top_border[0][15] = s->top_border[0][23] = s->top_border[0][31] = 129;
+        }
 
         for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb_xy++, mb++) {
-            uint8_t *segment_mb = segment_map+mb_x;
-
             /* Prefetch the current frame, 4 MBs ahead */
             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, segment_mb);
+            decode_mb_mode(s, mb, mb_x, mb_y, s->segmentation_map + mb_xy);
 
             prefetch_motion(s, mb, mb_x, mb_y, mb_xy, VP56_FRAME_PREVIOUS);
 
@@ -1667,12 +1793,6 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx)
     ff_h264_pred_init(&s->hpc, CODEC_ID_VP8);
     ff_vp8dsp_init(&s->vp8dsp);
 
-    // intra pred needs edge emulation among other things
-    if (avctx->flags&CODEC_FLAG_EMU_EDGE) {
-        av_log(avctx, AV_LOG_ERROR, "Edge emulation not supported\n");
-        return AVERROR_PATCHWELCOME;
-    }
-
     return 0;
 }