libavcodec/error_resilience.c
4d2858de
 /*
  * Error resilience / concealment
  *
8f2ab833
  * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
4d2858de
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
4d2858de
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
b78e7197
  * version 2.1 of the License, or (at your option) any later version.
4d2858de
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
4d2858de
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
b78e7197
  * License along with FFmpeg; if not, write to the Free Software
5509bffa
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
4d2858de
  */
115329f1
 
983e3246
 /**
ba87f080
  * @file
983e3246
  * Error resilience / concealment.
  */
4d2858de
 
7bc9090a
 #include <limits.h>
115329f1
 
4d2858de
 #include "avcodec.h"
 #include "dsputil.h"
 #include "mpegvideo.h"
2c4bc23e
 #include "h264.h"
e5d2bdec
 #include "rectangle.h"
6a9c8594
 #include "thread.h"
2c4bc23e
 
 /*
  * H264 redefines mb_intra so it is not mistakely used (its uninitialized in h264)
  * but error concealment must support both h264 and h263 thus we must undo this
  */
 #undef mb_intra
4d2858de
 
673fc638
 static void decode_mb(MpegEncContext *s, int ref){
7d1c3fc1
     s->dest[0] = s->current_picture.data[0] + (s->mb_y * 16* s->linesize  ) + s->mb_x * 16;
f40a7fd3
     s->dest[1] = s->current_picture.data[1] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift);
     s->dest[2] = s->current_picture.data[2] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift);
7d1c3fc1
 
3546fa8d
     if(CONFIG_H264_DECODER && s->codec_id == CODEC_ID_H264){
68f0bc7e
         H264Context *h= (void*)s;
         h->mb_xy= s->mb_x + s->mb_y*s->mb_stride;
         memset(h->non_zero_count_cache, 0, sizeof(h->non_zero_count_cache));
673fc638
         assert(ref>=0);
         if(ref >= h->ref_count[0]) //FIXME it is posible albeit uncommon that slice references differ between slices, we take the easy approuch and ignore it for now. If this turns out to have any relevance in practice then correct remapping should be added
             ref=0;
         fill_rectangle(&s->current_picture.ref_index[0][4*h->mb_xy], 2, 2, 2, ref, 1);
         fill_rectangle(&h->ref_cache[0][scan8[0]], 4, 4, 8, ref, 1);
68f0bc7e
         fill_rectangle(h->mv_cache[0][ scan8[0] ], 4, 4, 8, pack16to32(s->mv[0][0][0],s->mv[0][0][1]), 4);
         assert(!FRAME_MBAFF);
         ff_h264_hl_decode_mb(h);
     }else{
673fc638
         assert(ref==0);
115329f1
     MPV_decode_mb(s, s->block);
68f0bc7e
     }
7d1c3fc1
 }
 
4d2858de
 /**
2c4bc23e
  * @param stride the number of MVs to get to the next row
  * @param mv_step the number of MVs per row or column in a macroblock
  */
 static void set_mv_strides(MpegEncContext *s, int *mv_step, int *stride){
     if(s->codec_id == CODEC_ID_H264){
         H264Context *h= (void*)s;
         assert(s->quarter_sample);
         *mv_step= 4;
         *stride= h->b_stride;
     }else{
         *mv_step= 2;
         *stride= s->b8_stride;
     }
 }
 
 /**
4d2858de
  * replaces the current MB with a flat dc only version.
  */
 static void put_dc(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int mb_x, int mb_y)
 {
     int dc, dcu, dcv, y, i;
     for(i=0; i<4; i++){
137c8468
         dc= s->dc_val[0][mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*s->b8_stride];
4d2858de
         if(dc<0) dc=0;
         else if(dc>2040) dc=2040;
         for(y=0; y<8; y++){
             int x;
             for(x=0; x<8; x++){
                 dest_y[x + (i&1)*8 + (y + (i>>1)*8)*s->linesize]= dc/8;
             }
         }
     }
137c8468
     dcu = s->dc_val[1][mb_x + mb_y*s->mb_stride];
     dcv = s->dc_val[2][mb_x + mb_y*s->mb_stride];
4d2858de
     if     (dcu<0   ) dcu=0;
     else if(dcu>2040) dcu=2040;
     if     (dcv<0   ) dcv=0;
     else if(dcv>2040) dcv=2040;
     for(y=0; y<8; y++){
         int x;
         for(x=0; x<8; x++){
             dest_cb[x + y*(s->uvlinesize)]= dcu/8;
             dest_cr[x + y*(s->uvlinesize)]= dcv/8;
         }
     }
 }
 
b86216de
 static void filter181(int16_t *data, int width, int height, int stride){
4d2858de
     int x,y;
 
     /* horizontal filter */
     for(y=1; y<height-1; y++){
         int prev_dc= data[0 + y*stride];
 
         for(x=1; x<width-1; x++){
             int dc;
115329f1
 
             dc= - prev_dc
4d2858de
                 + data[x     + y*stride]*8
                 - data[x + 1 + y*stride];
             dc= (dc*10923 + 32768)>>16;
             prev_dc= data[x + y*stride];
             data[x + y*stride]= dc;
         }
     }
115329f1
 
4d2858de
     /* vertical filter */
     for(x=1; x<width-1; x++){
         int prev_dc= data[x];
 
         for(y=1; y<height-1; y++){
             int dc;
115329f1
 
             dc= - prev_dc
4d2858de
                 + data[x +  y   *stride]*8
                 - data[x + (y+1)*stride];
             dc= (dc*10923 + 32768)>>16;
             prev_dc= data[x + y*stride];
             data[x + y*stride]= dc;
         }
     }
 }
 
 /**
755bfeab
  * guess the dc of blocks which do not have an undamaged dc
bb270c08
  * @param w     width in 8 pixel blocks
  * @param h     height in 8 pixel blocks
4d2858de
  */
