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