2002-10-13 13:16:04 +00:00
/*
* Error resilience / concealment
*
2004-01-10 16:04:55 +00:00
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
2002-10-13 13:16:04 +00:00
*
2011-03-18 17:35:10 +00:00
* This file is part of Libav.
2006-10-07 15:30:46 +00:00
*
2011-03-18 17:35:10 +00:00
* Libav is free software; you can redistribute it and/or
2002-10-13 13:16:04 +00:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
2006-10-07 15:30:46 +00:00
* version 2.1 of the License, or (at your option) any later version.
2002-10-13 13:16:04 +00:00
*
2011-03-18 17:35:10 +00:00
* Libav is distributed in the hope that it will be useful,
2002-10-13 13:16:04 +00:00
* 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
2011-03-18 17:35:10 +00:00
* License along with Libav; if not, write to the Free Software
2006-01-12 22:43:26 +00:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2002-10-13 13:16:04 +00:00
*/
2005-12-17 18:14:38 +00:00
2003-03-06 11:32:04 +00:00
/**
2010-04-20 14:45:34 +00:00
* @file
2003-03-06 11:32:04 +00:00
* Error resilience / concealment.
*/
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
#include <limits.h>
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
2010-03-12 16:59:21 +00:00
#include "h264.h"
2010-04-13 22:52:14 +00:00
#include "rectangle.h"
2011-06-02 10:15:58 -07:00
#include "thread.h"
2010-03-12 16:59:21 +00:00
/*
* 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
2002-10-13 13:16:04 +00:00
2010-03-20 00:52:08 +00:00
static void decode_mb ( MpegEncContext * s , int ref ){
2011-07-06 20:08:30 +02:00
s -> dest [ 0 ] = s -> current_picture . f . data [ 0 ] + ( s -> mb_y * 16 * s -> linesize ) + s -> mb_x * 16 ;
s -> dest [ 1 ] = s -> current_picture . f . 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 . f . data [ 2 ] + ( s -> mb_y * ( 16 >> s -> chroma_y_shift ) * s -> uvlinesize ) + s -> mb_x * ( 16 >> s -> chroma_x_shift );
2003-07-29 02:09:12 +00:00
2010-03-20 23:18:07 +00:00
if ( CONFIG_H264_DECODER && s -> codec_id == CODEC_ID_H264 ){
2010-03-17 02:59:12 +00:00
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 ));
2010-03-20 00:52:08 +00:00
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 ;
2011-07-06 20:08:30 +02:00
fill_rectangle ( & s -> current_picture . f . ref_index [ 0 ][ 4 * h -> mb_xy ], 2 , 2 , 2 , ref , 1 );
2010-03-20 00:52:08 +00:00
fill_rectangle ( & h -> ref_cache [ 0 ][ scan8 [ 0 ]], 4 , 4 , 8 , ref , 1 );
2010-03-17 02:59:12 +00:00
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 {
2010-03-20 00:52:08 +00:00
assert ( ref == 0 );
2005-12-17 18:14:38 +00:00
MPV_decode_mb ( s , s -> block );
2010-03-17 02:59:12 +00:00
}
2003-07-29 02:09:12 +00:00
}
2010-03-12 16:59:21 +00:00
/**
* @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 ;
}
}
2002-10-13 13:16:04 +00:00
/**
* 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 ++ ){
2004-04-16 01:01:45 +00:00
dc = s -> dc_val [ 0 ][ mb_x * 2 + ( i & 1 ) + ( mb_y * 2 + ( i >> 1 )) * s -> b8_stride ];
2002-10-13 13:16:04 +00:00
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 ;
}
}
}
2004-04-16 01:01:45 +00:00
dcu = s -> dc_val [ 1 ][ mb_x + mb_y * s -> mb_stride ];
dcv = s -> dc_val [ 2 ][ mb_x + mb_y * s -> mb_stride ];
2002-10-13 13:16:04 +00:00
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 ;
}
}
}
2006-09-27 22:13:44 +00:00
static void filter181 ( int16_t * data , int width , int height , int stride ){
2002-10-13 13:16:04 +00:00
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 ;
2005-12-17 18:14:38 +00:00
dc = - prev_dc
2002-10-13 13:16:04 +00:00
+ 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 ;
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* vertical filter */
for ( x = 1 ; x < width - 1 ; x ++ ){
int prev_dc = data [ x ];
for ( y = 1 ; y < height - 1 ; y ++ ){
int dc ;
2005-12-17 18:14:38 +00:00
dc = - prev_dc
2002-10-13 13:16:04 +00:00
+ 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 ;
}
}
}
/**
2007-06-12 09:29:25 +00:00
* guess the dc of blocks which do not have an undamaged dc
2005-12-22 01:10:11 +00:00
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
2002-10-13 13:16:04 +00:00
*/
2006-09-27 22:13:44 +00:00
static void guess_dc ( MpegEncContext * s , int16_t * dc , int w , int h , int stride , int is_luma ){
2002-10-13 13:16:04 +00:00
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 ;
2003-02-11 16:35:48 +00:00
int64_t guess , weight_sum ;
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
mb_index = ( b_x >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
error = s -> error_status_table [ mb_index ];
2005-12-17 18:14:38 +00:00
2011-07-06 20:08:30 +02:00
if ( IS_INTER ( s -> current_picture . f . mb_type [ mb_index ])) continue ; //inter
2002-10-13 13:16:04 +00:00
if ( ! ( error & DC_ERROR )) continue ; //dc-ok
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* right block */
for ( j = b_x + 1 ; j < w ; j ++ ){
2003-04-10 13:18:38 +00:00
int mb_index_j = ( j >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
int error_j = s -> error_status_table [ mb_index_j ];
2011-07-06 20:08:30 +02:00
int intra_j = IS_INTRA ( s -> current_picture . f . mb_type [ mb_index_j ]);
2002-10-13 13:16:04 +00:00
if ( intra_j == 0 || ! ( error_j & DC_ERROR )){
color [ 0 ] = dc [ j + b_y * stride ];
distance [ 0 ] = j - b_x ;
break ;
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* left block */
for ( j = b_x - 1 ; j >= 0 ; j -- ){
2003-04-10 13:18:38 +00:00
int mb_index_j = ( j >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
int error_j = s -> error_status_table [ mb_index_j ];
2011-07-06 20:08:30 +02:00
int intra_j = IS_INTRA ( s -> current_picture . f . mb_type [ mb_index_j ]);
2002-10-13 13:16:04 +00:00
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 ++ ){
2003-04-10 13:18:38 +00:00
int mb_index_j = ( b_x >> is_luma ) + ( j >> is_luma ) * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
int error_j = s -> error_status_table [ mb_index_j ];
2011-07-06 20:08:30 +02:00
int intra_j = IS_INTRA ( s -> current_picture . f . mb_type [ mb_index_j ]);
2002-10-13 13:16:04 +00:00
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 -- ){
2003-04-10 13:18:38 +00:00
int mb_index_j = ( b_x >> is_luma ) + ( j >> is_luma ) * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
int error_j = s -> error_status_table [ mb_index_j ];
2011-07-06 20:08:30 +02:00
int intra_j = IS_INTRA ( s -> current_picture . f . mb_type [ mb_index_j ]);
2002-10-13 13:16:04 +00:00
if ( intra_j == 0 || ! ( error_j & DC_ERROR )){
color [ 3 ] = dc [ b_x + j * stride ];
distance [ 3 ] = b_y - j ;
break ;
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
weight_sum = 0 ;
guess = 0 ;
for ( j = 0 ; j < 4 ; j ++ ){
2003-02-11 16:35:48 +00:00
int64_t weight = 256 * 256 * 256 * 16 / distance [ j ];
guess += weight * ( int64_t ) color [ j ];
2002-10-13 13:16:04 +00:00
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
2005-12-22 01:10:11 +00:00
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
2002-10-13 13:16:04 +00:00
*/
2003-02-11 16:35:48 +00:00
static void h_block_filter ( MpegEncContext * s , uint8_t * dst , int w , int h , int stride , int is_luma ){
2010-03-14 00:42:26 +00:00
int b_x , b_y , mvx_stride , mvy_stride ;
2006-11-12 20:08:09 +00:00
uint8_t * cm = ff_cropTbl + MAX_NEG_CROP ;
2010-03-14 00:42:26 +00:00
set_mv_strides ( s , & mvx_stride , & mvy_stride );
mvx_stride >>= is_luma ;
mvy_stride *= mvx_stride ;
2002-10-13 13:16:04 +00:00
for ( b_y = 0 ; b_y < h ; b_y ++ ){
for ( b_x = 0 ; b_x < w - 1 ; b_x ++ ){
int y ;
2003-04-10 13:18:38 +00:00
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 ];
2011-07-06 20:08:30 +02:00
int left_intra = IS_INTRA ( s -> current_picture . f . mb_type [( b_x >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ]);
int right_intra = IS_INTRA ( s -> current_picture . f . mb_type [(( b_x + 1 ) >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ]);
2002-10-13 13:16:04 +00:00
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 ;
2011-07-06 20:08:30 +02:00
int16_t * left_mv = s -> current_picture . f . motion_val [ 0 ][ mvy_stride * b_y + mvx_stride * b_x ];
int16_t * right_mv = s -> current_picture . f . motion_val [ 0 ][ mvy_stride * b_y + mvx_stride * ( b_x + 1 )];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( ! ( left_damage || right_damage )) continue ; // both undamaged
2005-12-17 18:14:38 +00:00
if ( ( ! left_intra ) && ( ! right_intra )
2006-10-11 23:17:58 +00:00
&& FFABS ( left_mv [ 0 ] - right_mv [ 0 ]) + FFABS ( left_mv [ 1 ] + right_mv [ 1 ]) < 2 ) continue ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
for ( y = 0 ; y < 8 ; y ++ ){
int a , b , c , d ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
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 ];
2005-12-17 18:14:38 +00:00
2006-10-11 23:17:58 +00:00
d = FFABS ( b ) - (( FFABS ( a ) + FFABS ( c ) + 1 ) >> 1 );
2002-11-10 11:46:59 +00:00
d = FFMAX ( d , 0 );
2002-10-13 13:16:04 +00:00
if ( b < 0 ) d = - d ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( d == 0 ) continue ;
if ( ! ( left_damage && right_damage ))
d = d * 16 / 9 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
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
2005-12-22 01:10:11 +00:00
* @param w width in 8 pixel blocks
* @param h height in 8 pixel blocks
2002-10-13 13:16:04 +00:00
*/
2003-02-11 16:35:48 +00:00
static void v_block_filter ( MpegEncContext * s , uint8_t * dst , int w , int h , int stride , int is_luma ){
2010-03-14 00:42:26 +00:00
int b_x , b_y , mvx_stride , mvy_stride ;
2006-11-12 20:08:09 +00:00
uint8_t * cm = ff_cropTbl + MAX_NEG_CROP ;
2010-03-14 00:42:26 +00:00
set_mv_strides ( s , & mvx_stride , & mvy_stride );
mvx_stride >>= is_luma ;
mvy_stride *= mvx_stride ;
2002-10-13 13:16:04 +00:00
for ( b_y = 0 ; b_y < h - 1 ; b_y ++ ){
for ( b_x = 0 ; b_x < w ; b_x ++ ){
int x ;
2003-04-10 13:18:38 +00:00
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 ];
2011-07-06 20:08:30 +02:00
int top_intra = IS_INTRA ( s -> current_picture . f . mb_type [( b_x >> is_luma ) + ( b_y >> is_luma ) * s -> mb_stride ]);
int bottom_intra = IS_INTRA ( s -> current_picture . f . mb_type [( b_x >> is_luma ) + (( b_y + 1 ) >> is_luma ) * s -> mb_stride ]);
2002-10-13 13:16:04 +00:00
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 ;
2011-07-06 20:08:30 +02:00
int16_t * top_mv = s -> current_picture . f . motion_val [ 0 ][ mvy_stride * b_y + mvx_stride * b_x ];
int16_t * bottom_mv = s -> current_picture . f . motion_val [ 0 ][ mvy_stride * ( b_y + 1 ) + mvx_stride * b_x ];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( ! ( top_damage || bottom_damage )) continue ; // both undamaged
2005-12-17 18:14:38 +00:00
if ( ( ! top_intra ) && ( ! bottom_intra )
2006-10-11 23:17:58 +00:00
&& FFABS ( top_mv [ 0 ] - bottom_mv [ 0 ]) + FFABS ( top_mv [ 1 ] + bottom_mv [ 1 ]) < 2 ) continue ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
for ( x = 0 ; x < 8 ; x ++ ){
int a , b , c , d ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
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 ];
2005-12-17 18:14:38 +00:00
2006-10-11 23:17:58 +00:00
d = FFABS ( b ) - (( FFABS ( a ) + FFABS ( c ) + 1 ) >> 1 );
2002-11-10 11:46:59 +00:00
d = FFMAX ( d , 0 );
2002-10-13 13:16:04 +00:00
if ( b < 0 ) d = - d ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( d == 0 ) continue ;
if ( ! ( top_damage && bottom_damage ))
d = d * 16 / 9 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
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 ){
2003-04-10 13:18:38 +00:00
uint8_t fixed [ s -> mb_stride * s -> mb_height ];
2002-10-13 13:16:04 +00:00
#define MV_FROZEN 3
#define MV_CHANGED 2
#define MV_UNCHANGED 1
2003-04-10 13:18:38 +00:00
const int mb_stride = s -> mb_stride ;
2002-10-13 13:16:04 +00:00
const int mb_width = s -> mb_width ;
const int mb_height = s -> mb_height ;
int i , depth , num_avail ;
2010-03-12 16:59:21 +00:00
int mb_x , mb_y , mot_step , mot_stride ;
set_mv_strides ( s , & mot_step , & mot_stride );
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
num_avail = 0 ;
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
2002-10-13 13:16:04 +00:00
int f = 0 ;
2003-04-10 13:18:38 +00:00
int error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
2011-07-06 20:08:30 +02:00
if ( IS_INTRA ( s -> current_picture . f . mb_type [ mb_xy ])) f = MV_FROZEN ; //intra //FIXME check
2002-10-13 13:16:04 +00:00
if ( ! ( error & MV_ERROR )) f = MV_FROZEN ; //inter with undamaged MV
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
fixed [ mb_xy ] = f ;
2002-10-13 13:16:04 +00:00
if ( f == MV_FROZEN )
num_avail ++ ;
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
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 ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2005-12-17 18:14:38 +00:00
2011-07-06 20:08:30 +02:00
if ( IS_INTRA ( s -> current_picture . f . mb_type [ mb_xy ])) continue ;
2003-04-10 13:18:38 +00:00
if ( ! ( s -> error_status_table [ mb_xy ] & MV_ERROR )) continue ;
2002-10-13 13:16:04 +00:00
2011-07-06 20:08:30 +02:00
s -> mv_dir = s -> last_picture . f . data [ 0 ] ? MV_DIR_FORWARD : MV_DIR_BACKWARD ;
2002-10-13 13:16:04 +00:00
s -> mb_intra = 0 ;
s -> mv_type = MV_TYPE_16X16 ;
2005-04-24 17:21:11 +00:00
s -> mb_skipped = 0 ;
2002-10-13 13:16:04 +00:00
2005-12-22 01:10:11 +00:00
s -> dsp . clear_blocks ( s -> block [ 0 ]);
2002-10-13 13:16:04 +00:00
s -> mb_x = mb_x ;
s -> mb_y = mb_y ;
s -> mv [ 0 ][ 0 ][ 0 ] = 0 ;
s -> mv [ 0 ][ 0 ][ 1 ] = 0 ;
2010-03-20 00:52:08 +00:00
decode_mb ( s , 0 );
2002-10-13 13:16:04 +00:00
}
}
return ;
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
for ( depth = 0 ;; depth ++ ){
int changed , pass , none_left ;
none_left = 1 ;
changed = 1 ;
for ( pass = 0 ; ( changed || pass < 2 ) && pass < 10 ; pass ++ ){
2003-04-10 13:18:38 +00:00
int mb_x , mb_y ;
2002-10-13 13:16:04 +00:00
int score_sum = 0 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
changed = 0 ;
for ( mb_y = 0 ; mb_y < s -> mb_height ; mb_y ++ ){
for ( mb_x = 0 ; mb_x < s -> mb_width ; mb_x ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
int mv_predictor [ 8 ][ 2 ] = {{ 0 }};
2010-03-20 00:52:08 +00:00
int ref [ 8 ] = { 0 };
2002-10-13 13:16:04 +00:00
int pred_count = 0 ;
int j ;
int best_score = 256 * 256 * 256 * 64 ;
int best_pred = 0 ;
2010-03-12 16:59:21 +00:00
const int mot_index = ( mb_x + mb_y * mot_stride ) * mot_step ;
2011-06-02 10:15:58 -07:00
int prev_x , prev_y , prev_ref ;
2002-10-13 13:16:04 +00:00
if (( mb_x ^ mb_y ^ pass ) & 1 ) continue ;
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
if ( fixed [ mb_xy ] == MV_FROZEN ) continue ;
2011-07-06 20:08:30 +02:00
assert ( ! IS_INTRA ( s -> current_picture . f . mb_type [ mb_xy ]));
assert ( s -> last_picture_ptr && s -> last_picture_ptr -> f . data [ 0 ]);
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
j = 0 ;
2003-04-10 13:18:38 +00:00
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 ;
2002-10-13 13:16:04 +00:00
if ( j == 0 ) continue ;
j = 0 ;
2003-04-10 13:18:38 +00:00
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 ;
2002-10-13 13:16:04 +00:00
if ( j == 0 && pass > 1 ) continue ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
none_left = 0 ;
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
if ( mb_x > 0 && fixed [ mb_xy - 1 ]){
2011-07-06 20:08:30 +02:00
mv_predictor [ pred_count ][ 0 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index - mot_step ][ 0 ];
mv_predictor [ pred_count ][ 1 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index - mot_step ][ 1 ];
ref [ pred_count ] = s -> current_picture . f . ref_index [ 0 ][ 4 * ( mb_xy - 1 )];
2002-10-13 13:16:04 +00:00
pred_count ++ ;
}
2003-04-10 13:18:38 +00:00
if ( mb_x + 1 < mb_width && fixed [ mb_xy + 1 ]){
2011-07-06 20:08:30 +02:00
mv_predictor [ pred_count ][ 0 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index + mot_step ][ 0 ];
mv_predictor [ pred_count ][ 1 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index + mot_step ][ 1 ];
ref [ pred_count ] = s -> current_picture . f . ref_index [ 0 ][ 4 * ( mb_xy + 1 )];
2002-10-13 13:16:04 +00:00
pred_count ++ ;
}
2003-04-10 13:18:38 +00:00
if ( mb_y > 0 && fixed [ mb_xy - mb_stride ]){
2011-07-06 20:08:30 +02:00
mv_predictor [ pred_count ][ 0 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index - mot_stride * mot_step ][ 0 ];
mv_predictor [ pred_count ][ 1 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index - mot_stride * mot_step ][ 1 ];
ref [ pred_count ] = s -> current_picture . f . ref_index [ 0 ][ 4 * ( mb_xy - s -> mb_stride )];
2002-10-13 13:16:04 +00:00
pred_count ++ ;
}
2003-04-10 13:18:38 +00:00
if ( mb_y + 1 < mb_height && fixed [ mb_xy + mb_stride ]){
2011-07-06 20:08:30 +02:00
mv_predictor [ pred_count ][ 0 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index + mot_stride * mot_step ][ 0 ];
mv_predictor [ pred_count ][ 1 ] = s -> current_picture . f . motion_val [ 0 ][ mot_index + mot_stride * mot_step ][ 1 ];
ref [ pred_count ] = s -> current_picture . f . ref_index [ 0 ][ 4 * ( mb_xy + s -> mb_stride )];
2002-10-13 13:16:04 +00:00
pred_count ++ ;
}
if ( pred_count == 0 ) continue ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( pred_count > 1 ){
2010-03-20 00:52:08 +00:00
int sum_x = 0 , sum_y = 0 , sum_r = 0 ;
int max_x , max_y , min_x , min_y , max_r , min_r ;
2002-10-13 13:16:04 +00:00
for ( j = 0 ; j < pred_count ; j ++ ){
sum_x += mv_predictor [ j ][ 0 ];
sum_y += mv_predictor [ j ][ 1 ];
2010-03-20 00:52:08 +00:00
sum_r += ref [ j ];
2010-03-23 02:17:04 +00:00
if ( j && ref [ j ] != ref [ j - 1 ])
2010-03-20 00:52:08 +00:00
goto skip_mean_and_median ;
2002-10-13 13:16:04 +00:00
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* mean */
mv_predictor [ pred_count ][ 0 ] = sum_x / j ;
mv_predictor [ pred_count ][ 1 ] = sum_y / j ;
2010-03-20 00:52:08 +00:00
ref [ pred_count ] = sum_r / j ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* median */
if ( pred_count >= 3 ){
2010-03-20 00:52:08 +00:00
min_y = min_x = min_r = 99999 ;
max_y = max_x = max_r =- 99999 ;
2002-10-13 13:16:04 +00:00
} else {
2010-03-20 00:52:08 +00:00
min_x = min_y = max_x = max_y = min_r = max_r = 0 ;
2002-10-13 13:16:04 +00:00
}
for ( j = 0 ; j < pred_count ; j ++ ){
2002-11-10 11:46:59 +00:00
max_x = FFMAX ( max_x , mv_predictor [ j ][ 0 ]);
max_y = FFMAX ( max_y , mv_predictor [ j ][ 1 ]);
2010-03-20 00:52:08 +00:00
max_r = FFMAX ( max_r , ref [ j ]);
2002-11-10 11:46:59 +00:00
min_x = FFMIN ( min_x , mv_predictor [ j ][ 0 ]);
min_y = FFMIN ( min_y , mv_predictor [ j ][ 1 ]);
2010-03-20 00:52:08 +00:00
min_r = FFMIN ( min_r , ref [ j ]);
2002-10-13 13:16:04 +00:00
}
mv_predictor [ pred_count + 1 ][ 0 ] = sum_x - max_x - min_x ;
mv_predictor [ pred_count + 1 ][ 1 ] = sum_y - max_y - min_y ;
2010-03-20 00:52:08 +00:00
ref [ pred_count + 1 ] = sum_r - max_r - min_r ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( pred_count == 4 ){
mv_predictor [ pred_count + 1 ][ 0 ] /= 2 ;
mv_predictor [ pred_count + 1 ][ 1 ] /= 2 ;
2010-03-20 00:52:08 +00:00
ref [ pred_count + 1 ] /= 2 ;
2002-10-13 13:16:04 +00:00
}
pred_count += 2 ;
}
2010-03-20 00:52:08 +00:00
skip_mean_and_median :
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* zero MV */
pred_count ++ ;
2011-06-02 10:15:58 -07:00
if ( ! fixed [ mb_xy ]) {
if ( s -> avctx -> codec_id == CODEC_ID_H264 ) {
// FIXME
} else {
ff_thread_await_progress (( AVFrame * ) s -> last_picture_ptr ,
mb_y , 0 );
}
2011-07-06 20:08:30 +02:00
if ( ! s -> last_picture . f . motion_val [ 0 ] ||
! s -> last_picture . f . ref_index [ 0 ])
2011-06-20 15:07:56 +00:00
goto skip_last_mv ;
2011-07-06 20:08:30 +02:00
prev_x = s -> last_picture . f . motion_val [ 0 ][ mot_index ][ 0 ];
prev_y = s -> last_picture . f . motion_val [ 0 ][ mot_index ][ 1 ];
prev_ref = s -> last_picture . f . ref_index [ 0 ][ 4 * mb_xy ];
2011-06-02 10:15:58 -07:00
} else {
2011-07-06 20:08:30 +02:00
prev_x = s -> current_picture . f . motion_val [ 0 ][ mot_index ][ 0 ];
prev_y = s -> current_picture . f . motion_val [ 0 ][ mot_index ][ 1 ];
prev_ref = s -> current_picture . f . ref_index [ 0 ][ 4 * mb_xy ];
2011-06-02 10:15:58 -07:00
}
2002-10-13 13:16:04 +00:00
/* last MV */
2011-06-02 10:15:58 -07:00
mv_predictor [ pred_count ][ 0 ] = prev_x ;
mv_predictor [ pred_count ][ 1 ] = prev_y ;
ref [ pred_count ] = prev_ref ;
2011-06-20 15:07:55 +00:00
pred_count ++ ;
2011-06-20 15:07:56 +00:00
skip_last_mv :
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
s -> mv_dir = MV_DIR_FORWARD ;
s -> mb_intra = 0 ;
s -> mv_type = MV_TYPE_16X16 ;
2005-04-24 17:21:11 +00:00
s -> mb_skipped = 0 ;
2002-10-13 13:16:04 +00:00
2005-12-22 01:10:11 +00:00
s -> dsp . clear_blocks ( s -> block [ 0 ]);
2002-10-13 13:16:04 +00:00
s -> mb_x = mb_x ;
s -> mb_y = mb_y ;
2003-04-10 13:18:38 +00:00
2002-10-13 13:16:04 +00:00
for ( j = 0 ; j < pred_count ; j ++ ){
int score = 0 ;
2011-07-06 20:08:30 +02:00
uint8_t * src = s -> current_picture . f . data [ 0 ] + mb_x * 16 + mb_y * 16 * s -> linesize ;
2002-10-13 13:16:04 +00:00
2011-07-06 20:08:30 +02:00
s -> current_picture . f . motion_val [ 0 ][ mot_index ][ 0 ] = s -> mv [ 0 ][ 0 ][ 0 ] = mv_predictor [ j ][ 0 ];
s -> current_picture . f . motion_val [ 0 ][ mot_index ][ 1 ] = s -> mv [ 0 ][ 0 ][ 1 ] = mv_predictor [ j ][ 1 ];
2003-04-10 13:18:38 +00:00
2010-03-23 02:17:04 +00:00
if ( ref [ j ] < 0 ) //predictor intra or otherwise not available
2010-03-20 00:52:08 +00:00
continue ;
decode_mb ( s , ref [ j ]);
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
if ( mb_x > 0 && fixed [ mb_xy - 1 ]){
2002-10-13 13:16:04 +00:00
int k ;
for ( k = 0 ; k < 16 ; k ++ )
2006-10-11 23:17:58 +00:00
score += FFABS ( src [ k * s -> linesize - 1 ] - src [ k * s -> linesize ]);
2002-10-13 13:16:04 +00:00
}
2003-04-10 13:18:38 +00:00
if ( mb_x + 1 < mb_width && fixed [ mb_xy + 1 ]){
2002-10-13 13:16:04 +00:00
int k ;
for ( k = 0 ; k < 16 ; k ++ )
2006-10-11 23:17:58 +00:00
score += FFABS ( src [ k * s -> linesize + 15 ] - src [ k * s -> linesize + 16 ]);
2002-10-13 13:16:04 +00:00
}
2003-04-10 13:18:38 +00:00
if ( mb_y > 0 && fixed [ mb_xy - mb_stride ]){
2002-10-13 13:16:04 +00:00
int k ;
for ( k = 0 ; k < 16 ; k ++ )
2006-10-11 23:17:58 +00:00
score += FFABS ( src [ k - s -> linesize ] - src [ k ]);
2002-10-13 13:16:04 +00:00
}
2003-04-10 13:18:38 +00:00
if ( mb_y + 1 < mb_height && fixed [ mb_xy + mb_stride ]){
2002-10-13 13:16:04 +00:00
int k ;
for ( k = 0 ; k < 16 ; k ++ )
2006-10-11 23:17:58 +00:00
score += FFABS ( src [ k + s -> linesize * 15 ] - src [ k + s -> linesize * 16 ]);
2002-10-13 13:16:04 +00:00
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( score <= best_score ){ // <= will favor the last MV
best_score = score ;
best_pred = j ;
}
}
score_sum += best_score ;
2010-03-14 01:52:31 +00:00
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 ++ ){
2011-07-06 20:08:30 +02:00
s -> current_picture . f . motion_val [ 0 ][ mot_index + i + j * mot_stride ][ 0 ] = s -> mv [ 0 ][ 0 ][ 0 ];
s -> current_picture . f . motion_val [ 0 ][ mot_index + i + j * mot_stride ][ 1 ] = s -> mv [ 0 ][ 0 ][ 1 ];
2010-03-14 01:52:31 +00:00
}
2002-10-13 13:16:04 +00:00
2010-03-20 00:52:08 +00:00
decode_mb ( s , ref [ best_pred ]);
2002-10-13 13:16:04 +00:00
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( s -> mv [ 0 ][ 0 ][ 0 ] != prev_x || s -> mv [ 0 ][ 0 ][ 1 ] != prev_y ){
2003-04-10 13:18:38 +00:00
fixed [ mb_xy ] = MV_CHANGED ;
2002-10-13 13:16:04 +00:00
changed ++ ;
} else
2003-04-10 13:18:38 +00:00
fixed [ mb_xy ] = MV_UNCHANGED ;
2002-10-13 13:16:04 +00:00
}
}
// printf(".%d/%d", changed, score_sum); fflush(stdout);
}
2005-12-17 18:14:38 +00:00
if ( none_left )
2002-10-13 13:16:04 +00:00
return ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
int mb_xy = s -> mb_index2xy [ i ];
if ( fixed [ mb_xy ])
fixed [ mb_xy ] = MV_FROZEN ;
2002-10-13 13:16:04 +00:00
}
// printf(":"); fflush(stdout);
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
static int is_intra_more_likely ( MpegEncContext * s ){
int is_intra_likely , i , j , undamaged_count , skip_amount , mb_x , mb_y ;
2005-12-17 18:14:38 +00:00
2011-07-06 20:08:30 +02:00
if ( ! s -> last_picture_ptr || ! s -> last_picture_ptr -> f . data [ 0 ]) return 1 ; //no previous frame available -> use spatial prediction
2002-10-13 13:16:04 +00:00
undamaged_count = 0 ;
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
const int error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
if ( ! (( error & DC_ERROR ) && ( error & MV_ERROR )))
undamaged_count ++ ;
}
2005-12-17 18:14:38 +00:00
2010-03-30 20:46:46 +00:00
if ( s -> codec_id == CODEC_ID_H264 ){
H264Context * h = ( void * ) s ;
2011-10-02 00:48:12 +00:00
if ( h -> list_count <= 0 || h -> ref_count [ 0 ] <= 0 || ! h -> ref_list [ 0 ][ 0 ]. f . data [ 0 ])
2010-03-30 20:46:46 +00:00
return 1 ;
}
2008-03-22 16:46:36 +00:00
if ( undamaged_count < 5 ) return 0 ; //almost all MBs damaged -> use temporal prediction
2005-12-17 18:14:38 +00:00
2007-09-28 20:38:32 +00:00
//prevent dsp.sad() check, that requires access to the image
2011-04-29 18:53:57 +02:00
if ( CONFIG_MPEG_XVMC_DECODER && s -> avctx -> xvmc_acceleration && s -> pict_type == AV_PICTURE_TYPE_I )
2009-02-16 11:49:08 +00:00
return 1 ;
2007-09-28 20:38:32 +00:00
2005-12-17 18:14:38 +00:00
skip_amount = FFMAX ( undamaged_count / 50 , 1 ); //check only upto 50 MBs
2002-10-13 13:16:04 +00:00
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 ;
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
if (( error & DC_ERROR ) && ( error & MV_ERROR ))
continue ; //skip damaged
2005-12-17 18:14:38 +00:00
j ++ ;
2002-10-13 13:16:04 +00:00
if (( j % skip_amount ) != 0 ) continue ; //skip a few to speed things up
2005-12-17 18:14:38 +00:00
2011-04-29 18:53:57 +02:00
if ( s -> pict_type == AV_PICTURE_TYPE_I ){
2011-07-06 20:08:30 +02:00
uint8_t * mb_ptr = s -> current_picture . f . data [ 0 ] + mb_x * 16 + mb_y * 16 * s -> linesize ;
uint8_t * last_mb_ptr = s -> last_picture . f . data [ 0 ] + mb_x * 16 + mb_y * 16 * s -> linesize ;
2005-12-17 18:14:38 +00:00
2011-06-02 10:15:58 -07:00
if ( s -> avctx -> codec_id == CODEC_ID_H264 ) {
// FIXME
} else {
ff_thread_await_progress (( AVFrame * ) s -> last_picture_ptr ,
mb_y , 0 );
}
2005-12-22 01:10:11 +00:00
is_intra_likely += s -> dsp . sad [ 0 ]( NULL , last_mb_ptr , mb_ptr , s -> linesize , 16 );
2003-12-30 16:07:57 +00:00
is_intra_likely -= s -> dsp . sad [ 0 ]( NULL , last_mb_ptr , last_mb_ptr + s -> linesize * 16 , s -> linesize , 16 );
2002-10-13 13:16:04 +00:00
} else {
2011-07-06 20:08:30 +02:00
if ( IS_INTRA ( s -> current_picture . f . mb_type [ mb_xy ]))
2002-10-13 13:16:04 +00:00
is_intra_likely ++ ;
else
is_intra_likely -- ;
}
}
}
//printf("is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
2005-12-17 18:14:38 +00:00
return is_intra_likely > 0 ;
2002-10-13 13:16:04 +00:00
}
2003-03-20 01:00:57 +00:00
void ff_er_frame_start ( MpegEncContext * s ){
2008-09-08 18:18:49 +00:00
if ( ! s -> error_recognition ) return ;
2003-03-20 01:00:57 +00:00
2003-04-10 13:18:38 +00:00
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 ;
2011-06-02 10:15:58 -07:00
s -> error_occurred = 0 ;
2003-03-20 01:00:57 +00:00
}
/**
* 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
2008-03-22 01:06:57 +00:00
* error of the same type occurred
2003-03-20 01:00:57 +00:00
*/
void ff_er_add_slice ( MpegEncContext * s , int startx , int starty , int endx , int endy , int status ){
2007-02-25 10:27:12 +00:00
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 );
2003-04-10 13:18:38 +00:00
const int start_xy = s -> mb_index2xy [ start_i ];
const int end_xy = s -> mb_index2xy [ end_i ];
2003-03-20 01:00:57 +00:00
int mask = - 1 ;
2007-02-09 02:25:23 +00:00
2009-02-27 08:16:22 +00:00
if ( s -> avctx -> hwaccel )
return ;
2007-02-09 02:25:23 +00:00
if ( start_i > end_i || start_xy > end_xy ){
av_log ( s -> avctx , AV_LOG_ERROR , "internal error, slice end before start \n " );
return ;
}
2005-12-17 18:14:38 +00:00
2008-09-08 18:18:49 +00:00
if ( ! s -> error_recognition ) return ;
2003-03-20 01:00:57 +00:00
mask &= ~ VP_START ;
2003-04-10 13:18:38 +00:00
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 ;
}
2011-06-02 10:15:58 -07:00
if ( status & ( AC_ERROR | DC_ERROR | MV_ERROR )) {
s -> error_occurred = 1 ;
s -> error_count = INT_MAX ;
}
2003-03-20 01:00:57 +00:00
if ( mask == ~ 0x7F ){
2003-04-10 13:18:38 +00:00
memset ( & s -> error_status_table [ start_xy ], 0 , ( end_xy - start_xy ) * sizeof ( uint8_t ));
2003-03-20 01:00:57 +00:00
} else {
int i ;
for ( i = start_xy ; i < end_xy ; i ++ ){
2003-04-10 13:18:38 +00:00
s -> error_status_table [ i ] &= mask ;
2003-03-20 01:00:57 +00:00
}
}
2003-04-10 13:18:38 +00:00
2005-12-17 18:14:38 +00:00
if ( end_i == s -> mb_num )
2003-04-10 13:18:38 +00:00
s -> error_count = INT_MAX ;
else {
2003-03-20 01:00:57 +00:00
s -> error_status_table [ end_xy ] &= mask ;
s -> error_status_table [ end_xy ] |= status ;
}
2005-12-17 18:14:38 +00:00
2003-04-10 01:39:53 +00:00
s -> error_status_table [ start_xy ] |= VP_START ;
2003-04-10 13:18:38 +00:00
2004-06-26 02:20:38 +00:00
if ( start_xy > 0 && s -> avctx -> thread_count <= 1 && s -> avctx -> skip_top * s -> mb_width < start_i ){
2003-04-10 13:18:38 +00:00
int prev_status = s -> error_status_table [ s -> mb_index2xy [ start_i - 1 ] ];
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
prev_status &= ~ VP_START ;
if ( prev_status != ( MV_END | DC_END | AC_END )) s -> error_count = INT_MAX ;
}
2003-03-20 01:00:57 +00:00
}
void ff_er_frame_end ( MpegEncContext * s ){
2005-01-21 23:47:03 +00:00
int i , mb_x , mb_y , error , error_type , dc_error , mv_error , ac_error ;
2002-10-13 13:16:04 +00:00
int distance ;
int threshold_part [ 4 ] = { 100 , 100 , 100 };
int threshold = 50 ;
int is_intra_likely ;
2004-11-19 13:08:25 +00:00
int size = s -> b8_stride * 2 * s -> mb_height ;
Picture * pic = s -> current_picture_ptr ;
2005-12-17 18:14:38 +00:00
2008-09-30 00:28:13 +00:00
if ( ! s -> error_recognition || s -> error_count == 0 || s -> avctx -> lowres ||
2009-02-23 13:44:51 +00:00
s -> avctx -> hwaccel ||
2009-01-09 22:22:40 +00:00
s -> avctx -> codec -> capabilities & CODEC_CAP_HWACCEL_VDPAU ||
2009-11-30 19:15:19 +00:00
s -> picture_structure != PICT_FRAME || // we dont support ER of field pictures yet, though it should not crash if enabled
2004-06-26 02:20:38 +00:00
s -> error_count == 3 * s -> mb_width * ( s -> avctx -> skip_top + s -> avctx -> skip_bottom )) return ;
2003-03-20 01:00:57 +00:00
2011-07-06 20:08:30 +02:00
if ( s -> current_picture . f . motion_val [ 0 ] == NULL ) {
2003-11-03 13:26:22 +00:00
av_log ( s -> avctx , AV_LOG_ERROR , "Warning MVs not available \n " );
2005-12-17 18:14:38 +00:00
2004-01-08 18:24:35 +00:00
for ( i = 0 ; i < 2 ; i ++ ){
2011-07-06 20:08:30 +02:00
pic -> f . ref_index [ i ] = av_mallocz ( s -> mb_stride * s -> mb_height * 4 * sizeof ( uint8_t ));
2005-03-19 13:10:09 +00:00
pic -> motion_val_base [ i ] = av_mallocz (( size + 4 ) * 2 * sizeof ( uint16_t ));
2011-07-06 20:08:30 +02:00
pic -> f . motion_val [ i ] = pic -> motion_val_base [ i ] + 4 ;
2004-01-08 18:24:35 +00:00
}
2011-07-06 20:08:30 +02:00
pic -> f . motion_subsample_log2 = 3 ;
2004-01-08 18:24:35 +00:00
s -> current_picture = * s -> current_picture_ptr ;
2003-04-10 13:18:38 +00:00
}
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
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 ];
2005-12-17 18:14:38 +00:00
av_log ( s -> avctx , AV_LOG_DEBUG , "%2X " , status );
2003-04-10 13:18:38 +00:00
}
2003-11-03 13:26:22 +00:00
av_log ( s -> avctx , AV_LOG_DEBUG , " \n " );
2003-03-20 01:00:57 +00:00
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* 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 -- ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int error = s -> error_status_table [ mb_xy ];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( error & ( 1 << error_type ))
end_ok = 1 ;
if ( error & ( 8 << error_type ))
end_ok = 1 ;
if ( ! end_ok )
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= 1 << error_type ;
2002-10-13 13:16:04 +00:00
if ( error & VP_START )
end_ok = 0 ;
}
}
2011-04-26 13:52:12 +02:00
2002-10-13 13:16:04 +00:00
/* handle slices with partitions of different length */
if ( s -> partitioned_frame ){
int end_ok = 0 ;
for ( i = s -> mb_num - 1 ; i >= 0 ; i -- ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int error = s -> error_status_table [ mb_xy ];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( error & AC_END )
end_ok = 0 ;
if (( error & MV_END ) || ( error & DC_END ) || ( error & AC_ERROR ))
end_ok = 1 ;
if ( ! end_ok )
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= AC_ERROR ;
2002-10-13 13:16:04 +00:00
if ( error & VP_START )
end_ok = 0 ;
}
}
2011-04-26 13:52:12 +02:00
2002-10-13 13:16:04 +00:00
/* handle missing slices */
2008-09-08 18:18:49 +00:00
if ( s -> error_recognition >= 4 ){
2002-10-13 13:16:04 +00:00
int end_ok = 1 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
for ( i = s -> mb_num - 2 ; i >= s -> mb_width + 100 ; i -- ){ //FIXME +100 hack
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int error1 = s -> error_status_table [ mb_xy ];
2003-05-27 12:31:03 +00:00
int error2 = s -> error_status_table [ s -> mb_index2xy [ i + 1 ]];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( error1 & VP_START )
end_ok = 1 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( error2 == ( VP_START | DC_ERROR | AC_ERROR | MV_ERROR | AC_END | DC_END | MV_END )
2005-12-17 18:14:38 +00:00
&& error1 != ( VP_START | DC_ERROR | AC_ERROR | MV_ERROR | AC_END | DC_END | MV_END )
2008-02-13 09:26:10 +00:00
&& (( error1 & AC_END ) || ( error1 & DC_END ) || ( error1 & MV_END ))){ //end & uninit
2002-10-13 13:16:04 +00:00
end_ok = 0 ;
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( ! end_ok )
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= DC_ERROR | AC_ERROR | MV_ERROR ;
2002-10-13 13:16:04 +00:00
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* backward mark errors */
distance = 9999999 ;
for ( error_type = 1 ; error_type <= 3 ; error_type ++ ){
for ( i = s -> mb_num - 1 ; i >= 0 ; i -- ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int error = s -> error_status_table [ mb_xy ];
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
if ( ! s -> mbskip_table [ mb_xy ]) //FIXME partition specific
2005-12-17 18:14:38 +00:00
distance ++ ;
2002-10-13 13:16:04 +00:00
if ( error & ( 1 << error_type ))
distance = 0 ;
if ( s -> partitioned_frame ){
if ( distance < threshold_part [ error_type - 1 ])
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= 1 << error_type ;
2002-10-13 13:16:04 +00:00
} else {
if ( distance < threshold )
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= 1 << error_type ;
2002-10-13 13:16:04 +00:00
}
if ( error & VP_START )
distance = 9999999 ;
}
}
/* forward mark errors */
error = 0 ;
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int old_error = s -> error_status_table [ mb_xy ];
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( old_error & VP_START )
error = old_error & ( DC_ERROR | AC_ERROR | MV_ERROR );
else {
error |= old_error & ( DC_ERROR | AC_ERROR | MV_ERROR );
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] |= error ;
2002-10-13 13:16:04 +00:00
}
}
2011-04-26 13:52:12 +02:00
2002-10-13 13:16:04 +00:00
/* handle not partitioned case */
if ( ! s -> partitioned_frame ){
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
if ( error & ( AC_ERROR | DC_ERROR | MV_ERROR ))
error |= AC_ERROR | DC_ERROR | MV_ERROR ;
2003-04-10 13:18:38 +00:00
s -> error_status_table [ mb_xy ] = error ;
2002-10-13 13:16:04 +00:00
}
}
2005-01-21 23:47:03 +00:00
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 );
2002-10-13 13:16:04 +00:00
is_intra_likely = is_intra_more_likely ( s );
/* set unknown mb-type to most likely */
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
error = s -> error_status_table [ mb_xy ];
if ( ! (( error & DC_ERROR ) && ( error & MV_ERROR )))
continue ;
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
if ( is_intra_likely )
2011-07-06 20:08:30 +02:00
s -> current_picture . f . mb_type [ mb_xy ] = MB_TYPE_INTRA4x4 ;
2002-10-13 13:16:04 +00:00
else
2011-07-06 20:08:30 +02:00
s -> current_picture . f . mb_type [ mb_xy ] = MB_TYPE_16x16 | MB_TYPE_L0 ;
2002-10-13 13:16:04 +00:00
}
2005-12-17 18:14:38 +00:00
2009-04-10 07:17:30 +00:00
// change inter to intra blocks if no reference frames are available
2011-07-06 20:08:30 +02:00
if ( ! s -> last_picture . f . data [ 0 ] && ! s -> next_picture . f . data [ 0 ])
2009-04-10 07:17:30 +00:00
for ( i = 0 ; i < s -> mb_num ; i ++ ){
const int mb_xy = s -> mb_index2xy [ i ];
2011-07-06 20:08:30 +02:00
if ( ! IS_INTRA ( s -> current_picture . f . mb_type [ mb_xy ]))
s -> current_picture . f . mb_type [ mb_xy ] = MB_TYPE_INTRA4x4 ;
2009-04-10 07:17:30 +00:00
}
2002-10-13 13:16:04 +00:00
/* 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 ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2011-07-06 20:08:30 +02:00
const int mb_type = s -> current_picture . f . mb_type [ mb_xy ];
int dir = ! s -> last_picture . f . data [ 0 ];
2003-04-10 13:18:38 +00:00
error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
if ( IS_INTRA ( mb_type )) continue ; //intra
2002-10-13 13:16:04 +00:00
if ( error & MV_ERROR ) continue ; //inter with damaged MV
if ( ! ( error & AC_ERROR )) continue ; //undamaged inter
2005-12-17 18:14:38 +00:00
2009-04-10 07:17:30 +00:00
s -> mv_dir = dir ? MV_DIR_BACKWARD : MV_DIR_FORWARD ;
2002-10-13 13:16:04 +00:00
s -> mb_intra = 0 ;
2005-04-24 17:21:11 +00:00
s -> mb_skipped = 0 ;
2003-04-10 13:18:38 +00:00
if ( IS_8X8 ( mb_type )){
2004-04-16 01:01:45 +00:00
int mb_index = mb_x * 2 + mb_y * 2 * s -> b8_stride ;
2002-10-13 13:16:04 +00:00
int j ;
s -> mv_type = MV_TYPE_8X8 ;
for ( j = 0 ; j < 4 ; j ++ ){
2011-07-06 20:08:30 +02:00
s -> mv [ 0 ][ j ][ 0 ] = s -> current_picture . f . motion_val [ dir ][ mb_index + ( j & 1 ) + ( j >> 1 ) * s -> b8_stride ][ 0 ];
s -> mv [ 0 ][ j ][ 1 ] = s -> current_picture . f . motion_val [ dir ][ mb_index + ( j & 1 ) + ( j >> 1 ) * s -> b8_stride ][ 1 ];
2002-10-13 13:16:04 +00:00
}
} else {
s -> mv_type = MV_TYPE_16X16 ;
2011-07-06 20:08:30 +02:00
s -> mv [ 0 ][ 0 ][ 0 ] = s -> current_picture . f . motion_val [ dir ][ mb_x * 2 + mb_y * 2 * s -> b8_stride ][ 0 ];
s -> mv [ 0 ][ 0 ][ 1 ] = s -> current_picture . f . motion_val [ dir ][ mb_x * 2 + mb_y * 2 * s -> b8_stride ][ 1 ];
2002-10-13 13:16:04 +00:00
}
2005-12-17 18:14:38 +00:00
2005-12-22 01:10:11 +00:00
s -> dsp . clear_blocks ( s -> block [ 0 ]);
2002-10-13 13:16:04 +00:00
s -> mb_x = mb_x ;
s -> mb_y = mb_y ;
2010-03-20 00:52:08 +00:00
decode_mb ( s , 0 /*FIXME h264 partitioned slices need this set*/ );
2002-10-13 13:16:04 +00:00
}
}
/* guess MVs */
2011-04-29 18:53:57 +02:00
if ( s -> pict_type == AV_PICTURE_TYPE_B ){
2002-10-13 13:16:04 +00:00
for ( mb_y = 0 ; mb_y < s -> mb_height ; mb_y ++ ){
for ( mb_x = 0 ; mb_x < s -> mb_width ; mb_x ++ ){
2004-04-16 01:01:45 +00:00
int xy = mb_x * 2 + mb_y * 2 * s -> b8_stride ;
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2011-07-06 20:08:30 +02:00
const int mb_type = s -> current_picture . f . mb_type [ mb_xy ];
2003-04-10 13:18:38 +00:00
error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
if ( IS_INTRA ( mb_type )) continue ;
2002-10-13 13:16:04 +00:00
if ( ! ( error & MV_ERROR )) continue ; //inter with undamaged MV
if ( ! ( error & AC_ERROR )) continue ; //undamaged inter
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
s -> mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD ;
2011-07-06 20:08:30 +02:00
if ( ! s -> last_picture . f . data [ 0 ]) s -> mv_dir &= ~ MV_DIR_FORWARD ;
if ( ! s -> next_picture . f . data [ 0 ]) s -> mv_dir &= ~ MV_DIR_BACKWARD ;
2002-10-13 13:16:04 +00:00
s -> mb_intra = 0 ;
s -> mv_type = MV_TYPE_16X16 ;
2005-04-24 17:21:11 +00:00
s -> mb_skipped = 0 ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( s -> pp_time ){
int time_pp = s -> pp_time ;
int time_pb = s -> pb_time ;
2005-12-17 18:14:38 +00:00
2011-06-02 10:15:58 -07:00
if ( s -> avctx -> codec_id == CODEC_ID_H264 ) {
//FIXME
} else {
ff_thread_await_progress (( AVFrame * ) s -> next_picture_ptr ,
mb_y , 0 );
}
2011-07-06 20:08:30 +02:00
s -> mv [ 0 ][ 0 ][ 0 ] = s -> next_picture . f . motion_val [ 0 ][ xy ][ 0 ] * time_pb / time_pp ;
s -> mv [ 0 ][ 0 ][ 1 ] = s -> next_picture . f . motion_val [ 0 ][ xy ][ 1 ] * time_pb / time_pp ;
s -> mv [ 1 ][ 0 ][ 0 ] = s -> next_picture . f . motion_val [ 0 ][ xy ][ 0 ] * ( time_pb - time_pp ) / time_pp ;
s -> mv [ 1 ][ 0 ][ 1 ] = s -> next_picture . f . motion_val [ 0 ][ xy ][ 1 ] * ( time_pb - time_pp ) / time_pp ;
2002-10-13 13:16:04 +00:00
} 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 ;
}
2002-11-11 09:40:17 +00:00
s -> dsp . clear_blocks ( s -> block [ 0 ]);
2002-10-13 13:16:04 +00:00
s -> mb_x = mb_x ;
s -> mb_y = mb_y ;
2010-03-20 00:52:08 +00:00
decode_mb ( s , 0 );
2002-10-13 13:16:04 +00:00
}
}
} else
guess_mv ( s );
2003-07-26 01:28:49 +00:00
/* the filters below are not XvMC compatible, skip them */
2009-02-16 11:49:08 +00:00
if ( CONFIG_MPEG_XVMC_DECODER && s -> avctx -> xvmc_acceleration )
goto ec_clean ;
2002-10-13 13:16:04 +00:00
/* 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 ;
2006-09-27 22:13:44 +00:00
int16_t * dc_ptr ;
2003-02-11 16:35:48 +00:00
uint8_t * dest_y , * dest_cb , * dest_cr ;
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2011-07-06 20:08:30 +02:00
const int mb_type = s -> current_picture . f . mb_type [ mb_xy ];
2005-12-17 18:14:38 +00:00
2003-04-10 13:18:38 +00:00
error = s -> error_status_table [ mb_xy ];
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
if ( IS_INTRA ( mb_type ) && s -> partitioned_frame ) continue ;
2002-10-13 13:16:04 +00:00
// if(error&MV_ERROR) continue; //inter data damaged FIXME is this good?
2005-12-17 18:14:38 +00:00
2011-07-06 20:08:30 +02:00
dest_y = s -> current_picture . f . data [ 0 ] + mb_x * 16 + mb_y * 16 * s -> linesize ;
dest_cb = s -> current_picture . f . data [ 1 ] + mb_x * 8 + mb_y * 8 * s -> uvlinesize ;
dest_cr = s -> current_picture . f . data [ 2 ] + mb_x * 8 + mb_y * 8 * s -> uvlinesize ;
2005-12-17 18:14:38 +00:00
2004-04-16 01:01:45 +00:00
dc_ptr = & s -> dc_val [ 0 ][ mb_x * 2 + mb_y * 2 * s -> b8_stride ];
2002-10-13 13:16:04 +00:00
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 ];
}
}
2004-04-16 01:01:45 +00:00
dc_ptr [( n & 1 ) + ( n >> 1 ) * s -> b8_stride ] = ( dc + 4 ) >> 3 ;
2002-10-13 13:16:04 +00:00
}
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 )];
}
}
2004-04-16 01:01:45 +00:00
s -> dc_val [ 1 ][ mb_x + mb_y * s -> mb_stride ] = ( dcu + 4 ) >> 3 ;
2005-12-17 18:14:38 +00:00
s -> dc_val [ 2 ][ mb_x + mb_y * s -> mb_stride ] = ( dcv + 4 ) >> 3 ;
2002-10-13 13:16:04 +00:00
}
}
2011-04-26 13:52:12 +02:00
2002-10-13 13:16:04 +00:00
/* guess DC for damaged blocks */
2004-04-16 01:01:45 +00:00
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 );
2011-04-26 13:52:12 +02:00
2002-10-13 13:16:04 +00:00
/* filter luma DC */
2004-04-16 01:01:45 +00:00
filter181 ( s -> dc_val [ 0 ], s -> mb_width * 2 , s -> mb_height * 2 , s -> b8_stride );
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
/* 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 ++ ){
2003-02-11 16:35:48 +00:00
uint8_t * dest_y , * dest_cb , * dest_cr ;
2003-04-10 13:18:38 +00:00
const int mb_xy = mb_x + mb_y * s -> mb_stride ;
2011-07-06 20:08:30 +02:00
const int mb_type = s -> current_picture . f . mb_type [ mb_xy ];
2002-10-13 13:16:04 +00:00
2003-04-10 13:18:38 +00:00
error = s -> error_status_table [ mb_xy ];
if ( IS_INTER ( mb_type )) continue ;
2002-10-13 13:16:04 +00:00
if ( ! ( error & AC_ERROR )) continue ; //undamaged
2005-12-17 18:14:38 +00:00
2011-07-06 20:08:30 +02:00
dest_y = s -> current_picture . f . data [ 0 ] + mb_x * 16 + mb_y * 16 * s -> linesize ;
dest_cb = s -> current_picture . f . data [ 1 ] + mb_x * 8 + mb_y * 8 * s -> uvlinesize ;
dest_cr = s -> current_picture . f . data [ 2 ] + mb_x * 8 + mb_y * 8 * s -> uvlinesize ;
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
put_dc ( s , dest_y , dest_cb , dest_cr , mb_x , mb_y );
}
}
2005-12-17 18:14:38 +00:00
2002-10-13 13:16:04 +00:00
if ( s -> avctx -> error_concealment & FF_EC_DEBLOCK ){
/* filter horizontal block boundaries */
2011-07-06 20:08:30 +02:00
h_block_filter ( s , s -> current_picture . f . data [ 0 ], s -> mb_width * 2 , s -> mb_height * 2 , s -> linesize , 1 );
h_block_filter ( s , s -> current_picture . f . data [ 1 ], s -> mb_width , s -> mb_height , s -> uvlinesize , 0 );
h_block_filter ( s , s -> current_picture . f . data [ 2 ], s -> mb_width , s -> mb_height , s -> uvlinesize , 0 );
2002-10-13 13:16:04 +00:00
/* filter vertical block boundaries */
2011-07-06 20:08:30 +02:00
v_block_filter ( s , s -> current_picture . f . data [ 0 ], s -> mb_width * 2 , s -> mb_height * 2 , s -> linesize , 1 );
v_block_filter ( s , s -> current_picture . f . data [ 1 ], s -> mb_width , s -> mb_height , s -> uvlinesize , 0 );
v_block_filter ( s , s -> current_picture . f . data [ 2 ], s -> mb_width , s -> mb_height , s -> uvlinesize , 0 );
2002-10-13 13:16:04 +00:00
}
2003-07-26 01:28:49 +00:00
ec_clean :
2002-10-13 13:16:04 +00:00
/* clean a few tables */
for ( i = 0 ; i < s -> mb_num ; i ++ ){
2003-04-10 13:18:38 +00:00
const int mb_xy = s -> mb_index2xy [ i ];
int error = s -> error_status_table [ mb_xy ];
2005-12-17 18:14:38 +00:00
2011-04-29 18:53:57 +02:00
if ( s -> pict_type != AV_PICTURE_TYPE_B && ( error & ( DC_ERROR | MV_ERROR | AC_ERROR ))){
2003-04-10 13:18:38 +00:00
s -> mbskip_table [ mb_xy ] = 0 ;
2002-10-13 13:16:04 +00:00
}
2003-04-10 13:18:38 +00:00
s -> mbintra_table [ mb_xy ] = 1 ;
2005-12-17 18:14:38 +00:00
}
2002-10-13 13:16:04 +00:00
}