b86216de
 static void guess_dc(MpegEncContext *s, int16_t *dc, int w, int h, int stride, int is_luma){
4d2858de
     int b_x, b_y;
 
     for(b_y=0; b_y<h; b_y++){
         for(b_x=0; b_x<w; b_x++){
             int color[4]={1024,1024,1024,1024};
             int distance[4]={9999,9999,9999,9999};
             int mb_index, error, j;
0c1a9eda
             int64_t guess, weight_sum;
115329f1
 
7bc9090a
             mb_index= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
115329f1
 
4d2858de
             error= s->error_status_table[mb_index];
115329f1
 
7bc9090a
             if(IS_INTER(s->current_picture.mb_type[mb_index])) continue; //inter
4d2858de
             if(!(error&DC_ERROR)) continue;           //dc-ok
115329f1
 
4d2858de
             /* right block */
             for(j=b_x+1; j<w; j++){
7bc9090a
                 int mb_index_j= (j>>is_luma) + (b_y>>is_luma)*s->mb_stride;
4d2858de
                 int error_j= s->error_status_table[mb_index_j];
7bc9090a
                 int intra_j= IS_INTRA(s->current_picture.mb_type[mb_index_j]);
4d2858de
                 if(intra_j==0 || !(error_j&DC_ERROR)){
                     color[0]= dc[j + b_y*stride];
                     distance[0]= j-b_x;
                     break;
                 }
             }
115329f1
 
4d2858de
             /* left block */
             for(j=b_x-1; j>=0; j--){
7bc9090a
                 int mb_index_j= (j>>is_luma) + (b_y>>is_luma)*s->mb_stride;
4d2858de
                 int error_j= s->error_status_table[mb_index_j];
7bc9090a
                 int intra_j= IS_INTRA(s->current_picture.mb_type[mb_index_j]);
4d2858de
                 if(intra_j==0 || !(error_j&DC_ERROR)){
                     color[1]= dc[j + b_y*stride];
                     distance[1]= b_x-j;
                     break;
                 }
             }
 
             /* bottom block */
             for(j=b_y+1; j<h; j++){
7bc9090a
                 int mb_index_j= (b_x>>is_luma) + (j>>is_luma)*s->mb_stride;
4d2858de
                 int error_j= s->error_status_table[mb_index_j];
7bc9090a
                 int intra_j= IS_INTRA(s->current_picture.mb_type[mb_index_j]);
4d2858de
                 if(intra_j==0 || !(error_j&DC_ERROR)){
                     color[2]= dc[b_x + j*stride];
                     distance[2]= j-b_y;
                     break;
                 }
             }
 
             /* top block */
             for(j=b_y-1; j>=0; j--){
7bc9090a
                 int mb_index_j= (b_x>>is_luma) + (j>>is_luma)*s->mb_stride;
4d2858de
                 int error_j= s->error_status_table[mb_index_j];
7bc9090a
                 int intra_j= IS_INTRA(s->current_picture.mb_type[mb_index_j]);
4d2858de
                 if(intra_j==0 || !(error_j&DC_ERROR)){
                     color[3]= dc[b_x + j*stride];
                     distance[3]= b_y-j;
                     break;
                 }
             }
115329f1
 
4d2858de
             weight_sum=0;
             guess=0;
             for(j=0; j<4; j++){
0c1a9eda
                 int64_t weight= 256*256*256*16/distance[j];
                 guess+= weight*(int64_t)color[j];
4d2858de
                 weight_sum+= weight;
             }
             guess= (guess + weight_sum/2) / weight_sum;
 
             dc[b_x + b_y*stride]= guess;
         }
     }
 }
 
 /**
  * simple horizontal deblocking filter used for error resilience
bb270c08
  * @param w     width in 8 pixel blocks
  * @param h     height in 8 pixel blocks
4d2858de
  */
0c1a9eda
 static void h_block_filter(MpegEncContext *s, uint8_t *dst, int w, int h, int stride, int is_luma){
bb4fcfa3
     int b_x, b_y, mvx_stride, mvy_stride;
55fde95e
     uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
bb4fcfa3
     set_mv_strides(s, &mvx_stride, &mvy_stride);
     mvx_stride >>= is_luma;
     mvy_stride *= mvx_stride;
4d2858de
 
     for(b_y=0; b_y<h; b_y++){
         for(b_x=0; b_x<w-1; b_x++){
             int y;
7bc9090a
             int left_status = s->error_status_table[( b_x   >>is_luma) + (b_y>>is_luma)*s->mb_stride];
             int right_status= s->error_status_table[((b_x+1)>>is_luma) + (b_y>>is_luma)*s->mb_stride];
             int left_intra=   IS_INTRA(s->current_picture.mb_type      [( b_x   >>is_luma) + (b_y>>is_luma)*s->mb_stride]);
             int right_intra=  IS_INTRA(s->current_picture.mb_type      [((b_x+1)>>is_luma) + (b_y>>is_luma)*s->mb_stride]);
4d2858de
             int left_damage =  left_status&(DC_ERROR|AC_ERROR|MV_ERROR);
             int right_damage= right_status&(DC_ERROR|AC_ERROR|MV_ERROR);
             int offset= b_x*8 + b_y*stride*8;
bb4fcfa3
             int16_t *left_mv=  s->current_picture.motion_val[0][mvy_stride*b_y + mvx_stride* b_x   ];
             int16_t *right_mv= s->current_picture.motion_val[0][mvy_stride*b_y + mvx_stride*(b_x+1)];
115329f1
 
4d2858de
             if(!(left_damage||right_damage)) continue; // both undamaged
115329f1
 
             if(   (!left_intra) && (!right_intra)
c26abfa5
                && FFABS(left_mv[0]-right_mv[0]) + FFABS(left_mv[1]+right_mv[1]) < 2) continue;
115329f1
 
4d2858de
             for(y=0; y<8; y++){
                 int a,b,c,d;
115329f1
 
4d2858de
                 a= dst[offset + 7 + y*stride] - dst[offset + 6 + y*stride];
                 b= dst[offset + 8 + y*stride] - dst[offset + 7 + y*stride];
                 c= dst[offset + 9 + y*stride] - dst[offset + 8 + y*stride];
115329f1
 
c26abfa5
                 d= FFABS(b) - ((FFABS(a) + FFABS(c) + 1)>>1);
b8a78f41
                 d= FFMAX(d, 0);
4d2858de
                 if(b<0) d= -d;
115329f1
 
4d2858de
                 if(d==0) continue;
 
                 if(!(left_damage && right_damage))
                     d= d*16/9;
115329f1
 
4d2858de
                 if(left_damage){
                     dst[offset + 7 + y*stride] = cm[dst[offset + 7 + y*stride] + ((d*7)>>4)];
                     dst[offset + 6 + y*stride] = cm[dst[offset + 6 + y*stride] + ((d*5)>>4)];
                     dst[offset + 5 + y*stride] = cm[dst[offset + 5 + y*stride] + ((d*3)>>4)];
                     dst[offset + 4 + y*stride] = cm[dst[offset + 4 + y*stride] + ((d*1)>>4)];
                 }
                 if(right_damage){
                     dst[offset + 8 + y*stride] = cm[dst[offset + 8 + y*stride] - ((d*7)>>4)];
                     dst[offset + 9 + y*stride] = cm[dst[offset + 9 + y*stride] - ((d*5)>>4)];
                     dst[offset + 10+ y*stride] = cm[dst[offset +10 + y*stride] - ((d*3)>>4)];
                     dst[offset + 11+ y*stride] = cm[dst[offset +11 + y*stride] - ((d*1)>>4)];
                 }
             }
         }
     }
 }
 
 /**
  * simple vertical deblocking filter used for error resilience
bb270c08
  * @param w     width in 8 pixel blocks
  * @param h     height in 8 pixel blocks
4d2858de
  */
