blob: f06324dd6dadb28394cfe700c6131cf99eb2dba9 [file] [log] [blame]
/*!
*************************************************************************************
* \file macroblock.c
*
* \brief
* Process one macroblock
*
* \author
* Main contributors (see contributors.h for copyright, address and affiliation details)
* - Inge Lille-Langoy <inge.lille-langoy@telenor.com>
* - Rickard Sjoberg <rickard.sjoberg@era.ericsson.se>
* - Jani Lainema <jani.lainema@nokia.com>
* - Sebastian Purreiter <sebastian.purreiter@mch.siemens.de>
* - Detlev Marpe <marpe@hhi.de>
* - Thomas Wedi <wedi@tnt.uni-hannover.de>
* - Ragip Kurceren <ragip.kurceren@nokia.com>
* - Alexis Michael Tourapis <alexismt@ieee.org>
*************************************************************************************
*/
#include "contributors.h"
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <memory.h>
#include "global.h"
#include "elements.h"
#include "macroblock.h"
#include "refbuf.h"
#include "fmo.h"
#include "vlc.h"
#include "image.h"
#include "mb_access.h"
#include "ratectl.h" // header file for rate control
#include "rc_quadratic.h"
#include "cabac.h"
#include "transform8x8.h"
#include "me_fullsearch.h"
#include "symbol.h"
#if TRACE
#define TRACE_SE(trace,str) snprintf(trace,TRACESTRING_SIZE,str)
#else
#define TRACE_SE(trace,str)
#endif
extern const byte QP_SCALE_CR[52] ;
//Rate control
int predict_error,dq;
extern int delta_qp_mbaff[2][2],delta_qp_mbaff[2][2];
extern int qp_mbaff[2][2],qp_mbaff[2][2];
// function pointer for different ways of obtaining chroma interpolation
static void (*OneComponentChromaPrediction4x4) (imgpel* , int , int , short****** , int , short , int , int );
static void OneComponentChromaPrediction4x4_regenerate (imgpel* , int , int , short****** , int , short , int , int );
static void OneComponentChromaPrediction4x4_retrieve (imgpel* , int , int , short****** , int , short , int , int );
static int slice_too_big(int rlc_bits);
static int writeChromaIntraPredMode (void);
static int writeMotionInfo2NAL (void);
static int writeChromaCoeff (void);
static int writeCBPandLumaCoeff (void);
extern int *mvbits;
extern int QP2QUANT[40];
extern int ver_offset[4][8][4];
extern int hor_offset[4][8][4];
static int diff [16];
static int diff64[64];
static const unsigned char subblk_offset_x[3][8][4] =
{
{ {0, 4, 0, 4},
{0, 4, 0, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 4, 0, 4},
{0, 4, 0, 4},
{0, 4, 0, 4},
{0, 4, 0, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12} }
};
static const unsigned char subblk_offset_y[3][8][4] =
{
{ {0, 0, 4, 4},
{0, 0, 4, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 0, 4, 4},
{8, 8,12,12},
{0, 0, 4, 4},
{8, 8,12,12},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0} },
{ {0, 0, 4, 4},
{0, 0, 4, 4},
{8, 8,12,12},
{8, 8,12,12},
{0, 0, 4, 4},
{0, 0, 4, 4},
{8, 8,12,12},
{8, 8,12,12} }
};
/*!
************************************************************************
* \brief
* updates the coordinates for the next macroblock to be processed
*
* \param mb_addr
* macroblock address in scan order
************************************************************************
*/
void set_MB_parameters (int mb_addr)
{
img->current_mb_nr = mb_addr;
get_mb_block_pos(mb_addr, &img->mb_x, &img->mb_y);
img->block_x = img->mb_x << 2;
img->block_y = img->mb_y << 2;
img->pix_x = img->block_x << 2;
img->pix_y = img->block_y << 2;
img->opix_x = img->pix_x;
if (img->MbaffFrameFlag)
{
if (img->mb_data[mb_addr].mb_field)
{
imgY_org = (mb_addr % 2) ? imgY_org_bot : imgY_org_top;
imgUV_org = (mb_addr % 2) ? imgUV_org_bot : imgUV_org_top;
img->opix_y = (img->mb_y >> 1 ) << 4;
img->mb_data[mb_addr].list_offset = (mb_addr % 2) ? 4 : 2;
}
else
{
imgY_org = imgY_org_frm;
imgUV_org = imgUV_org_frm;
img->opix_y = img->block_y << 2;
img->mb_data[mb_addr].list_offset = 0;
}
}
else
{
img->opix_y = img->block_y << 2;
img->mb_data[mb_addr].list_offset = 0;
}
if (img->yuv_format != YUV400)
{
img->pix_c_x = (img->mb_cr_size_x * img->pix_x) >> 4;
img->pix_c_y = (img->mb_cr_size_y * img->pix_y) >> 4;
img->opix_c_x = (img->mb_cr_size_x * img->opix_x) >> 4;
img->opix_c_y = (img->mb_cr_size_y * img->opix_y) >> 4;
}
// printf ("set_MB_parameters: mb %d, mb_x %d, mb_y %d\n", mb_addr, img->mb_x, img->mb_y);
}
/*!
************************************************************************
* \brief
* updates the coordinates and statistics parameter for the
* next macroblock
************************************************************************
*/
void proceed2nextMacroblock(void)
{
#if TRACE
int use_bitstream_backing = (input->slice_mode == FIXED_RATE || input->slice_mode == CALLBACK);
#endif
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
int* bitCount = currMB->bitcounter;
int i;
if (bitCount[BITS_TOTAL_MB] > img->max_bitCount)
printf("Warning!!! Number of bits (%d) of macroblock_layer() data seems to exceed defined limit (%d).\n", bitCount[BITS_TOTAL_MB],img->max_bitCount);
// Update the statistics
stats->bit_use_mb_type[img->type] += bitCount[BITS_MB_MODE];
stats->bit_use_coeffY[img->type] += bitCount[BITS_COEFF_Y_MB] ;
stats->tmp_bit_use_cbp[img->type] += bitCount[BITS_CBP_MB];
stats->bit_use_coeffC[img->type] += bitCount[BITS_COEFF_UV_MB];
stats->bit_use_delta_quant[img->type] += bitCount[BITS_DELTA_QUANT_MB];
if (IS_INTRA(currMB))
{
++stats->intra_chroma_mode[currMB->c_ipred_mode];
if ((currMB->cbp&15) != 0)
{
if (currMB->luma_transform_size_8x8_flag)
++stats->mode_use_transform_8x8[img->type][currMB->mb_type];
else
++stats->mode_use_transform_4x4[img->type][currMB->mb_type];
}
}
++stats->mode_use[img->type][currMB->mb_type];
stats->bit_use_mode[img->type][currMB->mb_type]+= bitCount[BITS_INTER_MB];
if (img->type != I_SLICE)
{
if (currMB->mb_type == P8x8)
{
for(i=0;i<4;i++)
{
if (currMB->b8mode[i] > 0)
++stats->mode_use[img->type][currMB->b8mode[i]];
else
++stats->b8_mode_0_use[img->type][currMB->luma_transform_size_8x8_flag];
if (currMB->b8mode[i]==4)
{
if ((currMB->luma_transform_size_8x8_flag && (currMB->cbp&15) != 0) || input->Transform8x8Mode == 2)
++stats->mode_use_transform_8x8[img->type][4];
else
++stats->mode_use_transform_4x4[img->type][4];
}
}
}
else if (currMB->mb_type >= 0 && currMB->mb_type <=3 && ((currMB->cbp&15) != 0))
{
if (currMB->luma_transform_size_8x8_flag)
++stats->mode_use_transform_8x8[img->type][currMB->mb_type];
else
++stats->mode_use_transform_4x4[img->type][currMB->mb_type];
}
}
// Statistics
if ((img->type == P_SLICE)||(img->type==SP_SLICE) )
{
++stats->quant0;
stats->quant1 += currMB->qp; // to find average quant for inter frames
}
}
/*!
************************************************************************
* \brief
* updates chroma QP according to luma QP and bit depth
************************************************************************
*/
void set_chroma_qp(Macroblock *currMB)
{
int i;
for (i=0; i<2; i++)
{
currMB->qpc[i] = iClip3 ( -img->bitdepth_chroma_qp_scale, 51, currMB->qp + img->chroma_qp_offset[i] );
currMB->qpc[i] = currMB->qpc[i] < 0 ? currMB->qpc[i] : QP_SCALE_CR[currMB->qpc[i]];
}
}
/*!
************************************************************************
* \brief
* initializes the current macroblock
*
* \param mb_addr
* macroblock address in scan order
* \param mb_field
* true for field macroblock coding
************************************************************************
*/
void start_macroblock(int mb_addr, int mb_field)
{
int i,j,l;
int use_bitstream_backing = (input->slice_mode == FIXED_RATE || input->slice_mode == CALLBACK);
Macroblock *currMB = &img->mb_data[mb_addr];
Slice *curr_slice = img->currentSlice;
DataPartition *dataPart;
Bitstream *currStream;
int prev_mb;
currMB->mb_field = mb_field;
enc_picture->mb_field[mb_addr] = mb_field;
currMB->is_field_mode = (img->field_picture || ( img->MbaffFrameFlag && currMB->mb_field));
set_MB_parameters (mb_addr);
prev_mb = FmoGetPreviousMBNr(img->current_mb_nr);
if(use_bitstream_backing)
{
if ((!input->MbInterlace)||((mb_addr&1)==0)) // KS: MB AFF -> store stream positions for
// first macroblock only
{
// Keep the current state of the bitstreams
if(!img->cod_counter)
{
for (i=0; i<curr_slice->max_part_nr; i++)
{
dataPart = &(curr_slice->partArr[i]);
currStream = dataPart->bitstream;
currStream->stored_bits_to_go = currStream->bits_to_go;
currStream->stored_byte_pos = currStream->byte_pos;
currStream->stored_byte_buf = currStream->byte_buf;
stats->stored_bit_slice = stats->bit_slice;
if (input->symbol_mode ==CABAC)
{
dataPart->ee_recode = dataPart->ee_cabac;
}
}
}
}
}
// Save the slice number of this macroblock. When the macroblock below
// is coded it will use this to decide if prediction for above is possible
currMB->slice_nr = img->current_slice_nr;
// Initialize delta qp change from last macroblock. Feature may be used for future rate control
// Rate control
currMB->qpsp = img->qpsp;
if(input->RCEnable)
{
if (prev_mb > -1)
{
if ( input->MbInterlace == ADAPTIVE_CODING && !img->bot_MB && currMB->mb_field )
{
currMB->qp = img->qp = img->mb_data[prev_mb].qp;
}
currMB->prev_qp = img->mb_data[prev_mb].qp;
if (img->mb_data[prev_mb].slice_nr == img->current_slice_nr)
{
currMB->prev_delta_qp = img->mb_data[prev_mb].delta_qp;
}
else
{
currMB->prev_delta_qp = 0;
}
}
else
{
currMB->prev_qp = curr_slice->qp;
currMB->prev_delta_qp = 0;
}
// frame layer rate control
if(input->basicunit==img->FrameSizeInMbs)
{
currMB->delta_qp = 0;
currMB->qp = img->qp;
}
// basic unit layer rate control
else
{
// each I or B frame has only one QP
if( ((img->type == I_SLICE || img->type == B_SLICE) && input->RCUpdateMode != RC_MODE_1 ) || (!IMG_NUMBER) )
{
currMB->delta_qp = 0;
currMB->qp = img->qp;
}
else if( img->type == P_SLICE || input->RCUpdateMode == RC_MODE_1 )
{
if (!img->write_macroblock) //write macroblock
{
if (prev_mb < 0) //first macroblock (of slice)
{
// Initialize delta qp change from last macroblock. Feature may be used for future rate control
currMB->delta_qp = 0;
currMB->qp = img->qp;
delta_qp_mbaff[currMB->mb_field][img->bot_MB] = currMB->delta_qp;
qp_mbaff [currMB->mb_field][img->bot_MB] = currMB->qp;
}
else
{
if (!((input->MbInterlace) && img->bot_MB)) //top macroblock
{
if (img->mb_data[prev_mb].prev_cbp == 1)
{
currMB->delta_qp = 0;
currMB->qp = img->qp;
}
else
{
currMB->qp = img->mb_data[prev_mb].prev_qp;
currMB->delta_qp = currMB->qp - img->mb_data[prev_mb].qp;
img->qp = currMB->qp;
}
delta_qp_mbaff[currMB->mb_field][img->bot_MB] = currMB->delta_qp;
qp_mbaff [currMB->mb_field][img->bot_MB] = currMB->qp;
}
else //bottom macroblock
{
// Initialize delta qp change from last macroblock. Feature may be used for future rate control
currMB->delta_qp = 0;
currMB->qp = img->qp; // needed in loop filter (even if constant QP is used)
}
}
}
else
{
if (!img->bot_MB) //write top macroblock
{
if (img->write_mbaff_frame)
{
currMB->delta_qp = delta_qp_mbaff[0][img->bot_MB];
img->qp = currMB->qp = qp_mbaff[0][img->bot_MB];
//set_chroma_qp(currMB);
}
else
{
if (prev_mb < 0) //first macroblock (of slice)
{
// Initialize delta qp change from last macroblock. Feature may be used for future rate control
currMB->delta_qp = 0;
currMB->qp = img->qp;
delta_qp_mbaff[currMB->mb_field][img->bot_MB] = currMB->delta_qp;
qp_mbaff [currMB->mb_field][img->bot_MB] = currMB->qp;
}
else
{
currMB->delta_qp = delta_qp_mbaff[1][img->bot_MB];
img->qp = currMB->qp = qp_mbaff[1][img->bot_MB];
//set_chroma_qp(currMB);
}
}
}
else //write bottom macroblock
{
currMB->delta_qp = 0;
currMB->qp = img->qp;
set_chroma_qp(currMB);
}
}
// compute the quantization parameter for each basic unit of P frame
if (!img->write_macroblock)
{
if(!((input->MbInterlace) && img->bot_MB))
{
if((img->NumberofCodedMacroBlocks>0) && (img->NumberofCodedMacroBlocks%img->BasicUnit==0))
{
// frame coding
if(active_sps->frame_mbs_only_flag)
{
updateRCModel(quadratic_RC);
img->BasicUnitQP=updateQP(quadratic_RC, generic_RC->TopFieldFlag);
}
// picture adaptive field/frame coding
else if((input->PicInterlace!=FRAME_CODING)&&(!input->MbInterlace)&&(generic_RC->NoGranularFieldRC==0))
{
updateRCModel(quadratic_RC);
img->BasicUnitQP=updateQP(quadratic_RC, generic_RC->TopFieldFlag);
}
// mb adaptive f/f coding, field coding
else if((input->MbInterlace))
{
updateRCModel(quadratic_RC);
img->BasicUnitQP=updateQP(quadratic_RC, generic_RC->TopFieldFlag);
}
}
if(img->current_mb_nr==0)
img->BasicUnitQP=img->qp;
currMB->predict_qp = iClip3(currMB->qp - img->min_qp_delta, currMB->qp + img->max_qp_delta, img->BasicUnitQP);
dq = currMB->delta_qp + currMB->predict_qp - currMB->qp;
if(dq < -img->min_qp_delta)
{
dq = -img->min_qp_delta;
predict_error = dq-currMB->delta_qp;
img->qp = img->qp+predict_error;
currMB->delta_qp = -img->min_qp_delta;
}
else if(dq > img->max_qp_delta)
{
dq = img->max_qp_delta;
predict_error = dq - currMB->delta_qp;
img->qp = img->qp + predict_error;
currMB->delta_qp = img->max_qp_delta;
}
else
{
currMB->delta_qp = dq;
predict_error=currMB->predict_qp-currMB->qp;
img->qp = currMB->predict_qp;
}
currMB->qp = img->qp;
if (input->MbInterlace)
{
delta_qp_mbaff[currMB->mb_field][img->bot_MB] = currMB->delta_qp;
qp_mbaff [currMB->mb_field][img->bot_MB] = currMB->qp;
}
currMB->predict_error=predict_error;
}
else
currMB->prev_qp=img->qp;
}
}
}
}
else
{
Slice* currSlice = img->currentSlice;
if (prev_mb>-1)
{
currMB->prev_qp = img->mb_data[prev_mb].qp;
currMB->prev_delta_qp = (img->mb_data[prev_mb].slice_nr == img->current_slice_nr) ? img->mb_data[prev_mb].delta_qp : 0;
}
else
{
currMB->prev_qp = currSlice->qp;
currMB->prev_delta_qp = 0;
}
currMB->qp = currSlice->qp ;
currMB->delta_qp = currMB->qp - currMB->prev_qp;
delta_qp_mbaff[currMB->mb_field][img->bot_MB] = currMB->delta_qp;
qp_mbaff [currMB->mb_field][img->bot_MB] = currMB->qp;
}
img->qp_scaled = img->qp + img->bitdepth_luma_qp_scale;
set_chroma_qp (currMB);
// loop filter parameter
if (active_pps->deblocking_filter_control_present_flag)
{
currMB->LFDisableIdc = img->LFDisableIdc;
currMB->LFAlphaC0Offset = img->LFAlphaC0Offset;
currMB->LFBetaOffset = img->LFBetaOffset;
}
else
{
currMB->LFDisableIdc = 0;
currMB->LFAlphaC0Offset = 0;
currMB->LFBetaOffset = 0;
}
// If MB is next to a slice boundary, mark neighboring blocks unavailable for prediction
CheckAvailabilityOfNeighbors();
if (input->symbol_mode == CABAC)
CheckAvailabilityOfNeighborsCABAC();
// Reset vectors and reference indices
for (l=0; l<2; l++)
{
for (j=img->block_y; j < img->block_y + BLOCK_MULTIPLE; j++)
{
memset(&enc_picture->ref_idx[l][j][img->block_x], -1, BLOCK_MULTIPLE * sizeof(char));
memset(enc_picture->mv [l][j][img->block_x], 0, 2 * BLOCK_MULTIPLE * sizeof(short));
for (i=img->block_x; i < img->block_x + BLOCK_MULTIPLE; i++)
enc_picture->ref_pic_id[l][j][i]= -1;
}
}
// Reset syntax element entries in MB struct
currMB->mb_type = 0;
currMB->cbp_blk = 0;
currMB->cbp = 0;
currMB->cbp_bits = 0;
currMB->c_ipred_mode = DC_PRED_8;
memset (currMB->mvd, 0, BLOCK_CONTEXT * sizeof(int));
memset (currMB->intra_pred_modes, DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); // changing this to char would allow us to use memset
memset (currMB->intra_pred_modes8x8, DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char));
//initialize the whole MB as INTRA coded
//Blocks are set to notINTRA in write_one_macroblock
if (input->UseConstrainedIntraPred)
{
img->intra_block[img->current_mb_nr] = 1;
}
// Initialize bitcounters for this macroblock
if(prev_mb < 0) // No slice header to account for
{
currMB->bitcounter[BITS_HEADER] = 0;
}
else if (currMB->slice_nr == img->mb_data[prev_mb].slice_nr) // current MB belongs to the
// same slice as the last MB
{
currMB->bitcounter[BITS_HEADER] = 0;
}
currMB->bitcounter[BITS_MB_MODE ] = 0;
currMB->bitcounter[BITS_COEFF_Y_MB ] = 0;
currMB->bitcounter[BITS_INTER_MB ] = 0;
currMB->bitcounter[BITS_CBP_MB ] = 0;
currMB->bitcounter[BITS_DELTA_QUANT_MB] = 0;
currMB->bitcounter[BITS_COEFF_UV_MB ] = 0;
if(input->SearchMode == FAST_FULL_SEARCH)
ResetFastFullIntegerSearch ();
// disable writing of trace file
#if TRACE
curr_slice->partArr[0].bitstream->trace_enabled = FALSE;
if (input->partition_mode)
{
curr_slice->partArr[1].bitstream->trace_enabled = FALSE;
curr_slice->partArr[2].bitstream->trace_enabled = FALSE;
}
#endif
}
/*!
************************************************************************
* \brief
* terminates processing of the current macroblock depending
* on the chosen slice mode
************************************************************************
*/
void terminate_macroblock( Boolean *end_of_slice, //!< returns true for last macroblock of a slice, otherwise false
Boolean *recode_macroblock //!< returns true if max. slice size is exceeded an macroblock must be recoded in next slice
)
{
int i;
Slice *currSlice = img->currentSlice;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
SyntaxElement se;
int *partMap = assignSE2partition[input->partition_mode];
DataPartition *dataPart;
Bitstream *currStream;
int rlc_bits=0;
int use_bitstream_backing = (input->slice_mode == FIXED_RATE || input->slice_mode == CALLBACK);
int new_slice;
static int skip = FALSE;
// if previous mb in the same slice group has different slice number as the current, it's the
// the start of new slice
new_slice=0;
if ( (img->current_mb_nr==0) || (FmoGetPreviousMBNr(img->current_mb_nr)<0) )
new_slice=1;
else if( img->mb_data[FmoGetPreviousMBNr(img->current_mb_nr)].slice_nr != img->current_slice_nr )
new_slice=1;
*recode_macroblock=FALSE;
switch(input->slice_mode)
{
case NO_SLICES:
currSlice->num_mb++;
*recode_macroblock = FALSE;
if ((currSlice->num_mb) == (int)img->PicSizeInMbs) // maximum number of MBs reached
*end_of_slice = TRUE;
// if it's end of current slice group, slice ends too
*end_of_slice = (Boolean) (*end_of_slice | (img->current_mb_nr == FmoGetLastCodedMBOfSliceGroup (FmoMB2SliceGroup (img->current_mb_nr))));
break;
case FIXED_MB:
// For slice mode one, check if a new slice boundary follows
currSlice->num_mb++;
*recode_macroblock = FALSE;
//! Check end-of-slice group condition first
*end_of_slice = (Boolean) (img->current_mb_nr == FmoGetLastCodedMBOfSliceGroup (FmoMB2SliceGroup (img->current_mb_nr)));
//! Now check maximum # of MBs in slice
*end_of_slice = (Boolean) (*end_of_slice | (currSlice->num_mb >= input->slice_argument));
break;
// For slice modes two and three, check if coding of this macroblock
// resulted in too many bits for this slice. If so, indicate slice
// boundary before this macroblock and code the macroblock again
case FIXED_RATE:
// in case of skip MBs check if there is a slice boundary
// only for UVLC (img->cod_counter is always 0 in case of CABAC)
if(img->cod_counter)
{
// write out the skip MBs to know how many bits we need for the RLC
se.value1 = img->cod_counter;
se.value2 = 0;
se.type = SE_MBTYPE;
dataPart = &(currSlice->partArr[partMap[se.type]]);
TRACE_SE (se.tracestring, "mb_skip_run");
writeSE_UVLC(&se, dataPart);
rlc_bits=se.len;
currStream = dataPart->bitstream;
// save the bitstream as it would be if we write the skip MBs
currStream->bits_to_go_skip = currStream->bits_to_go;
currStream->byte_pos_skip = currStream->byte_pos;
currStream->byte_buf_skip = currStream->byte_buf;
// restore the bitstream
currStream->bits_to_go = currStream->stored_bits_to_go;
currStream->byte_pos = currStream->stored_byte_pos;
currStream->byte_buf = currStream->stored_byte_buf;
skip = TRUE;
}
//! Check if the last coded macroblock fits into the size of the slice
//! But only if this is not the first macroblock of this slice
if (!new_slice)
{
if(slice_too_big(rlc_bits))
{
*recode_macroblock = TRUE;
*end_of_slice = TRUE;
}
else if(!img->cod_counter)
skip = FALSE;
}
// maximum number of MBs
// check if current slice group is finished
if ((*recode_macroblock == FALSE) && (img->current_mb_nr == FmoGetLastCodedMBOfSliceGroup (FmoMB2SliceGroup (img->current_mb_nr))))
{
*end_of_slice = TRUE;
if(!img->cod_counter)
skip = FALSE;
}
//! (first MB OR first MB in a slice) AND bigger that maximum size of slice
if (new_slice && slice_too_big(rlc_bits))
{
*end_of_slice = TRUE;
if(!img->cod_counter)
skip = FALSE;
}
if (!*recode_macroblock)
currSlice->num_mb++;
break;
case CALLBACK:
if (img->current_mb_nr > 0 && !new_slice)
{
if (currSlice->slice_too_big(rlc_bits))
{
*recode_macroblock = TRUE;
*end_of_slice = TRUE;
}
}
if ( (*recode_macroblock == FALSE) && (img->current_mb_nr == FmoGetLastCodedMBOfSliceGroup (FmoMB2SliceGroup (img->current_mb_nr))))
*end_of_slice = TRUE;
break;
default:
snprintf(errortext, ET_SIZE, "Slice Mode %d not supported", input->slice_mode);
error(errortext, 600);
}
if (*recode_macroblock == TRUE)
{
// Restore everything
for (i=0; i<currSlice->max_part_nr; i++)
{
dataPart = &(currSlice->partArr[i]);
currStream = dataPart->bitstream;
currStream->bits_to_go = currStream->stored_bits_to_go;
currStream->byte_pos = currStream->stored_byte_pos;
currStream->byte_buf = currStream->stored_byte_buf;
stats->bit_slice = stats->stored_bit_slice;
if (input->symbol_mode == CABAC)
{
dataPart->ee_cabac = dataPart->ee_recode;
}
}
}
if (input->symbol_mode == UVLC)
{
// Skip MBs at the end of this slice
dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]);
if(*end_of_slice == TRUE && skip == TRUE)
{
// only for Slice Mode 2 or 3
// If we still have to write the skip, let's do it!
if(img->cod_counter && *recode_macroblock == TRUE) // MB that did not fit in this slice
{
// If recoding is true and we have had skip,
// we have to reduce the counter in case of recoding
img->cod_counter--;
if(img->cod_counter)
{
se.value1 = img->cod_counter;
se.value2 = 0;
se.type = SE_MBTYPE;
#if TRACE
snprintf(se.tracestring, TRACESTRING_SIZE, "Final MB runlength = %3d",img->cod_counter);
#endif
writeSE_UVLC(&se, dataPart);
rlc_bits=se.len;
currMB->bitcounter[BITS_MB_MODE]+=rlc_bits;
img->cod_counter = 0;
}
}
else //! MB that did not fit in this slice anymore is not a Skip MB
{
currStream = dataPart->bitstream;
// update the bitstream
currStream->bits_to_go = currStream->bits_to_go_skip;
currStream->byte_pos = currStream->byte_pos_skip;
currStream->byte_buf = currStream->byte_buf_skip;
// update the statistics
img->cod_counter = 0;
skip = FALSE;
}
}
// Skip MBs at the end of this slice for Slice Mode 0 or 1
if(*end_of_slice == TRUE && img->cod_counter && !use_bitstream_backing)
{
se.value1 = img->cod_counter;
se.value2 = 0;
se.type = SE_MBTYPE;
TRACE_SE (se.tracestring, "mb_skip_run");
writeSE_UVLC(&se, dataPart);
rlc_bits=se.len;
currMB->bitcounter[BITS_MB_MODE]+=rlc_bits;
img->cod_counter = 0;
}
}
}
/*!
*****************************************************************************
*
* \brief
* For Slice Mode 2: Checks if one partition of one slice exceeds the
* allowed size
*
* \return
* FALSE if all Partitions of this slice are smaller than the allowed size
* TRUE is at least one Partition exceeds the limit
*
* \par Side effects
* none
*
* \date
* 4 November 2001
*
* \author
* Tobias Oelbaum drehvial@gmx.net
*****************************************************************************/
int slice_too_big(int rlc_bits)
{
Slice *currSlice = img->currentSlice;
DataPartition *dataPart;
Bitstream *currStream;
EncodingEnvironmentPtr eep;
int i;
int size_in_bytes;
//! UVLC
if (input->symbol_mode == UVLC)
{
for (i=0; i<currSlice->max_part_nr; i++)
{
dataPart = &(currSlice->partArr[i]);
currStream = dataPart->bitstream;
size_in_bytes = currStream->byte_pos /*- currStream->tmp_byte_pos*/;
if (currStream->bits_to_go < 8)
size_in_bytes++;
if (currStream->bits_to_go < rlc_bits)
size_in_bytes++;
if(size_in_bytes > input->slice_argument)
return TRUE;
}
}
//! CABAC
if (input->symbol_mode ==CABAC)
{
for (i=0; i<currSlice->max_part_nr; i++)
{
dataPart= &(currSlice->partArr[i]);
eep = &(dataPart->ee_cabac);
if( arienco_bits_written(eep) > (input->slice_argument*8))
return TRUE;
}
}
return FALSE;
}
/*!
************************************************************************
* \brief
* Predict one component of a 4x4 Luma block
************************************************************************
*/
void OneComponentLumaPrediction4x4 ( imgpel* mpred, //!< array of prediction values (row by row)
int pic_pix_x, //!< absolute horizontal coordinate of 4x4 block
int pic_pix_y, //!< absolute vertical coordinate of 4x4 block
short* mv, //!< motion vector
short ref, //!< reference frame
StorablePicture **list //!< reference picture list
)
{
int j;
imgpel *ref_line;
width_pad = list[ref]->size_x_pad;
height_pad = list[ref]->size_y_pad;
ref_line = UMVLine4X (list[ref]->imgY_sub, pic_pix_y + mv[1], pic_pix_x + mv[0]);
for (j = 0; j < BLOCK_SIZE; j++)
{
memcpy(mpred, ref_line, BLOCK_SIZE * sizeof(imgpel));
ref_line += img_padded_size_x;
mpred += BLOCK_SIZE;
}
}
/*!
************************************************************************
* \brief
* Predict one 4x4 Luma block
************************************************************************
*/
void LumaPrediction4x4 ( int block_x, //!< relative horizontal block coordinate of 4x4 block
int block_y, //!< relative vertical block coordinate of 4x4 block
int p_dir, //!< prediction direction (0=list0, 1=list1, 2=bipred)
int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT if l1_mode=0)
int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT if l0_mode=0)
short l0_ref_idx, //!< reference frame for list0 prediction (-1: Intra4x4 pred. with l0_mode)
short l1_ref_idx //!< reference frame for list1 prediction
)
{
static imgpel l0_pred[16];
static imgpel l1_pred[16];
int i, j;
int block_x4 = block_x+4;
int block_y4 = block_y+4;
int pic_opix_x = ((img->opix_x + block_x) << 2) + IMG_PAD_SIZE_TIMES4;
int pic_opix_y = ((img->opix_y + block_y) << 2) + IMG_PAD_SIZE_TIMES4;
int bx = block_x >> 2;
int by = block_y >> 2;
imgpel* l0pred = l0_pred;
imgpel* l1pred = l1_pred;
Macroblock* currMB = &img->mb_data[img->current_mb_nr];
int apply_weights = ( (active_pps->weighted_pred_flag && (img->type== P_SLICE || img->type == SP_SLICE)) ||
(active_pps->weighted_bipred_idc && (img->type== B_SLICE)));
short**** mv_array = img->all_mv[by][bx];
if (currMB->bi_pred_me && l0_ref_idx == 0 && l1_ref_idx == 0 && p_dir == 2 && l0_mode==1 && l1_mode==1)
{
mv_array = currMB->bi_pred_me == 1? img->bipred_mv1[by][bx] : img->bipred_mv2[by][bx];
}
switch (p_dir)
{
case 0:
OneComponentLumaPrediction4x4 (l0_pred, pic_opix_x, pic_opix_y, mv_array[LIST_0][l0_ref_idx][l0_mode], l0_ref_idx, listX[0+currMB->list_offset]);
break;
case 1:
OneComponentLumaPrediction4x4 (l1_pred, pic_opix_x, pic_opix_y, mv_array[LIST_1][l1_ref_idx][l1_mode], l1_ref_idx, listX[1+currMB->list_offset]);
break;
case 2:
OneComponentLumaPrediction4x4 (l0_pred, pic_opix_x, pic_opix_y, mv_array[LIST_0][l0_ref_idx][l0_mode], l0_ref_idx, listX[0+currMB->list_offset]);
OneComponentLumaPrediction4x4 (l1_pred, pic_opix_x, pic_opix_y, mv_array[LIST_1][l1_ref_idx][l1_mode], l1_ref_idx, listX[1+currMB->list_offset]);
break;
default:
break;
}
if (apply_weights)
{
if (p_dir==2)
{
int wbp0 = wbp_weight[0][l0_ref_idx][l1_ref_idx][0];
int wbp1 = wbp_weight[1][l0_ref_idx][l1_ref_idx][0];
int offset = (wp_offset[0][l0_ref_idx][0] + wp_offset[1][l1_ref_idx][0] + 1)>>1;
int wp_round = 2*wp_luma_round;
int weight_denom = luma_log_weight_denom + 1;
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value,
((wbp0 * *l0pred++ + wbp1 * *l1pred++ + wp_round) >> (weight_denom)) + offset);
}
else if (p_dir==0)
{
int wp = wp_weight[0][l0_ref_idx][0];
int offset = wp_offset[0][l0_ref_idx][0];
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value,
((wp * *l0pred++ + wp_luma_round) >> luma_log_weight_denom) + offset);
}
else // p_dir==1
{
int wp = wp_weight[1][l1_ref_idx][0];
int offset = wp_offset[1][l1_ref_idx][0];
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value,
((wp * *l1pred++ + wp_luma_round) >> luma_log_weight_denom) + offset );
}
}
else
{
if (p_dir==2)
{
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = (*l0pred++ + *l1pred++ + 1) >> 1;
}
else if (p_dir==0)
{
for (j=block_y; j<block_y4; j++)
{
memcpy(&(img->mpr[j][block_x]), l0pred, BLOCK_SIZE * sizeof(imgpel));
l0pred += BLOCK_SIZE;
}
}
else // p_dir==1
{
for (j=block_y; j<block_y4; j++)
{
memcpy(&(img->mpr[j][block_x]), l1pred, BLOCK_SIZE * sizeof(imgpel));
l1pred += BLOCK_SIZE;
}
}
}
}
/*!
************************************************************************
* \brief
* Predict one 4x4 Luma block
************************************************************************
*/
void LumaPrediction4x4Bi ( int block_x, //!< relative horizontal block coordinate of 4x4 block
int block_y, //!< relative vertical block coordinate of 4x4 block
int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT if l1_mode=0)
int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT if l0_mode=0)
short l0_ref_idx, //!< reference frame for list0 prediction (-1: Intra4x4 pred. with l0_mode)
short l1_ref_idx, //!< reference frame for list1 prediction
int list //!< current list for prediction.
)
{
static imgpel l0_pred[16];
static imgpel l1_pred[16];
int i, j;
int block_x4 = block_x+4;
int block_y4 = block_y+4;
int pic_opix_x = ((img->opix_x + block_x) << 2) + IMG_PAD_SIZE_TIMES4;
int pic_opix_y = ((img->opix_y + block_y) << 2) + IMG_PAD_SIZE_TIMES4;
int bx = block_x >> 2;
int by = block_y >> 2;
imgpel* l0pred = l0_pred;
imgpel* l1pred = l1_pred;
Macroblock* currMB = &img->mb_data[img->current_mb_nr];
int apply_weights = ( (active_pps->weighted_pred_flag && (img->type == P_SLICE || img->type == SP_SLICE)) ||
(active_pps->weighted_bipred_idc && (img->type == B_SLICE)));
short ****mv_array = list ? img->bipred_mv1[by][bx] : img->bipred_mv2[by][bx];
OneComponentLumaPrediction4x4 (l0_pred, pic_opix_x, pic_opix_y, mv_array[LIST_0][l0_ref_idx][l0_mode], l0_ref_idx, listX[0+currMB->list_offset]);
OneComponentLumaPrediction4x4 (l1_pred, pic_opix_x, pic_opix_y, mv_array[LIST_1][l1_ref_idx][l1_mode], l1_ref_idx, listX[1+currMB->list_offset]);
if (apply_weights)
{
int wbp0 = wbp_weight[0][l0_ref_idx][l1_ref_idx][0];
int wbp1 = wbp_weight[1][l0_ref_idx][l1_ref_idx][0];
int offset = (wp_offset[0][l0_ref_idx][0] + wp_offset[1][l1_ref_idx][0] + 1)>>1;
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value,
((wbp0 * *l0pred++ + wbp1 * *l1pred++ + 2*wp_luma_round) >> (luma_log_weight_denom + 1)) + offset);
}
else
{
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = (*l0pred++ + *l1pred++ + 1) >> 1;
}
}
/*!
************************************************************************
* \brief
* Residual Coding of an 8x8 Luma block (not for intra)
*
* \return
* coefficient cost
************************************************************************
*/
int LumaResidualCoding8x8 ( int *cbp, //!< Output: cbp (updated according to processed 8x8 luminance block)
int64 *cbp_blk, //!< Output: block cbp (updated according to processed 8x8 luminance block)
int block8x8, //!< block number of 8x8 block
short p_dir, //!< prediction direction
int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT)
int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT)
short l0_ref_idx, //!< reference picture for list0 prediction
short l1_ref_idx //!< reference picture for list0 prediction
)
{
int block_y, block_x, pic_pix_y, pic_pix_x, i, j, nonzero = 0, cbp_blk_mask;
int coeff_cost = 0;
int mb_y = (block8x8 >> 1) << 3;
int mb_x = (block8x8 & 0x01) << 3;
int pix_y;
int cbp_mask = 1 << block8x8;
int bxx, byy; // indexing curr_blk
int skipped = (l0_mode == 0 && l1_mode == 0 && (img->type != B_SLICE));
Macroblock* currMB = &img->mb_data[img->current_mb_nr];
//set transform size
int need_8x8_transform = currMB->luma_transform_size_8x8_flag;
if ( input->ChromaMCBuffer )
OneComponentChromaPrediction4x4 = OneComponentChromaPrediction4x4_retrieve;
else
OneComponentChromaPrediction4x4 = OneComponentChromaPrediction4x4_regenerate;
//===== loop over 4x4 blocks =====
if(!need_8x8_transform)
{
for (byy=0, block_y=mb_y; block_y<mb_y+8; byy+=4, block_y+=4)
{
pic_pix_y = img->opix_y + block_y;
for (bxx=0, block_x=mb_x; block_x<mb_x+8; bxx+=4, block_x+=4)
{
pic_pix_x = img->opix_x + block_x;
cbp_blk_mask = (block_x>>2) + block_y;
//===== prediction of 4x4 block =====
LumaPrediction4x4 (block_x, block_y, p_dir, l0_mode, l1_mode, l0_ref_idx, l1_ref_idx);
//===== get displaced frame difference ======
for (j=0; j<4; j++)
{
pix_y = pic_pix_y + j;
for (i=0; i<4; i++)
{
img->m7[j][i] = imgY_org[pix_y][pic_pix_x + i] - img->mpr[j+block_y][i+block_x];
}
}
//===== DCT, Quantization, inverse Quantization, IDCT, Reconstruction =====
if ( (img->NoResidueDirect != 1 && !skipped ) ||
((img->qp_scaled)==0 && img->lossless_qpprime_flag==1) )
{
//===== DCT, Quantization, inverse Quantization, IDCT, Reconstruction =====
if (img->type!=SP_SLICE)
nonzero = dct_luma (block_x, block_y, &coeff_cost, 0);
else if(!si_frame_indicator && !sp2_frame_indicator)
nonzero = dct_luma_sp(block_x, block_y, &coeff_cost);// SP frame encoding
else
nonzero = dct_luma_sp2(block_x, block_y, &coeff_cost);//switching SP/SI encoding
if (nonzero)
{
(*cbp_blk) |= (int64)1 << cbp_blk_mask; // one bit for every 4x4 block
(*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block
}
}
}
}
}
else
{
for (byy=0, block_y=mb_y; block_y<mb_y+8; byy+=4, block_y+=4)
{
pic_pix_y = img->opix_y + block_y;
for (bxx=0, block_x=mb_x; block_x<mb_x+8; bxx+=4, block_x+=4)
{
pic_pix_x = img->opix_x + block_x;
cbp_blk_mask = (block_x>>2) + block_y;
//===== prediction of 4x4 block =====
LumaPrediction4x4 (block_x, block_y, p_dir, l0_mode, l1_mode, l0_ref_idx, l1_ref_idx);
//===== get displaced frame difference ======
for (j=0; j<4; j++)
{
pix_y = pic_pix_y + j;
for (i=0; i<4; i++)
{
img->m7[j+byy][i+bxx] = imgY_org[pix_y][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
}
}
}
if (img->NoResidueDirect != 1 && !skipped)
{
if (img->type!=SP_SLICE)
nonzero = dct_luma8x8 (block8x8, &coeff_cost, 0);
if (nonzero)
{
(*cbp_blk) |= 51 << (4*block8x8-2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position
(*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block
}
}
}
/*
The purpose of the action below is to prevent that single or 'expensive' coefficients are coded.
With 4x4 transform there is larger chance that a single coefficient in a 8x8 or 16x16 block may be nonzero.
A single small (level=1) coefficient in a 8x8 block will cost: 3 or more bits for the coefficient,
4 bits for EOBs for the 4x4 blocks,possibly also more bits for CBP. Hence the total 'cost' of that single
coefficient will typically be 10-12 bits which in a RD consideration is too much to justify the distortion improvement.
The action below is to watch such 'single' coefficients and set the reconstructed block equal to the prediction according
to a given criterium. The action is taken only for inter luma blocks.
Notice that this is a pure encoder issue and hence does not have any implication on the standard.
coeff_cost is a parameter set in dct_luma() and accumulated for each 8x8 block. If level=1 for a coefficient,
coeff_cost is increased by a number depending on RUN for that coefficient.The numbers are (see also dct_luma()): 3,2,2,1,1,1,0,0,...
when RUN equals 0,1,2,3,4,5,6, etc.
If level >1 coeff_cost is increased by 9 (or any number above 3). The threshold is set to 3. This means for example:
1: If there is one coefficient with (RUN,level)=(0,1) in a 8x8 block this coefficient is discarded.
2: If there are two coefficients with (RUN,level)=(1,1) and (4,1) the coefficients are also discarded
sum_cnt_nonz is the accumulation of coeff_cost over a whole macro block. If sum_cnt_nonz is 5 or less for the whole MB,
all nonzero coefficients are discarded for the MB and the reconstructed block is set equal to the prediction.
*/
if (img->NoResidueDirect != 1 && !skipped && coeff_cost <= _LUMA_COEFF_COST_ &&
((img->qp_scaled)!=0 || img->lossless_qpprime_flag==0)&&
!(img->type==SP_SLICE && (si_frame_indicator==1 || sp2_frame_indicator==1 )))// last set of conditions
// cannot skip when perfect reconstruction is as in switching pictures or SI pictures
{
coeff_cost = 0;
(*cbp) &= (63 - cbp_mask);
(*cbp_blk) &= ~(51 << (4*block8x8-2*(block8x8 & 0x01)));
for (j=mb_y; j<mb_y+8; j++)
memcpy(&enc_picture->imgY[img->pix_y + j][img->pix_x + mb_x], &img->mpr[j][mb_x], 2 * BLOCK_SIZE * sizeof(imgpel));
if (img->type==SP_SLICE)
{
for (i=mb_x; i < mb_x+BLOCK_SIZE*2; i+=BLOCK_SIZE)
for (j=mb_y; j < mb_y+BLOCK_SIZE*2; j+=BLOCK_SIZE)
copyblock_sp(i,j);
}
}
return coeff_cost;
}
/*!
************************************************************************
* \brief
* Set mode parameters and reference frames for an 8x8 block
************************************************************************
*/
void SetModesAndRefframe (int b8, short* p_dir, int* l0_mode, int* l1_mode, short* fw_ref, short* bw_ref)
{
Macroblock* currMB = &img->mb_data[img->current_mb_nr];
int j = 2*(b8>>1);
int i = 2*(b8 & 0x01);
*l0_mode = *l1_mode = *fw_ref = *bw_ref = -1;
*p_dir = currMB->b8pdir[b8];
if (img->type!=B_SLICE)
{
*fw_ref = enc_picture->ref_idx[LIST_0][img->block_y+j][img->block_x+i];
*bw_ref = 0;
*l0_mode = currMB->b8mode[b8];
*l1_mode = 0;
}
else
{
if (currMB->b8pdir[b8]==-1)
{
*fw_ref = -1;
*bw_ref = -1;
*l0_mode = 0;
*l1_mode = 0;
}
else if (currMB->b8pdir[b8]==0)
{
*fw_ref = enc_picture->ref_idx[LIST_0][img->block_y+j][img->block_x+i];
*bw_ref = 0;
*l0_mode = currMB->b8mode[b8];
*l1_mode = 0;
}
else if (currMB->b8pdir[b8]==1)
{
*fw_ref = 0;
*bw_ref = enc_picture->ref_idx[LIST_1][img->block_y+j][img->block_x+i];
*l0_mode = 0;
*l1_mode = currMB->b8mode[b8];
}
else
{
*fw_ref = enc_picture->ref_idx[LIST_0][img->block_y+j][img->block_x+i];
*bw_ref = enc_picture->ref_idx[LIST_1][img->block_y+j][img->block_x+i];
*l0_mode = currMB->b8mode[b8];
*l1_mode = currMB->b8mode[b8];
}
}
}
/*!
************************************************************************
* \brief
* Residual Coding of a Luma macroblock (not for intra)
************************************************************************
*/
void LumaResidualCoding (void)
{
int i,j,block8x8,b8_x,b8_y;
int l0_mode, l1_mode;
short p_dir, refframe;
int sum_cnt_nonz;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
currMB->cbp = 0 ;
currMB->cbp_blk = 0 ;
sum_cnt_nonz = 0 ;
for (block8x8=0; block8x8<4; block8x8++)
{
short bw_ref;
SetModesAndRefframe (block8x8, &p_dir, &l0_mode, &l1_mode, &refframe, &bw_ref);
sum_cnt_nonz += LumaResidualCoding8x8 (&(currMB->cbp), &(currMB->cbp_blk), block8x8,
p_dir, l0_mode, l1_mode, refframe, bw_ref);
}
if (sum_cnt_nonz <= _LUMA_MB_COEFF_COST_ &&
((img->qp_scaled)!=0 || img->lossless_qpprime_flag==0) &&
!(img->type==SP_SLICE && (si_frame_indicator==1 || sp2_frame_indicator==1)))// modif ES added last set of conditions
//cannot skip if SI or switching SP frame perfect reconstruction is needed
{
currMB->cbp &= 0xfffff0 ;
currMB->cbp_blk &= 0xff0000 ;
for (j=0; j < MB_BLOCK_SIZE; j++)
memcpy(&enc_picture->imgY[img->pix_y+j][img->pix_x], img->mpr[j], MB_BLOCK_SIZE * sizeof (imgpel));
if (img->type==SP_SLICE)
{
for(block8x8=0;block8x8<4;block8x8++)
{
b8_x=(block8x8&1)<<3;
b8_y=(block8x8&2)<<2;
for (i=b8_x;i<b8_x+8;i+=4)
for (j=b8_y;j<b8_y+8;j+=4)
copyblock_sp(i,j);
}
}
}
}
/*!
************************************************************************
* \brief
* Makes the decision if 8x8 tranform will be used (for RD-off)
************************************************************************
*/
int TransformDecision (int block_check, int *cost)
{
int block_y, block_x, pic_pix_y, pic_pix_x, i, j, k;
int mb_y, mb_x, block8x8;
int l0_mode, l1_mode;
short p_dir, fw_ref, bw_ref;
int num_blks;
int cost8x8=0, cost4x4=0;
int *diff_ptr;
if(block_check==-1)
{
block8x8=0;
num_blks=4;
}
else
{
block8x8=block_check;
num_blks=block_check+1;
}
for (; block8x8<num_blks; block8x8++)
{
SetModesAndRefframe (block8x8, &p_dir, &l0_mode, &l1_mode, &fw_ref, &bw_ref);
mb_y = (block8x8 >> 1) << 3;
mb_x = (block8x8 & 0x01) << 3;
//===== loop over 4x4 blocks =====
k=0;
for (block_y=mb_y; block_y<mb_y+8; block_y+=4)
{
pic_pix_y = img->opix_y + block_y;
for (block_x=mb_x; block_x<mb_x+8; block_x+=4)
{
pic_pix_x = img->opix_x + block_x;
//===== prediction of 4x4 block =====
LumaPrediction4x4 (block_x, block_y, p_dir, l0_mode, l1_mode, fw_ref, bw_ref);
//===== get displaced frame difference ======
diff_ptr=&diff64[k];
for (j=0; j<4; j++)
{
for (i=0; i<4; i++, k++)
diff64[k] = imgY_org[pic_pix_y+j][pic_pix_x+i] - img->mpr[j+block_y][i+block_x];
}
cost4x4 += distortion4x4 (diff_ptr);
}
}
cost8x8 += distortion8x8 (diff64);
}
if(input->Transform8x8Mode==2) //always allow 8x8 transform
return 1;
else if(cost8x8<cost4x4)
return 1;
else
{
*cost = (*cost-cost8x8+cost4x4);
return 0;
}
}
/*!
************************************************************************
* \brief
* Predict (on-the-fly) one component of a chroma 4x4 block
************************************************************************
*/
void OneComponentChromaPrediction4x4_regenerate (
imgpel* mpred, //!< array to store prediction values
int block_c_x, //!< horizontal pixel coordinate of 4x4 block
int block_c_y, //!< vertical pixel coordinate of 4x4 block
short****** mv, //!< motion vector array
int list_idx, //!< reference picture list
short ref, //!< reference index
int blocktype, //!< block type
int uv) //!< chroma component
{
int i, j, ii, jj, ii0, jj0, ii1, jj1, if0, if1, jf0, jf1;
short* mvb;
int f1_x = 64/img->mb_cr_size_x;
int f2_x=f1_x-1;
int f1_y = 64/img->mb_cr_size_y;
int f2_y=f1_y-1;
int f3=f1_x*f1_y, f4=f3>>1;
int list_offset = img->mb_data[img->current_mb_nr].list_offset;
int max_y_cr = (int) (list_offset ? (img->height_cr >> 1) - 1 : img->height_cr - 1);
int max_x_cr = (int) (img->width_cr - 1);
int jjx, iix;
int mb_cr_y_div4 = img->mb_cr_size_y>>2;
int mb_cr_x_div4 = img->mb_cr_size_x>>2;
int jpos;
StorablePicture **list = listX[list_idx + list_offset];
imgpel** refimage = list[ref]->imgUV[uv];
for (j=block_c_y; j < block_c_y + BLOCK_SIZE; j++)
{
jjx = j/mb_cr_y_div4;
jpos = (j + img->opix_c_y)*f1_y;
for (i=block_c_x; i < block_c_x + BLOCK_SIZE; i++)
{
iix = i/mb_cr_x_div4;
mvb = mv [jjx][iix][list_idx][ref][blocktype];
ii = (i + img->opix_c_x)*f1_x + mvb[0];
jj = jpos + mvb[1];
if (active_sps->chroma_format_idc == 1)
jj += list[ref]->chroma_vector_adjustment;
ii0 = iClip3 (0, max_x_cr, ii/f1_x);
jj0 = iClip3 (0, max_y_cr, jj/f1_y);
ii1 = iClip3 (0, max_x_cr, (ii+f2_x)/f1_x);
jj1 = iClip3 (0, max_y_cr, (jj+f2_y)/f1_y);
if1 = (ii&f2_x); if0 = f1_x-if1;
jf1 = (jj&f2_y); jf0 = f1_y-jf1;
*mpred++ = (if0 * jf0 * refimage[jj0][ii0] +
if1 * jf0 * refimage[jj0][ii1] +
if0 * jf1 * refimage[jj1][ii0] +
if1 * jf1 * refimage[jj1][ii1] + f4) / f3;
}
}
}
/*!
************************************************************************
* \brief
* Retrieve one component of a chroma 4x4 block from the buffer
************************************************************************
*/
void OneComponentChromaPrediction4x4_retrieve (imgpel* mpred, //!< array to store prediction values
int block_c_x, //!< horizontal pixel coordinate of 4x4 block
int block_c_y, //!< vertical pixel coordinate of 4x4 block
short****** mv, //!< motion vector array
int list_idx, //!< reference picture list
short ref, //!< reference index
int blocktype, //!< block type
int uv) //!< chroma component
{
int j, ii, jj;
short* mvb;
int list_offset = img->mb_data[img->current_mb_nr].list_offset;
int jjx;
int right_shift_x = 4 - chroma_shift_x;
int right_shift_y = 4 - chroma_shift_y;
int jpos;
int pos_x1 = block_c_x >> right_shift_x;
int pos_x2 = (block_c_x + 2) >> right_shift_x;
int ipos1 = ((block_c_x + img->opix_c_x) << chroma_shift_x) + IMG_PAD_SIZE_TIMES4;
int ipos2 = ((block_c_x + 2 + img->opix_c_x) << chroma_shift_x) + IMG_PAD_SIZE_TIMES4;
StorablePicture **list = listX[list_idx + list_offset];
imgpel**** refsubimage = list[ref]->imgUV_sub[uv];
imgpel *line_ptr;
int jj_chroma = ((active_sps->chroma_format_idc == 1) ? list[ref]->chroma_vector_adjustment : 0) + IMG_PAD_SIZE_TIMES4;
width_pad_cr = list[ref]->size_x_cr_pad;
height_pad_cr = list[ref]->size_y_cr_pad;
for (j=block_c_y; j < block_c_y + BLOCK_SIZE; j++)
{
jjx = j >> right_shift_y; // translate into absolute block (luma) coordinates
jpos = ( (j + img->opix_c_y) << chroma_shift_y ) + jj_chroma;
mvb = mv [jjx][pos_x1][list_idx][ref][blocktype];
ii = ipos1 + mvb[0];
jj = jpos + mvb[1];
line_ptr = UMVLine8X_chroma ( refsubimage, jj, ii);
*mpred++ = *line_ptr++;
*mpred++ = *line_ptr;
mvb = mv [jjx][pos_x2][list_idx][ref][blocktype];
ii = ipos2 + mvb[0];
jj = jpos + mvb[1];
line_ptr = UMVLine8X_chroma ( refsubimage, jj, ii);
*mpred++ = *line_ptr++;
*mpred++ = *line_ptr;
}
}
/*!
************************************************************************
* \brief
* Predict an intra chroma 4x4 block
************************************************************************
*/
void IntraChromaPrediction4x4 (int uv, // <-- colour component
int block_x, // <-- relative horizontal block coordinate of 4x4 block
int block_y) // <-- relative vertical block coordinate of 4x4 block
{
int mode = img->mb_data[img->current_mb_nr].c_ipred_mode;
int j;
//===== prediction =====
for (j=block_y; j<block_y+4; j++)
memcpy(&img->mpr[j][block_x],&img->mprr_c[uv][mode][j][block_x], BLOCK_MULTIPLE * sizeof(imgpel));
}
/*!
************************************************************************
* \brief
* Predict one chroma 4x4 block
************************************************************************
*/
void ChromaPrediction4x4 ( int uv, // <-- colour component
int block_x, // <-- relative horizontal block coordinate of 4x4 block
int block_y, // <-- relative vertical block coordinate of 4x4 block
int p_dir, // <-- prediction direction
int l0_mode, // <-- list0 prediction mode (1-7, 0=DIRECT if l1_mode=0)
int l1_mode, // <-- list1 prediction mode (1-7, 0=DIRECT if l0_mode=0)
short l0_ref_idx, // <-- reference frame for list0 prediction (if (<0) -> intra prediction)
short l1_ref_idx) // <-- reference frame for list1 prediction
{
static imgpel l0_pred[MB_BLOCK_SIZE];
static imgpel l1_pred[MB_BLOCK_SIZE];
int i, j;
int block_x4 = block_x+4;
int block_y4 = block_y+4;
imgpel* l0pred = l0_pred;
imgpel* l1pred = l1_pred;
short****** mv_array = img->all_mv;
Macroblock* currMB = &img->mb_data[img->current_mb_nr];
int apply_weights = ( (active_pps->weighted_pred_flag && (img->type == P_SLICE || img->type == SP_SLICE)) ||
(active_pps->weighted_bipred_idc && (img->type == B_SLICE)));
if (currMB->bi_pred_me && l0_ref_idx == 0 && l1_ref_idx == 0 && p_dir == 2 && l0_mode==1 && l1_mode==1)
mv_array = currMB->bi_pred_me == 1? img->bipred_mv1 : img->bipred_mv2 ;
//===== INTRA PREDICTION =====
if (p_dir==-1)
{
IntraChromaPrediction4x4 (uv, block_x, block_y);
return;
}
//===== INTER PREDICTION =====
if ((p_dir==0) || (p_dir==2))
{
(*OneComponentChromaPrediction4x4) (l0_pred, block_x, block_y, mv_array, LIST_0, l0_ref_idx, l0_mode, uv);
}
if ((p_dir==1) || (p_dir==2))
{
(*OneComponentChromaPrediction4x4) (l1_pred, block_x, block_y, mv_array, LIST_1, l1_ref_idx, l1_mode, uv);
}
if (apply_weights)
{
if (p_dir==2)
{
int wbp0 = wbp_weight[0][l0_ref_idx][l1_ref_idx][uv+1];
int wbp1 = wbp_weight[1][l0_ref_idx][l1_ref_idx][uv+1];
int offset = (wp_offset[0][l0_ref_idx][uv+1] + wp_offset[1][l1_ref_idx][uv+1] + 1)>>1;
int wp_round = 2*wp_chroma_round;
int weight_denom = luma_log_weight_denom + 1;
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value_uv,
((wbp0 * *l0pred++ + wbp1 * *l1pred++ + wp_round) >> (weight_denom)) + (offset) );
}
else if (p_dir==0)
{
int wp = wp_weight[0][l0_ref_idx][uv+1];
int offset = wp_offset[0][l0_ref_idx][uv+1];
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value_uv, (( wp * *l0pred++ + wp_chroma_round) >> chroma_log_weight_denom) + offset);
}
else // (p_dir==1)
{
int wp = wp_weight[1][l1_ref_idx][uv+1];
int offset = wp_offset[1][l1_ref_idx][uv+1];
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = iClip1( img->max_imgpel_value_uv, ((wp * *l1pred++ + wp_chroma_round) >> chroma_log_weight_denom) + offset);
}
}
else
{
if (p_dir==2)
{
for (j=block_y; j<block_y4; j++)
for (i=block_x; i<block_x4; i++)
img->mpr[j][i] = (*l0pred++ + *l1pred++ + 1) >> 1;
}
else if (p_dir==0)
{
for (j=block_y; j<block_y4; j++)
{
memcpy(&(img->mpr[j][block_x]), l0pred, BLOCK_SIZE * sizeof(imgpel));
l0pred += BLOCK_SIZE;
}
}
else // (p_dir==1)
{
for (j=block_y; j<block_y4; j++)
{
memcpy(&(img->mpr[j][block_x]), l1pred, BLOCK_SIZE * sizeof(imgpel));
l1pred += BLOCK_SIZE;
}
}
}
}
/*!
************************************************************************
* \brief
* Chroma residual coding for an macroblock
************************************************************************
*/
void ChromaResidualCoding (int* cr_cbp)
{
static const int block8x8_idx[3][4][4] = //ADD-VG-15052004
{
{ {0, 1, 0, 0},
{2, 3, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
},
{ {0, 1, 0, 0},
{0, 1, 0, 0},
{2, 3, 0, 0},
{2, 3, 0, 0},
},
{ {0, 0, 1, 1},
{0, 0, 1, 1},
{2, 2, 3, 3},
{2, 2, 3, 3}
}
};
int uv, block8, block_y, block_x, j, i;
int l0_mode, l1_mode;
short p_dir, refframe, bw_ref;
int skipped = (img->mb_data[img->current_mb_nr].mb_type == 0 && (img->type == P_SLICE || img->type == SP_SLICE));
int yuv = img->yuv_format - 1; //ADD-VG-15052004
if ( input->ChromaMCBuffer )
OneComponentChromaPrediction4x4 = OneComponentChromaPrediction4x4_retrieve;
else
OneComponentChromaPrediction4x4 = OneComponentChromaPrediction4x4_regenerate;
for (*cr_cbp=0, uv=0; uv<2; uv++)
{
//===== prediction of chrominance blocks ===d==
block8 = 0;
for (block_y=0; block_y < img->mb_cr_size_y; block_y+=4)
for (block_x=0; block_x < img->mb_cr_size_x; block_x+=4)
{
block8 = block8x8_idx[yuv][block_y>>2][block_x>>2];
SetModesAndRefframe (block8, &p_dir, &l0_mode, &l1_mode, &refframe, &bw_ref);
ChromaPrediction4x4 (uv, block_x, block_y, p_dir, l0_mode, l1_mode, refframe, bw_ref);
}
// ==== set chroma residue to zero for skip Mode in SP frames
if (img->NoResidueDirect)
{
for (j=0; j<img->mb_cr_size_y; j++)
memcpy(&enc_picture->imgUV[uv][img->pix_c_y+j][img->pix_c_x], img->mpr[j], img->mb_cr_size_x * sizeof(imgpel));
}
else if (skipped && img->type==SP_SLICE)
{
for (j=0; j<8; j++)
memset(img->m7[j], 0 , 8 * sizeof(int));
}
else
if (skipped)
{
for (j=0; j<img->mb_cr_size_y; j++)
memcpy(&enc_picture->imgUV[uv][img->pix_c_y+j][img->pix_c_x], img->mpr[j], img->mb_cr_size_x * sizeof(imgpel));
}
else
{
for (j=0; j<img->mb_cr_size_y; j++)
for (i=0; i<img->mb_cr_size_x; i++)
{
img->m7[j][i] = imgUV_org[uv][img->opix_c_y+j][img->opix_c_x+i] - img->mpr[j][i];
}
}
//===== DCT, Quantization, inverse Quantization, IDCT, and Reconstruction =====
//===== Call function for skip mode in SP frames to properly process frame ====
if (skipped && img->type==SP_SLICE)
{
if(si_frame_indicator || sp2_frame_indicator)
*cr_cbp=dct_chroma_sp2(uv,*cr_cbp);//modif ES added, calls the SI/switching SP encoding function
else
*cr_cbp=dct_chroma_sp(uv,*cr_cbp);
}
else
{
if (!img->NoResidueDirect && !skipped)
{
if (img->type!=SP_SLICE || (img->mb_data[img->current_mb_nr].mb_type==I16MB ))
{
//even if the block is intra it should still be treated as SP
*cr_cbp=dct_chroma (uv,*cr_cbp);
}
else
{
if(si_frame_indicator||sp2_frame_indicator)
*cr_cbp=dct_chroma_sp2(uv,*cr_cbp);// SI frames or switching SP frames
else
*cr_cbp=dct_chroma_sp(uv,*cr_cbp);
}
}
}
}
//===== update currMB->cbp =====
img->mb_data[img->current_mb_nr].cbp += ((*cr_cbp)<<4);
}
/*!
************************************************************************
* \brief
* Intra prediction of the chrminance layers of one macroblock
************************************************************************
*/
void IntraChromaPrediction (int *mb_up, int *mb_left, int*mb_up_left)
{
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
int s, s0, s1, s2, s3, i, j, k;
imgpel** image;
int block_x, block_y;
int mb_nr = img->current_mb_nr;
int mb_available_up;
int mb_available_left[2];
int mb_available_up_left;
int ih,iv;
int ib,ic,iaa;
int uv;
imgpel hline[16], vline[16];
int mode;
int best_mode = DC_PRED_8; //just an initilaization here, should always be overwritten
int cost;
int min_cost;
PixelPos up; //!< pixel position p(0,-1)
PixelPos left[17]; //!< pixel positions p(-1, -1..15)
int cr_MB_x = img->mb_cr_size_x;
int cr_MB_y = img->mb_cr_size_y;
int blk_x;
int blk_y;
int b8,b4;
int yuv = img->yuv_format - 1;
static const int block_pos[3][4][4]= //[yuv][b8][b4]
{
{ {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}}
};
for (i=0;i<cr_MB_y+1;i++)
{
getNeighbour(mb_nr, -1 , i-1 , IS_CHROMA, &left[i]);
}
getNeighbour(mb_nr, 0 , -1 , IS_CHROMA, &up);
mb_available_up = up.available;
mb_available_up_left = left[0].available;
mb_available_left[0] = mb_available_left[1] = left[1].available;
if(input->UseConstrainedIntraPred)
{
mb_available_up = up.available ? img->intra_block[up.mb_addr] : 0;
for (i=0, mb_available_left[0]=1; i<(cr_MB_y>>1);i++)
mb_available_left[0] &= left[i+1].available ? img->intra_block[left[i+1].mb_addr]: 0;
for (i=(cr_MB_y>>1), mb_available_left[1]=1; i<cr_MB_y;i++)
mb_available_left[1] &= left[i+1].available ? img->intra_block[left[i+1].mb_addr]: 0;
mb_available_up_left = left[0].available ? img->intra_block[left[0].mb_addr]: 0;
}
if (mb_up)
*mb_up = mb_available_up;
if (mb_left)
*mb_left = mb_available_left[0] && mb_available_left[1];
if (mb_up_left)
*mb_up_left = mb_available_up_left;
// compute all chroma intra prediction modes for both U and V
for (uv=0; uv<2; uv++)
{
image = enc_picture->imgUV[uv];
// DC prediction
for(b8=0; b8<img->num_blk8x8_uv >> 1;b8++)
{
for (b4=0; b4<4; b4++)
{
block_y = subblk_offset_y[yuv][b8][b4];
block_x = subblk_offset_x[yuv][b8][b4];
blk_x = block_x;
blk_y = block_y + 1;
s=img->dc_pred_value_chroma;
s0=s1=s2=s3=0;
//===== get prediction value =====
switch (block_pos[yuv][b8][b4])
{
case 0: //===== TOP LEFT =====
if (mb_available_up) for (i=blk_x;i<(blk_x+4);i++) s0 += image[up.pos_y][up.pos_x + i];
if (mb_available_left[0]) for (i=blk_y;i<(blk_y+4);i++) s2 += image[left[i].pos_y][left[i].pos_x];
if (mb_available_up && mb_available_left[0]) s = (s0+s2+4) >> 3;
else if (mb_available_up) s = (s0 +2) >> 2;
else if (mb_available_left[0]) s = (s2 +2) >> 2;
break;
case 1: //===== TOP RIGHT =====
if (mb_available_up) for (i=blk_x;i<(blk_x+4);i++) s1 += image[up.pos_y][up.pos_x + i];
else if (mb_available_left[0]) for (i=blk_y;i<(blk_y+4);i++) s2 += image[left[i].pos_y][left[i].pos_x];
if (mb_available_up) s = (s1 +2) >> 2;
else if (mb_available_left[0]) s = (s2 +2) >> 2;
break;
case 2: //===== BOTTOM LEFT =====
if (mb_available_left[1]) for (i=blk_y;i<(blk_y+4);i++) s3 += image[left[i].pos_y][left[i].pos_x];
else if (mb_available_up) for (i=blk_x;i<(blk_x+4);i++) s0 += image[up.pos_y][up.pos_x + i];
if (mb_available_left[1]) s = (s3 +2) >> 2;
else if (mb_available_up) s = (s0 +2) >> 2;
break;
case 3: //===== BOTTOM RIGHT =====
if (mb_available_up) for (i=blk_x;i<(blk_x+4);i++) s1 += image[up.pos_y][up.pos_x + i];
if (mb_available_left[1]) for (i=blk_y;i<(blk_y+4);i++) s3 += image[left[i].pos_y][left[i].pos_x];
if (mb_available_up && mb_available_left[1]) s = (s1+s3+4) >> 3;
else if (mb_available_up) s = (s1 +2) >> 2;
else if (mb_available_left[1]) s = (s3 +2) >> 2;
break;
}
//===== prediction =====
for (j=block_y; j<block_y+4; j++)
for (i=block_x; i<block_x+4; i++)
{
img->mprr_c[uv][DC_PRED_8][j][i] = s;
}
}
}
// vertical prediction
if (mb_available_up)
{
memcpy(hline,&image[up.pos_y][up.pos_x], cr_MB_x * sizeof(imgpel));
for (j=0; j<cr_MB_y; j++)
memcpy(img->mprr_c[uv][VERT_PRED_8][j], hline, cr_MB_x * sizeof(imgpel));
}
// horizontal prediction
if (mb_available_left[0] && mb_available_left[1])
{
for (i=0; i<cr_MB_y; i++)
vline[i] = image[left[i+1].pos_y][left[i+1].pos_x];
for (i=0; i<cr_MB_x; i++)
for (j=0; j<cr_MB_y; j++)
img->mprr_c[uv][HOR_PRED_8][j][i] = vline[j];
}
// plane prediction
if (mb_available_left[0] && mb_available_left[1] && mb_available_up && mb_available_up_left)
{
ih = (cr_MB_x>>1)*(hline[cr_MB_x-1] - image[left[0].pos_y][left[0].pos_x]);
for (i=0;i<(cr_MB_x>>1)-1;i++)
ih += (i+1)*(hline[(cr_MB_x>>1)+i] - hline[(cr_MB_x>>1)-2-i]);
iv = (cr_MB_y>>1)*(vline[cr_MB_y-1] - image[left[0].pos_y][left[0].pos_x]);
for (i=0;i<(cr_MB_y>>1)-1;i++)
iv += (i+1)*(vline[(cr_MB_y>>1)+i] - vline[(cr_MB_y>>1)-2-i]);
ib= ((cr_MB_x == 8?17:5)*ih+2*cr_MB_x)>>(cr_MB_x == 8?5:6);
ic= ((cr_MB_y == 8?17:5)*iv+2*cr_MB_y)>>(cr_MB_y == 8?5:6);
iaa=16*(hline[cr_MB_x-1]+vline[cr_MB_y-1]);
for (j=0; j<cr_MB_y; j++)
for (i=0; i<cr_MB_x; i++)
img->mprr_c[uv][PLANE_8][j][i]= iClip3(0, img->max_imgpel_value_uv,
(iaa+(i-(cr_MB_x>>1)+1)*ib+(j-(cr_MB_y>>1)+1)*ic+16)>>5);
}
}
if (!input->rdopt) // the rd-opt part does not work correctly (see encode_one_macroblock)
{ // since ipredmodes could be overwritten => encoder-decoder-mismatches
// pick lowest cost prediction mode
min_cost = INT_MAX;
for (i=0;i<cr_MB_y;i++)
{
getNeighbour(mb_nr, 0 , i, IS_CHROMA, &left[i]);
}
for (mode=DC_PRED_8; mode<=PLANE_8; mode++)
{
if ((img->type != I_SLICE || !input->IntraDisableInterOnly) && input->ChromaIntraDisable == 1 && mode!=DC_PRED_8)
continue;
if ((mode==VERT_PRED_8 && !mb_available_up) ||
(mode==HOR_PRED_8 && (!mb_available_left[0] || !mb_available_left[1])) ||
(mode==PLANE_8 && (!mb_available_left[0] || !mb_available_left[1] || !mb_available_up || !mb_available_up_left)))
continue;
cost = 0;
for (uv=0; uv<2; uv++)
{
image = imgUV_org[uv];
for (block_y=0; block_y<cr_MB_y; block_y+=4)
for (block_x=0; block_x<cr_MB_x; block_x+=4)
{
for (k=0,j=block_y; j<block_y+4; j++)
{
for (i=block_x; i<block_x+4; i++,k++)
diff[k] = image[left[j].pos_y][left[j].pos_x+i] - img->mprr_c[uv][mode][j][i];
}
cost += distortion4x4(diff);
}
}
if (cost < min_cost)
{
best_mode = mode;
min_cost = cost;
}
}
currMB->c_ipred_mode = best_mode;
}
}
/*!
**************************************************************************************
* \brief
* RD Decision for Intra prediction mode of the chrominance layers of one macroblock
**************************************************************************************
*/
void IntraChromaRDDecision (RD_PARAMS enc_mb)
{
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
int i, j, k;
imgpel** image;
int block_x, block_y;
int mb_nr = img->current_mb_nr;
int mb_available_up;
int mb_available_left[2];
int mb_available_up_left;
int uv;
int mode;
int best_mode = DC_PRED_8; //just an initialization here, should always be overwritten
int cost;
int min_cost;
PixelPos up; //!< pixel position p(0,-1)
PixelPos left[17]; //!< pixel positions p(-1, -1..15)
int cr_MB_x = img->mb_cr_size_x;
int cr_MB_y = img->mb_cr_size_y;
for (i=0;i<cr_MB_y+1;i++)
{
getNeighbour(mb_nr, -1 , i-1 , IS_CHROMA, &left[i]);
}
getNeighbour(mb_nr, 0 , -1 , IS_CHROMA, &up);
mb_available_up = up.available;
mb_available_up_left = left[0].available;
mb_available_left[0] = mb_available_left[1] = left[1].available;
if(input->UseConstrainedIntraPred)
{
mb_available_up = up.available ? img->intra_block[up.mb_addr] : 0;
for (i=0, mb_available_left[0]=1; i<(cr_MB_y>>1);i++)
mb_available_left[0] &= left[i+1].available ? img->intra_block[left[i+1].mb_addr]: 0;
for (i=(cr_MB_y>>1), mb_available_left[1]=1; i<cr_MB_y;i++)
mb_available_left[1] &= left[i+1].available ? img->intra_block[left[i+1].mb_addr]: 0;
mb_available_up_left = left[0].available ? img->intra_block[left[0].mb_addr]: 0;
}
// pick lowest cost prediction mode
min_cost = INT_MAX;
for (i=0;i<cr_MB_y;i++)
{
getNeighbour(mb_nr, 0 , i, IS_CHROMA, &left[i]);
}
if ( img->MbaffFrameFlag && img->field_mode )
{
for (i=0;i<cr_MB_y;i++)
{
left[i].pos_y = left[i].pos_y >> 1;
}
}
for (mode=DC_PRED_8; mode<=PLANE_8; mode++)
{
if ((mode==VERT_PRED_8 && !mb_available_up) ||
(mode==HOR_PRED_8 && (!mb_available_left[0] || !mb_available_left[1])) ||
(mode==PLANE_8 && (!mb_available_left[0] || !mb_available_left[1] || !mb_available_up || !mb_available_up_left)))
continue;
cost = 0;
for (uv=0; uv<2; uv++)
{
image = imgUV_org[uv];
for (block_y=0; block_y<cr_MB_y; block_y+=4)
{
for (block_x=0; block_x<cr_MB_x; block_x+=4)
{
for (k=0,j=block_y; j<block_y+4; j++)
{
for (i=block_x; i<block_x+4; i++,k++)
diff[k] = image[left[j].pos_y][left[j].pos_x+i] - img->mprr_c[uv][mode][j][i];
}
cost += distortion4x4(diff);
}
if (cost > min_cost) break;
}
if (cost > min_cost) break;
}
cost += (int) (enc_mb.lambda_me[Q_PEL] * mvbits[ mode ]); // exp golomb coding cost for mode signaling
if (cost < min_cost)
{
best_mode = mode;
min_cost = cost;
}
}
currMB->c_ipred_mode = best_mode;
}
/*!
************************************************************************
* \brief
* Check if all reference frames for a macroblock are zero
************************************************************************
*/
int ZeroRef (Macroblock* currMB)
{
int i,j;
for (j=img->block_y; j<img->block_y + BLOCK_MULTIPLE; j++)
for (i=img->block_x; i<img->block_x + BLOCK_MULTIPLE; i++)
{
if (enc_picture->ref_idx[LIST_0][j][i]!=0)
return 0;
}
return 1;
}
/*!
************************************************************************
* \brief
* Converts macroblock type to coding value
************************************************************************
*/
int MBType2Value (Macroblock* currMB)
{
static const int dir1offset[3] = { 1, 2, 3};
static const int dir2offset[3][3] = {{ 0, 4, 8}, // 1. block forward
{ 6, 2, 10}, // 1. block backward
{12, 14, 16}}; // 1. block bi-directional
int mbtype, pdir0, pdir1;
if (img->type!=B_SLICE)
{
if (currMB->mb_type==I8MB ||currMB->mb_type==I4MB)
return (img->type==I_SLICE ? 0 : 6);
else if (currMB->mb_type==I16MB) return (img->type==I_SLICE ? 0 : 6) + img->i16offset;
else if (currMB->mb_type==IPCM) return (img->type==I_SLICE ? 25 : 31);
else if (currMB->mb_type==P8x8)
{
if (input->symbol_mode==UVLC
&& ZeroRef (currMB)) return 5;
else return 4;
}
else return currMB->mb_type;
}
else
{
mbtype = currMB->mb_type;
pdir0 = currMB->b8pdir[0];
pdir1 = currMB->b8pdir[3];
if (mbtype==0) return 0;
else if (mbtype==I4MB || mbtype==I8MB)
return 23;
else if (mbtype==I16MB) return 23 + img->i16offset;
else if (mbtype==IPCM) return 48;
else if (mbtype==P8x8) return 22;
else if (mbtype==1) return dir1offset[pdir0];
else if (mbtype==2) return 4 + dir2offset[pdir0][pdir1];
else return 5 + dir2offset[pdir0][pdir1];
}
}
/*!
************************************************************************
* \brief
* Writes 4x4 intra prediction modes for a macroblock
************************************************************************
*/
int writeIntra4x4Modes(void)
{
int i;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
SyntaxElement se;
int *bitCount = currMB->bitcounter;
Slice *currSlice = img->currentSlice;
const int *partMap = assignSE2partition[input->partition_mode];
DataPartition *dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]);
int rate = 0;
currMB->IntraChromaPredModeFlag = 1;
for(i=0;i<16;i++)
{
se.context = i;
se.value1 = currMB->intra_pred_modes[i];
se.value2 = 0;
#if TRACE
if (se.value1 < 0 )
snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 4x4 mode = predicted (context: %d)",se.context);
else
snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 4x4 mode = %3d (context: %d)",se.value1,se.context);
#endif
// set symbol type and function pointers
se.type = SE_INTRAPREDMODE;
// encode and update rate
writeIntraPredMode (&se, dataPart);
bitCount[BITS_COEFF_Y_MB]+=se.len;
rate += se.len;
}
return rate;
}
/*!
************************************************************************
* \brief
* Writes 8x8 intra prediction modes for a macroblock
************************************************************************
*/
int writeIntra8x8Modes(void)
{
int block8x8;
Macroblock *currMB = &img->mb_data[img->current_mb_nr];
SyntaxElement se;
int *bitCount = currMB->bitcounter;
Slice *currSlice = img->currentSlice;
const int *partMap = assignSE2partition[input->partition_mode];
DataPartition *dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]);
int rate = 0;
currMB->IntraChromaPredModeFlag = 1;
for(block8x8=0;block8x8<4;block8x8++)
{
se.context = block8x8<<2;
se.value1 = currMB->intra_pred_modes8x8[(block8x8<<2)];
se.value2 = 0;
#if TRACE
if (se.value1 < 0 )
snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 8x8 mode = predicted (context: %d)",se.context);
else
snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 8x8 mode = %3d (context: %d)",se.value1,se.context);
#endif
// set symbol type and function pointers
se.type = SE_INTRAPREDMODE;
// encode and update rate
writeIntraPredMode (&se, dataPart);
bitCount[BITS_COEFF_Y_MB]+=se.len;
rate += se.len;
}
return rate;
}
int writeIntraModes(void)
{
switch (img->mb_data[img->current_mb_nr].mb_type)
{
case I4MB:
return writeIntra4x4Modes();
break;
case I8MB:
return writeIntra8x8Modes();
break;
default:
return 0;
break;
}
}
/*!
************************************************************************
* \brief
* Converts 8x8 block type to coding value
************************************************************************
*/
int B8Mode2Value (int b8mode, int b8pdir)
{
static const int b8start[8] = {0,0,0,0, 1, 4, 5, 10};
static const int b8inc [8] = {0,0,0,0, 1, 2, 2, 1};
if (img->type!=B_SLICE)
{
return (b8mode-4);
}
else
{
return b8start[b8mode] + b8inc[b8mode] * b8pdir;
}
}
/*!
************************************************************************
* \brief
* Codes macroblock header
* \param rdopt
* true for calls during RD-optimization
* \param coeff_rate
* bitrate of Luma and Chroma coeff
************************************************************************
*/
int writeMBLayer (int rdopt, int *coeff_rate)
{
int i,j;
int mb_nr = img->current_mb_nr;
int prev_mb_nr = FmoGetPreviousMBNr(img->current_mb_nr);
Macroblock* currMB = &img->mb_data[mb_nr];
Macroblock* prevMB = mb_nr ? (&img->mb_data[prev_mb_nr]) : NULL;
SyntaxElement se;
int* bitCount = currMB->bitcounter;
Slice* currSlice = img->currentSlice;
DataPartition* dataPart;
const int* partMap = assignSE2partition[input->partition_mode];
int no_bits = 0;
int skip = currMB->mb_type ? 0:((img->type == B_SLICE) ? !currMB->cbp:1);
int mb_type;
int prevMbSkipped = 0;
int mb_field_tmp;
Macroblock *topMB = NULL;
int WriteFrameFieldMBInHeader = 0;
if (img->MbaffFrameFlag)
{
if (0==(mb_nr & 0x01))
{
WriteFrameFieldMBInHeader = 1; // top field
prevMbSkipped = 0;
}
else
{
if (prevMB->mb_type ? 0:((img->type == B_SLICE) ? !prevMB->cbp:1))
{
WriteFrameFieldMBInHeader = 1; // bottom, if top was skipped