0c1a9eda
 static void v_block_filter(MpegEncContext *s, uint8_t *dst, int w, int h, int stride, int is_luma){
bb4fcfa3
     int b_x, b_y, mvx_stride, mvy_stride;
55fde95e
     uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
bb4fcfa3
     set_mv_strides(s, &mvx_stride, &mvy_stride);
     mvx_stride >>= is_luma;
     mvy_stride *= mvx_stride;
4d2858de
 
     for(b_y=0; b_y<h-1; b_y++){
         for(b_x=0; b_x<w; b_x++){
             int x;
7bc9090a
             int top_status   = s->error_status_table[(b_x>>is_luma) + ( b_y   >>is_luma)*s->mb_stride];
             int bottom_status= s->error_status_table[(b_x>>is_luma) + ((b_y+1)>>is_luma)*s->mb_stride];
             int top_intra=     IS_INTRA(s->current_picture.mb_type      [(b_x>>is_luma) + ( b_y   >>is_luma)*s->mb_stride]);
             int bottom_intra=  IS_INTRA(s->current_picture.mb_type      [(b_x>>is_luma) + ((b_y+1)>>is_luma)*s->mb_stride]);
4d2858de
             int top_damage =      top_status&(DC_ERROR|AC_ERROR|MV_ERROR);
             int bottom_damage= bottom_status&(DC_ERROR|AC_ERROR|MV_ERROR);
             int offset= b_x*8 + b_y*stride*8;
bb4fcfa3
             int16_t *top_mv=    s->current_picture.motion_val[0][mvy_stride* b_y    + mvx_stride*b_x];
             int16_t *bottom_mv= s->current_picture.motion_val[0][mvy_stride*(b_y+1) + mvx_stride*b_x];
115329f1
 
4d2858de
             if(!(top_damage||bottom_damage)) continue; // both undamaged
115329f1
 
             if(   (!top_intra) && (!bottom_intra)
c26abfa5
                && FFABS(top_mv[0]-bottom_mv[0]) + FFABS(top_mv[1]+bottom_mv[1]) < 2) continue;
115329f1
 
4d2858de
             for(x=0; x<8; x++){
                 int a,b,c,d;
115329f1
 
4d2858de
                 a= dst[offset + x + 7*stride] - dst[offset + x + 6*stride];
                 b= dst[offset + x + 8*stride] - dst[offset + x + 7*stride];
                 c= dst[offset + x + 9*stride] - dst[offset + x + 8*stride];
115329f1
 
c26abfa5
                 d= FFABS(b) - ((FFABS(a) + FFABS(c)+1)>>1);
b8a78f41
                 d= FFMAX(d, 0);
4d2858de
                 if(b<0) d= -d;
115329f1
 
4d2858de
                 if(d==0) continue;
 
                 if(!(top_damage && bottom_damage))
                     d= d*16/9;
115329f1
 
4d2858de
                 if(top_damage){
                     dst[offset + x +  7*stride] = cm[dst[offset + x +  7*stride] + ((d*7)>>4)];
                     dst[offset + x +  6*stride] = cm[dst[offset + x +  6*stride] + ((d*5)>>4)];
                     dst[offset + x +  5*stride] = cm[dst[offset + x +  5*stride] + ((d*3)>>4)];
                     dst[offset + x +  4*stride] = cm[dst[offset + x +  4*stride] + ((d*1)>>4)];
                 }
                 if(bottom_damage){
                     dst[offset + x +  8*stride] = cm[dst[offset + x +  8*stride] - ((d*7)>>4)];
                     dst[offset + x +  9*stride] = cm[dst[offset + x +  9*stride] - ((d*5)>>4)];
                     dst[offset + x + 10*stride] = cm[dst[offset + x + 10*stride] - ((d*3)>>4)];
                     dst[offset + x + 11*stride] = cm[dst[offset + x + 11*stride] - ((d*1)>>4)];
                 }
             }
         }
     }
 }
 
 static void guess_mv(MpegEncContext *s){
7bc9090a
     uint8_t fixed[s->mb_stride * s->mb_height];
4d2858de
 #define MV_FROZEN    3
 #define MV_CHANGED   2
 #define MV_UNCHANGED 1
7bc9090a
     const int mb_stride = s->mb_stride;
4d2858de
     const int mb_width = s->mb_width;
     const int mb_height= s->mb_height;
     int i, depth, num_avail;
2c4bc23e
     int mb_x, mb_y, mot_step, mot_stride;
 
     set_mv_strides(s, &mot_step, &mot_stride);
115329f1
 
4d2858de
     num_avail=0;
     for(i=0; i<s->mb_num; i++){
7bc9090a
         const int mb_xy= s->mb_index2xy[ i ];
4d2858de
         int f=0;
7bc9090a
         int error= s->error_status_table[mb_xy];
4d2858de
 
7bc9090a
         if(IS_INTRA(s->current_picture.mb_type[mb_xy])) f=MV_FROZEN; //intra //FIXME check
4d2858de
         if(!(error&MV_ERROR)) f=MV_FROZEN;           //inter with undamaged MV
115329f1
 
7bc9090a
         fixed[mb_xy]= f;
4d2858de
         if(f==MV_FROZEN)
             num_avail++;
b8a4b015
         else if(s->last_picture.data[0] && s->last_picture.motion_val[0]){
3732c483
             const int mb_y= mb_xy / s->mb_stride;
             const int mb_x= mb_xy % s->mb_stride;
             const int mot_index= (mb_x + mb_y*mot_stride) * mot_step;
             s->current_picture.motion_val[0][mot_index][0]= s->last_picture.motion_val[0][mot_index][0];
             s->current_picture.motion_val[0][mot_index][1]= s->last_picture.motion_val[0][mot_index][1];
             s->current_picture.ref_index[0][4*mb_xy]      = s->last_picture.ref_index[0][4*mb_xy];
         }
4d2858de
     }
115329f1
 
4d2858de
     if((!(s->avctx->error_concealment&FF_EC_GUESS_MVS)) || num_avail <= mb_width/2){
         for(mb_y=0; mb_y<s->mb_height; mb_y++){
             for(mb_x=0; mb_x<s->mb_width; mb_x++){
7bc9090a
                 const int mb_xy= mb_x + mb_y*s->mb_stride;
115329f1
 
7bc9090a
                 if(IS_INTRA(s->current_picture.mb_type[mb_xy]))  continue;
                 if(!(s->error_status_table[mb_xy]&MV_ERROR)) continue;
4d2858de
 
b6b66760
                 s->mv_dir = s->last_picture.data[0] ? MV_DIR_FORWARD : MV_DIR_BACKWARD;
4d2858de
                 s->mb_intra=0;
                 s->mv_type = MV_TYPE_16X16;
160d679c
                 s->mb_skipped=0;
4d2858de
 
bb270c08
                 s->dsp.clear_blocks(s->block[0]);
4d2858de
 
                 s->mb_x= mb_x;
                 s->mb_y= mb_y;
                 s->mv[0][0][0]= 0;
                 s->mv[0][0][1]= 0;
673fc638
                 decode_mb(s, 0);
4d2858de
             }
         }
         return;
     }
115329f1
 
4d2858de
     for(depth=0;; depth++){
         int changed, pass, none_left;
 
         none_left=1;
         changed=1;
         for(pass=0; (changed || pass<2) && pass<10; pass++){
7bc9090a
             int mb_x, mb_y;
4d2858de
 int score_sum=0;
115329f1
 
4d2858de
             changed=0;
             for(mb_y=0; mb_y<s->mb_height; mb_y++){
                 for(mb_x=0; mb_x<s->mb_width; mb_x++){
7bc9090a
                     const int mb_xy= mb_x + mb_y*s->mb_stride;
4d2858de
                     int mv_predictor[8][2]={{0}};
673fc638
                     int ref[8]={0};
4d2858de
                     int pred_count=0;
                     int j;
                     int best_score=256*256*256*64;
                     int best_pred=0;
2c4bc23e
                     const int mot_index= (mb_x + mb_y*mot_stride) * mot_step;
6a9c8594
                     int prev_x, prev_y, prev_ref;
4d2858de
 
                     if((mb_x^mb_y^pass)&1) continue;
115329f1
 
7bc9090a
                     if(fixed[mb_xy]==MV_FROZEN) continue;
                     assert(!IS_INTRA(s->current_picture.mb_type[mb_xy]));
                     assert(s->last_picture_ptr && s->last_picture_ptr->data[0]);
115329f1
 
4d2858de
                     j=0;
7bc9090a
                     if(mb_x>0           && fixed[mb_xy-1        ]==MV_FROZEN) j=1;
                     if(mb_x+1<mb_width  && fixed[mb_xy+1        ]==MV_FROZEN) j=1;
                     if(mb_y>0           && fixed[mb_xy-mb_stride]==MV_FROZEN) j=1;
                     if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]==MV_FROZEN) j=1;
4d2858de
                     if(j==0) continue;
 
                     j=0;
7bc9090a
                     if(mb_x>0           && fixed[mb_xy-1        ]==MV_CHANGED) j=1;
                     if(mb_x+1<mb_width  && fixed[mb_xy+1        ]==MV_CHANGED) j=1;
                     if(mb_y>0           && fixed[mb_xy-mb_stride]==MV_CHANGED) j=1;
                     if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]==MV_CHANGED) j=1;
4d2858de
                     if(j==0 && pass>1) continue;
115329f1
 
4d2858de
                     none_left=0;
115329f1
 
7bc9090a
                     if(mb_x>0 && fixed[mb_xy-1]){
2c4bc23e
                         mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_step][0];
                         mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_step][1];
673fc638
                         ref         [pred_count]   = s->current_picture.ref_index[0][4*(mb_xy-1)];
4d2858de
                         pred_count++;
                     }
7bc9090a
                     if(mb_x+1<mb_width && fixed[mb_xy+1]){
2c4bc23e
                         mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_step][0];
                         mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_step][1];
673fc638
                         ref         [pred_count]   = s->current_picture.ref_index[0][4*(mb_xy+1)];
4d2858de
                         pred_count++;
                     }
7bc9090a
                     if(mb_y>0 && fixed[mb_xy-mb_stride]){
2c4bc23e
                         mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][0];
                         mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][1];
673fc638
                         ref         [pred_count]   = s->current_picture.ref_index[0][4*(mb_xy-s->mb_stride)];
4d2858de
                         pred_count++;
                     }
7bc9090a
                     if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]){
2c4bc23e
                         mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][0];
                         mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][1];
673fc638
                         ref         [pred_count]   = s->current_picture.ref_index[0][4*(mb_xy+s->mb_stride)];
4d2858de
                         pred_count++;
                     }
                     if(pred_count==0) continue;
115329f1
 
4d2858de
                     if(pred_count>1){
673fc638
                         int sum_x=0, sum_y=0, sum_r=0;
                         int max_x, max_y, min_x, min_y, max_r, min_r;
4d2858de
 
                         for(j=0; j<pred_count; j++){
                             sum_x+= mv_predictor[j][0];
                             sum_y+= mv_predictor[j][1];
673fc638
                             sum_r+= ref[j];
fc4a2d1e
                             if(j && ref[j] != ref[j-1])
673fc638
                                 goto skip_mean_and_median;
4d2858de
                         }
115329f1
 
4d2858de
                         /* mean */
                         mv_predictor[pred_count][0] = sum_x/j;
                         mv_predictor[pred_count][1] = sum_y/j;
673fc638
                         ref         [pred_count]    = sum_r/j;
115329f1
 
4d2858de
                         /* median */
                         if(pred_count>=3){
673fc638
                             min_y= min_x= min_r= 99999;
                             max_y= max_x= max_r=-99999;
4d2858de
                         }else{
673fc638
                             min_x=min_y=max_x=max_y=min_r=max_r=0;
4d2858de
                         }
                         for(j=0; j<pred_count; j++){
b8a78f41
                             max_x= FFMAX(max_x, mv_predictor[j][0]);
                             max_y= FFMAX(max_y, mv_predictor[j][1]);
673fc638
                             max_r= FFMAX(max_r, ref[j]);
b8a78f41
                             min_x= FFMIN(min_x, mv_predictor[j][0]);
                             min_y= FFMIN(min_y, mv_predictor[j][1]);
673fc638
                             min_r= FFMIN(min_r, ref[j]);
4d2858de
                         }
                         mv_predictor[pred_count+1][0] = sum_x - max_x - min_x;
                         mv_predictor[pred_count+1][1] = sum_y - max_y - min_y;
673fc638
                         ref         [pred_count+1]    = sum_r - max_r - min_r;
115329f1
 
4d2858de
                         if(pred_count==4){
                             mv_predictor[pred_count+1][0] /= 2;
                             mv_predictor[pred_count+1][1] /= 2;
673fc638
                             ref         [pred_count+1]    /= 2;
4d2858de
                         }
                         pred_count+=2;
                     }
673fc638
 skip_mean_and_median:
115329f1
 
4d2858de
                     /* zero MV */
                     pred_count++;
 
99eb31e2
                     if (!fixed[mb_xy] && 0) {
6a9c8594
                         if (s->avctx->codec_id == CODEC_ID_H264) {
                             // FIXME
                         } else {
                             ff_thread_await_progress((AVFrame *) s->last_picture_ptr,
                                                      mb_y, 0);
                         }
20153fb8
                         if (!s->last_picture.motion_val[0] ||
                             !s->last_picture.ref_index[0])
                             goto skip_last_mv;
6a9c8594
                         prev_x = s->last_picture.motion_val[0][mot_index][0];
                         prev_y = s->last_picture.motion_val[0][mot_index][1];
                         prev_ref = s->last_picture.ref_index[0][4*mb_xy];
                     } else {
                         prev_x = s->current_picture.motion_val[0][mot_index][0];
                         prev_y = s->current_picture.motion_val[0][mot_index][1];
                         prev_ref = s->current_picture.ref_index[0][4*mb_xy];
                     }
 
4d2858de
                     /* last MV */
6a9c8594
                     mv_predictor[pred_count][0]= prev_x;
                     mv_predictor[pred_count][1]= prev_y;
                     ref         [pred_count]   = prev_ref;
115329f1
                     pred_count++;
20153fb8
                 skip_last_mv:
115329f1
 
4d2858de
                     s->mv_dir = MV_DIR_FORWARD;
                     s->mb_intra=0;
                     s->mv_type = MV_TYPE_16X16;
160d679c
                     s->mb_skipped=0;
4d2858de
 
bb270c08
                     s->dsp.clear_blocks(s->block[0]);
4d2858de
 
                     s->mb_x= mb_x;
                     s->mb_y= mb_y;
7bc9090a
 
4d2858de
                     for(j=0; j<pred_count; j++){
                         int score=0;
0c1a9eda
                         uint8_t *src= s->current_picture.data[0] + mb_x*16 + mb_y*16*s->linesize;
4d2858de
 
8d7ec294
                         s->current_picture.motion_val[0][mot_index][0]= s->mv[0][0][0]= mv_predictor[j][0];
                         s->current_picture.motion_val[0][mot_index][1]= s->mv[0][0][1]= mv_predictor[j][1];
7bc9090a
 
fc4a2d1e
                         if(ref[j]<0) //predictor intra or otherwise not available
673fc638
                             continue;
 
                         decode_mb(s, ref[j]);
115329f1
 
7bc9090a
                         if(mb_x>0 && fixed[mb_xy-1]){
4d2858de
                             int k;
                             for(k=0; k<16; k++)
c26abfa5
                                 score += FFABS(src[k*s->linesize-1 ]-src[k*s->linesize   ]);
4d2858de
                         }
7bc9090a
                         if(mb_x+1<mb_width && fixed[mb_xy+1]){
4d2858de
                             int k;
                             for(k=0; k<16; k++)
c26abfa5
                                 score += FFABS(src[k*s->linesize+15]-src[k*s->linesize+16]);
4d2858de
                         }
7bc9090a
                         if(mb_y>0 && fixed[mb_xy-mb_stride]){
4d2858de
                             int k;
                             for(k=0; k<16; k++)
c26abfa5
                                 score += FFABS(src[k-s->linesize   ]-src[k               ]);
4d2858de
                         }
7bc9090a
                         if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]){
4d2858de
                             int k;
                             for(k=0; k<16; k++)
c26abfa5
                                 score += FFABS(src[k+s->linesize*15]-src[k+s->linesize*16]);
4d2858de
                         }
115329f1
 
4d2858de
                         if(score <= best_score){ // <= will favor the last MV
                             best_score= score;
                             best_pred= j;
                         }
                     }
 score_sum+= best_score;
686c7817
                     s->mv[0][0][0]= mv_predictor[best_pred][0];
                     s->mv[0][0][1]= mv_predictor[best_pred][1];
 
                     for(i=0; i<mot_step; i++)
                         for(j=0; j<mot_step; j++){
                             s->current_picture.motion_val[0][mot_index+i+j*mot_stride][0]= s->mv[0][0][0];
                             s->current_picture.motion_val[0][mot_index+i+j*mot_stride][1]= s->mv[0][0][1];
                         }
4d2858de
 
673fc638
                     decode_mb(s, ref[best_pred]);
4d2858de
 
115329f1
 
4d2858de
                     if(s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y){
7bc9090a
                         fixed[mb_xy]=MV_CHANGED;
4d2858de
                         changed++;
                     }else
7bc9090a
                         fixed[mb_xy]=MV_UNCHANGED;
4d2858de
                 }
             }
 
 //            printf(".%d/%d", changed, score_sum); fflush(stdout);
         }
115329f1
 
         if(none_left)
4d2858de
             return;
115329f1
 
4d2858de
         for(i=0; i<s->mb_num; i++){
7bc9090a
             int mb_xy= s->mb_index2xy[i];
             if(fixed[mb_xy])
                 fixed[mb_xy]=MV_FROZEN;
4d2858de
         }
 //        printf(":"); fflush(stdout);
     }
 }
115329f1
 
4d2858de
 static int is_intra_more_likely(MpegEncContext *s){
     int is_intra_likely, i, j, undamaged_count, skip_amount, mb_x, mb_y;
115329f1
 
68997192
     if(!s->last_picture_ptr || !s->last_picture_ptr->data[0]) return 1; //no previous frame available -> use spatial prediction
4d2858de
 
     undamaged_count=0;
     for(i=0; i<s->mb_num; i++){
7bc9090a
         const int mb_xy= s->mb_index2xy[i];
         const int error= s->error_status_table[mb_xy];
4d2858de
         if(!((error&DC_ERROR) && (error&MV_ERROR)))
             undamaged_count++;
     }
115329f1
 
c28112fa
     if(s->codec_id == CODEC_ID_H264){
         H264Context *h= (void*)s;
d2a276a3
         if (h->list_count <= 0 || h->ref_count[0] <= 0 || !h->ref_list[0][0].data[0])
c28112fa
             return 1;
     }
 
04932b0d
     if(undamaged_count < 5) return 0; //almost all MBs damaged -> use temporal prediction
115329f1
 
551109d4
     //prevent dsp.sad() check, that requires access to the image
ce5e49b0
     if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration && s->pict_type == AV_PICTURE_TYPE_I)
83344066
         return 1;
551109d4
 
115329f1
     skip_amount= FFMAX(undamaged_count/50, 1); //check only upto 50 MBs
4d2858de
     is_intra_likely=0;
 
     j=0;
     for(mb_y= 0; mb_y<s->mb_height-1; mb_y++){
         for(mb_x= 0; mb_x<s->mb_width; mb_x++){
             int error;
7bc9090a
             const int mb_xy= mb_x + mb_y*s->mb_stride;
4d2858de
 
7bc9090a
             error= s->error_status_table[mb_xy];
4d2858de
             if((error&DC_ERROR) && (error&MV_ERROR))
                 continue; //skip damaged
115329f1
 
             j++;
4d2858de
             if((j%skip_amount) != 0) continue; //skip a few to speed things up
115329f1
 
ce5e49b0
             if(s->pict_type==AV_PICTURE_TYPE_I){
0c1a9eda
                 uint8_t *mb_ptr     = s->current_picture.data[0] + mb_x*16 + mb_y*16*s->linesize;
                 uint8_t *last_mb_ptr= s->last_picture.data   [0] + mb_x*16 + mb_y*16*s->linesize;
115329f1
 
6a9c8594
                 if (s->avctx->codec_id == CODEC_ID_H264) {
                     // FIXME
                 } else {
                     ff_thread_await_progress((AVFrame *) s->last_picture_ptr,
                                              mb_y, 0);
                 }
bb270c08
                 is_intra_likely += s->dsp.sad[0](NULL, last_mb_ptr, mb_ptr                    , s->linesize, 16);
a811ec7c
                 // FIXME need await_progress() here
bb198e19
                 is_intra_likely -= s->dsp.sad[0](NULL, last_mb_ptr, last_mb_ptr+s->linesize*16, s->linesize, 16);
4d2858de
             }else{
7bc9090a
                 if(IS_INTRA(s->current_picture.mb_type[mb_xy]))
4d2858de
                    is_intra_likely++;
                 else
                    is_intra_likely--;
             }
         }
     }
 //printf("is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
115329f1
     return is_intra_likely > 0;
4d2858de
 }
 
46b4feec
 void ff_er_frame_start(MpegEncContext *s){
047599a4
     if(!s->error_recognition) return;
46b4feec
 
7bc9090a
     memset(s->error_status_table, MV_ERROR|AC_ERROR|DC_ERROR|VP_START|AC_END|DC_END|MV_END, s->mb_stride*s->mb_height*sizeof(uint8_t));
     s->error_count= 3*s->mb_num;
6a9c8594
     s->error_occurred = 0;
46b4feec
 }
 
 /**
  * adds a slice.
  * @param endx x component of the last macroblock, can be -1 for the last of the previous line
  * @param status the status at the end (MV_END, AC_ERROR, ...), it is assumed that no earlier end or
d9526386
  *               error of the same type occurred
46b4feec
  */
 void ff_er_add_slice(MpegEncContext *s, int startx, int starty, int endx, int endy, int status){
f66e4f5f
     const int start_i= av_clip(startx + starty * s->mb_width    , 0, s->mb_num-1);
     const int end_i  = av_clip(endx   + endy   * s->mb_width    , 0, s->mb_num);
7bc9090a
     const int start_xy= s->mb_index2xy[start_i];
     const int end_xy  = s->mb_index2xy[end_i];
46b4feec
     int mask= -1;
04cfef21
 
11647a9f
     if(s->avctx->hwaccel)
         return;
 
04cfef21
     if(start_i > end_i || start_xy > end_xy){
         av_log(s->avctx, AV_LOG_ERROR, "internal error, slice end before start\n");
         return;
     }
115329f1
 
047599a4
     if(!s->error_recognition) return;
46b4feec
 
     mask &= ~VP_START;
7bc9090a
     if(status & (AC_ERROR|AC_END)){
         mask &= ~(AC_ERROR|AC_END);
         s->error_count -= end_i - start_i + 1;
     }
     if(status & (DC_ERROR|DC_END)){
         mask &= ~(DC_ERROR|DC_END);
         s->error_count -= end_i - start_i + 1;
     }
     if(status & (MV_ERROR|MV_END)){
         mask &= ~(MV_ERROR|MV_END);
         s->error_count -= end_i - start_i + 1;
     }
 
6a9c8594
     if(status & (AC_ERROR|DC_ERROR|MV_ERROR)) {
         s->error_occurred = 1;
         s->error_count= INT_MAX;
     }
46b4feec
 
     if(mask == ~0x7F){
7bc9090a
         memset(&s->error_status_table[start_xy], 0, (end_xy - start_xy) * sizeof(uint8_t));
46b4feec
     }else{
         int i;
         for(i=start_xy; i<end_xy; i++){
7bc9090a
             s->error_status_table[ i ] &= mask;
46b4feec
         }
     }
7bc9090a
 
115329f1
     if(end_i == s->mb_num)
7bc9090a
         s->error_count= INT_MAX;
     else{
46b4feec
         s->error_status_table[end_xy] &= mask;
         s->error_status_table[end_xy] |= status;
     }
115329f1
 
0aae3f43
     s->error_status_table[start_xy] |= VP_START;
7bc9090a
 
0dfd33c3
     if(start_xy > 0 && s->avctx->thread_count <= 1 && s->avctx->skip_top*s->mb_width < start_i){
7bc9090a
         int prev_status= s->error_status_table[ s->mb_index2xy[start_i - 1] ];
115329f1
 
7bc9090a
         prev_status &= ~ VP_START;
         if(prev_status != (MV_END|DC_END|AC_END)) s->error_count= INT_MAX;
     }
46b4feec
 }
 
 void ff_er_frame_end(MpegEncContext *s){
4cfbbbde
     int i, mb_x, mb_y, error, error_type, dc_error, mv_error, ac_error;
4d2858de
     int distance;
     int threshold_part[4]= {100,100,100};
     int threshold= 50;
     int is_intra_likely;
ec892563
     int size = s->b8_stride * 2 * s->mb_height;
     Picture *pic= s->current_picture_ptr;
115329f1
 
8c07cee9
     if(!s->error_recognition || s->error_count==0 || s->avctx->lowres ||
40e5d31b
        s->avctx->hwaccel ||
7eb6ed78
        s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU ||
fd1ef13b
        s->picture_structure != PICT_FRAME || // we dont support ER of field pictures yet, though it should not crash if enabled
0dfd33c3
        s->error_count==3*s->mb_width*(s->avctx->skip_top + s->avctx->skip_bottom)) return;
46b4feec
 
8d7ec294
     if(s->current_picture.motion_val[0] == NULL){
9b879566
         av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n");
115329f1
 
967be700
         for(i=0; i<2; i++){
358b5b1a
             pic->ref_index[i]= av_mallocz(s->mb_stride * s->mb_height * 4 * sizeof(uint8_t));
02dc8983
             pic->motion_val_base[i]= av_mallocz((size+4) * 2 * sizeof(uint16_t));
             pic->motion_val[i]= pic->motion_val_base[i]+4;
967be700
         }
         pic->motion_subsample_log2= 3;
         s->current_picture= *s->current_picture_ptr;
46b4feec
     }
115329f1
 
7bc9090a
     if(s->avctx->debug&FF_DEBUG_ER){
         for(mb_y=0; mb_y<s->mb_height; mb_y++){
             for(mb_x=0; mb_x<s->mb_width; mb_x++){
                 int status= s->error_status_table[mb_x + mb_y*s->mb_stride];
115329f1
 
                 av_log(s->avctx, AV_LOG_DEBUG, "%2X ", status);
7bc9090a
             }
9b879566
             av_log(s->avctx, AV_LOG_DEBUG, "\n");
46b4feec
         }
     }
115329f1
 
7b9e9817
 #if 1
4d2858de
     /* handle overlapping slices */
     for(error_type=1; error_type<=3; error_type++){
         int end_ok=0;
 
         for(i=s->mb_num-1; i>=0; i--){
7bc9090a
             const int mb_xy= s->mb_index2xy[i];
             int error= s->error_status_table[mb_xy];
115329f1
 
4d2858de
             if(error&(1<<error_type))
                 end_ok=1;
             if(error&(8<<error_type))
                 end_ok=1;
 
             if(!end_ok)
7bc9090a
                 s->error_status_table[mb_xy]|= 1<<error_type;
4d2858de
 
             if(error&VP_START)
                 end_ok=0;
         }
     }
7b9e9817
 #endif
 #if 1
4d2858de
     /* handle slices with partitions of different length */
     if(s->partitioned_frame){
         int end_ok=0;
 
         for(i=s->mb_num-1; i>=0; i--){
7bc9090a
             const int mb_xy= s->mb_index2xy[i];
             int error= s->error_status_table[mb_xy];
115329f1
 
4d2858de
             if(error&AC_END)
                 end_ok=0;
             if((error&MV_END) || (error&DC_END) || (error&AC_ERROR))
                 end_ok=1;
 
             if(!end_ok)
7bc9090a
                 s->error_status_table[mb_xy]|= AC_ERROR;
4d2858de
 
             if(error&VP_START)
                 end_ok=0;
         }
     }
7b9e9817
 #endif
4d2858de
     /* handle missing slices */
047599a4
     if(s->error_recognition>=4){
4d2858de
         int end_ok=1;
115329f1
 
4d2858de
         for(i=s->mb_num-2; i>=s->mb_width+100; i--){ //FIXME +100 hack
7bc9090a
             const int mb_xy= s->mb_index2xy[i];
             int error1= s->error_status_table[mb_xy  ];
db6e7795
             int error2= s->error_status_table[s->mb_index2xy[i+1]];
115329f1
 
4d2858de
             if(error1&VP_START)
                 end_ok=1;
115329f1
 
4d2858de
             if(   error2==(VP_START|DC_ERROR|AC_ERROR|MV_ERROR|AC_END|DC_END|MV_END)
115329f1
                && error1!=(VP_START|DC_ERROR|AC_ERROR|MV_ERROR|AC_END|DC_END|MV_END)
5e534865
                && ((error1&AC_END) || (error1&DC_END) || (error1&MV_END))){ //end & uninit
4d2858de
                 end_ok=0;
             }
115329f1
 
4d2858de
             if(!end_ok)
7bc9090a
                 s->error_status_table[mb_xy]|= DC_ERROR|AC_ERROR|MV_ERROR;
4d2858de
         }
     }
115329f1
 
7b9e9817
 #if 1
4d2858de
     /* backward mark errors */
     distance=9999999;
     for(error_type=1; error_type<=3; error_type++){
         for(i=s->mb_num-1; i>=0; i--){
7bc9090a
             const int mb_xy= s->mb_index2xy[i];
             int error= s->error_status_table[mb_xy];
115329f1
 
7bc9090a
             if(!s->mbskip_table[mb_xy]) //FIXME partition specific
115329f1
                 distance++;
4d2858de
             if(error&(1<<error_type))
                 distance= 0;
 
             if(s->partitioned_frame){
                 if(distance < threshold_part[error_type-1])
7bc9090a
                     s->error_status_table[mb_xy]|= 1<<error_type;
4d2858de
             }else{
                 if(distance < threshold)
7bc9090a
                     s->error_status_table[mb_xy]|= 1<<error_type;
4d2858de
             }
 
             if(error&VP_START)
                 distance= 9999999;
         }
     }
7b9e9817
 #endif
4d2858de
 
     /* forward mark errors */
     error=0;
     for(i=0; i<s->mb_num; i++){
7bc9090a
         const int mb_xy= s->mb_index2xy[i];
         int old_error= s->error_status_table[mb_xy];
115329f1
 
4d2858de
         if(old_error&VP_START)
             error= old_error& (DC_ERROR|AC_ERROR|MV_ERROR);
         else{
             error|= old_error& (DC_ERROR|AC_ERROR|MV_ERROR);
7bc9090a
             s->error_status_table[mb_xy]|= error;
4d2858de
         }
     }
7b9e9817
 #if 1
4d2858de
     /* handle not partitioned case */
     if(!s->partitioned_frame){
         for(i=0; i<s->mb_num; i++){
7bc9090a
             const int mb_xy= s->mb_index2xy[i];
             error= s->error_status_table[mb_xy];
4d2858de
             if(error&(AC_ERROR|DC_ERROR|MV_ERROR))
                 error|= AC_ERROR|DC_ERROR|MV_ERROR;
7bc9090a
             s->error_status_table[mb_xy]= error;
4d2858de
         }
     }
7b9e9817
 #endif
4cfbbbde
 
     dc_error= ac_error= mv_error=0;
     for(i=0; i<s->mb_num; i++){
         const int mb_xy= s->mb_index2xy[i];
         error= s->error_status_table[mb_xy];
         if(error&DC_ERROR) dc_error ++;
         if(error&AC_ERROR) ac_error ++;
         if(error&MV_ERROR) mv_error ++;
     }
     av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors\n", dc_error, ac_error, mv_error);
 
4d2858de
     is_intra_likely= is_intra_more_likely(s);
 
     /* set unknown mb-type to most likely */
     for(i=0; i<s->mb_num; i++){
7bc9090a
         const int mb_xy= s->mb_index2xy[i];
         error= s->error_status_table[mb_xy];
         if(!((error&DC_ERROR) && (error&MV_ERROR)))
             continue;
4d2858de
 
7bc9090a
         if(is_intra_likely)
             s->current_picture.mb_type[mb_xy]= MB_TYPE_INTRA4x4;
4d2858de
         else
7bc9090a
             s->current_picture.mb_type[mb_xy]= MB_TYPE_16x16 | MB_TYPE_L0;
4d2858de
     }
115329f1
 
b6b66760
     // change inter to intra blocks if no reference frames are available
     if (!s->last_picture.data[0] && !s->next_picture.data[0])
         for(i=0; i<s->mb_num; i++){
             const int mb_xy= s->mb_index2xy[i];
             if(!IS_INTRA(s->current_picture.mb_type[mb_xy]))
                 s->current_picture.mb_type[mb_xy]= MB_TYPE_INTRA4x4;
         }
 
4d2858de
     /* handle inter blocks with damaged AC */
     for(mb_y=0; mb_y<s->mb_height; mb_y++){
         for(mb_x=0; mb_x<s->mb_width; mb_x++){
7bc9090a
             const int mb_xy= mb_x + mb_y * s->mb_stride;
             const int mb_type= s->current_picture.mb_type[mb_xy];
b6b66760
             int dir = !s->last_picture.data[0];
7bc9090a
             error= s->error_status_table[mb_xy];
4d2858de
 
7bc9090a
             if(IS_INTRA(mb_type)) continue; //intra
4d2858de
             if(error&MV_ERROR) continue;              //inter with damaged MV
             if(!(error&AC_ERROR)) continue;           //undamaged inter
115329f1
 
b6b66760
             s->mv_dir = dir ? MV_DIR_BACKWARD : MV_DIR_FORWARD;
4d2858de
             s->mb_intra=0;
160d679c
             s->mb_skipped=0;
7bc9090a
             if(IS_8X8(mb_type)){
137c8468
                 int mb_index= mb_x*2 + mb_y*2*s->b8_stride;
4d2858de
                 int j;
                 s->mv_type = MV_TYPE_8X8;
                 for(j=0; j<4; j++){
b6b66760
                     s->mv[0][j][0] = s->current_picture.motion_val[dir][ mb_index + (j&1) + (j>>1)*s->b8_stride ][0];
                     s->mv[0][j][1] = s->current_picture.motion_val[dir][ mb_index + (j&1) + (j>>1)*s->b8_stride ][1];
4d2858de
                 }
             }else{
                 s->mv_type = MV_TYPE_16X16;
b6b66760
                 s->mv[0][0][0] = s->current_picture.motion_val[dir][ mb_x*2 + mb_y*2*s->b8_stride ][0];
                 s->mv[0][0][1] = s->current_picture.motion_val[dir][ mb_x*2 + mb_y*2*s->b8_stride ][1];
4d2858de
             }
115329f1
 
bb270c08
             s->dsp.clear_blocks(s->block[0]);
4d2858de
 
             s->mb_x= mb_x;
             s->mb_y= mb_y;
673fc638
             decode_mb(s, 0/*FIXME h264 partitioned slices need this set*/);
4d2858de
         }
     }
 
     /* guess MVs */
ce5e49b0
     if(s->pict_type==AV_PICTURE_TYPE_B){
4d2858de
         for(mb_y=0; mb_y<s->mb_height; mb_y++){
             for(mb_x=0; mb_x<s->mb_width; mb_x++){
137c8468
                 int xy= mb_x*2 + mb_y*2*s->b8_stride;
7bc9090a
                 const int mb_xy= mb_x + mb_y * s->mb_stride;
                 const int mb_type= s->current_picture.mb_type[mb_xy];
                 error= s->error_status_table[mb_xy];
4d2858de
 
7bc9090a
                 if(IS_INTRA(mb_type)) continue;
4d2858de
                 if(!(error&MV_ERROR)) continue;           //inter with undamaged MV
                 if(!(error&AC_ERROR)) continue;           //undamaged inter
115329f1
 
4d2858de
                 s->mv_dir = MV_DIR_FORWARD|MV_DIR_BACKWARD;
b6b66760
                 if(!s->last_picture.data[0]) s->mv_dir &= ~MV_DIR_FORWARD;
                 if(!s->next_picture.data[0]) s->mv_dir &= ~MV_DIR_BACKWARD;
4d2858de
                 s->mb_intra=0;
                 s->mv_type = MV_TYPE_16X16;
160d679c
                 s->mb_skipped=0;
115329f1
 
4d2858de
                 if(s->pp_time){
                     int time_pp= s->pp_time;
                     int time_pb= s->pb_time;
115329f1
 
6a9c8594
                     if (s->avctx->codec_id == CODEC_ID_H264) {
                         //FIXME
                     } else {
                         ff_thread_await_progress((AVFrame *) s->next_picture_ptr,
                                                  mb_y, 0);
                     }
8d7ec294
                     s->mv[0][0][0] = s->next_picture.motion_val[0][xy][0]*time_pb/time_pp;
                     s->mv[0][0][1] = s->next_picture.motion_val[0][xy][1]*time_pb/time_pp;
                     s->mv[1][0][0] = s->next_picture.motion_val[0][xy][0]*(time_pb - time_pp)/time_pp;
                     s->mv[1][0][1] = s->next_picture.motion_val[0][xy][1]*(time_pb - time_pp)/time_pp;
4d2858de
                 }else{
                     s->mv[0][0][0]= 0;
                     s->mv[0][0][1]= 0;
                     s->mv[1][0][0]= 0;
                     s->mv[1][0][1]= 0;
                 }
eb4b3dd3
 
                 s->dsp.clear_blocks(s->block[0]);
4d2858de
                 s->mb_x= mb_x;
                 s->mb_y= mb_y;
673fc638
                 decode_mb(s, 0);
4d2858de
             }
         }
     }else
         guess_mv(s);
 
2e7b4c84
     /* the filters below are not XvMC compatible, skip them */
83344066
     if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
         goto ec_clean;
4d2858de
     /* fill DC for inter blocks */
     for(mb_y=0; mb_y<s->mb_height; mb_y++){
         for(mb_x=0; mb_x<s->mb_width; mb_x++){
             int dc, dcu, dcv, y, n;
b86216de
             int16_t *dc_ptr;
0c1a9eda
             uint8_t *dest_y, *dest_cb, *dest_cr;
7bc9090a
             const int mb_xy= mb_x + mb_y * s->mb_stride;
             const int mb_type= s->current_picture.mb_type[mb_xy];
115329f1
 
7bc9090a
             error= s->error_status_table[mb_xy];
4d2858de
 
7bc9090a
             if(IS_INTRA(mb_type) && s->partitioned_frame) continue;
4d2858de
 //            if(error&MV_ERROR) continue; //inter data damaged FIXME is this good?
115329f1
 
1e491e29
             dest_y = s->current_picture.data[0] + mb_x*16 + mb_y*16*s->linesize;
             dest_cb= s->current_picture.data[1] + mb_x*8  + mb_y*8 *s->uvlinesize;
             dest_cr= s->current_picture.data[2] + mb_x*8  + mb_y*8 *s->uvlinesize;
115329f1
 
137c8468
             dc_ptr= &s->dc_val[0][mb_x*2 + mb_y*2*s->b8_stride];
4d2858de
             for(n=0; n<4; n++){
                 dc=0;
                 for(y=0; y<8; y++){
                     int x;
                     for(x=0; x<8; x++){
                        dc+= dest_y[x + (n&1)*8 + (y + (n>>1)*8)*s->linesize];
                     }
                 }
137c8468
                 dc_ptr[(n&1) + (n>>1)*s->b8_stride]= (dc+4)>>3;
4d2858de
             }
 
             dcu=dcv=0;
             for(y=0; y<8; y++){
                 int x;
                 for(x=0; x<8; x++){
                     dcu+=dest_cb[x + y*(s->uvlinesize)];
                     dcv+=dest_cr[x + y*(s->uvlinesize)];
                 }
             }
137c8468
             s->dc_val[1][mb_x + mb_y*s->mb_stride]= (dcu+4)>>3;
115329f1
             s->dc_val[2][mb_x + mb_y*s->mb_stride]= (dcv+4)>>3;
4d2858de
         }
     }
7b9e9817
 #if 1
4d2858de
     /* guess DC for damaged blocks */
137c8468
     guess_dc(s, s->dc_val[0], s->mb_width*2, s->mb_height*2, s->b8_stride, 1);
     guess_dc(s, s->dc_val[1], s->mb_width  , s->mb_height  , s->mb_stride, 0);
     guess_dc(s, s->dc_val[2], s->mb_width  , s->mb_height  , s->mb_stride, 0);
7b9e9817
 #endif
4d2858de
     /* filter luma DC */
137c8468
     filter181(s->dc_val[0], s->mb_width*2, s->mb_height*2, s->b8_stride);
115329f1
 
7b9e9817
 #if 1
4d2858de
     /* render DC only intra */
     for(mb_y=0; mb_y<s->mb_height; mb_y++){
         for(mb_x=0; mb_x<s->mb_width; mb_x++){
0c1a9eda
             uint8_t *dest_y, *dest_cb, *dest_cr;
7bc9090a
             const int mb_xy= mb_x + mb_y * s->mb_stride;
             const int mb_type= s->current_picture.mb_type[mb_xy];
 
             error= s->error_status_table[mb_xy];
4d2858de
 
7bc9090a
             if(IS_INTER(mb_type)) continue;
4d2858de
             if(!(error&AC_ERROR)) continue;              //undamaged
115329f1
 
1e491e29
             dest_y = s->current_picture.data[0] + mb_x*16 + mb_y*16*s->linesize;
             dest_cb= s->current_picture.data[1] + mb_x*8  + mb_y*8 *s->uvlinesize;
             dest_cr= s->current_picture.data[2] + mb_x*8  + mb_y*8 *s->uvlinesize;
115329f1
 
4d2858de
             put_dc(s, dest_y, dest_cb, dest_cr, mb_x, mb_y);
         }
     }
7b9e9817
 #endif
115329f1
 
4d2858de
     if(s->avctx->error_concealment&FF_EC_DEBLOCK){
         /* filter horizontal block boundaries */
1e491e29
         h_block_filter(s, s->current_picture.data[0], s->mb_width*2, s->mb_height*2, s->linesize  , 1);
         h_block_filter(s, s->current_picture.data[1], s->mb_width  , s->mb_height  , s->uvlinesize, 0);
         h_block_filter(s, s->current_picture.data[2], s->mb_width  , s->mb_height  , s->uvlinesize, 0);
4d2858de
 
         /* filter vertical block boundaries */
1e491e29
         v_block_filter(s, s->current_picture.data[0], s->mb_width*2, s->mb_height*2, s->linesize  , 1);
         v_block_filter(s, s->current_picture.data[1], s->mb_width  , s->mb_height  , s->uvlinesize, 0);
         v_block_filter(s, s->current_picture.data[2], s->mb_width  , s->mb_height  , s->uvlinesize, 0);
4d2858de
     }
 
2e7b4c84
 ec_clean:
4d2858de
     /* clean a few tables */
     for(i=0; i<s->mb_num; i++){
7bc9090a
         const int mb_xy= s->mb_index2xy[i];
         int error= s->error_status_table[mb_xy];
115329f1
 
ce5e49b0
         if(s->pict_type!=AV_PICTURE_TYPE_B && (error&(DC_ERROR|MV_ERROR|AC_ERROR))){
7bc9090a
             s->mbskip_table[mb_xy]=0;
4d2858de
         }
7bc9090a
         s->mbintra_table[mb_xy]=1;
115329f1
     }
4d2858de
 }