void MvDataCodec::CodePredmode(const MvData& in_data) { int val = in_data.Mode()[b_yp][b_xp] - BlockModePrediction( in_data.Mode() ); if (val < 0) val += 4; //produce value mod 4 for (int bin = 1; bin<= val; ++bin) EncodeSymbol( 0 , ChoosePredContext( in_data , bin ) ); if (val != 3) //if we've had three zeroes, know we must have value 3 EncodeSymbol( 1 , ChoosePredContext( in_data , val + 1 ) ); }
void MvDataCodec::CodeMv2(const MvData& in_data) { const MvArray& mv_array = in_data.Vectors(2); const MVector pred = Mv2Prediction( mv_array , in_data.Mode() ); const int valx = mv_array[b_yp][b_xp].x - pred.x; const int abs_valx = abs(valx); for (int bin = 1; bin <= abs_valx; ++bin) EncodeSymbol( 0 , ChooseREF2xContext( in_data , bin ) ); EncodeSymbol( 1 , ChooseREF2xContext( in_data , abs_valx + 1 ) ); if (valx != 0) EncodeSymbol( ( (valx > 0)? 1 : 0) , ChooseREF2xSignContext( in_data ) ); const int valy = mv_array[b_yp][b_xp].y-pred.y; const int abs_valy = std::abs(valy); for (int bin = 1; bin<=abs_valy; ++bin ) EncodeSymbol( 0 , ChooseREF2yContext( in_data , bin ) ); EncodeSymbol( 1 , ChooseREF2yContext( in_data , abs_valy + 1 ) ); if (valy != 0) EncodeSymbol( ( (valy > 0)? 1 : 0) , ChooseREF2ySignContext( in_data ) ); }
void MvDataCodec::CodeDC(const MvData& in_data) { //begin with Y DC value const ValueType valY = in_data.DC( Y_COMP )[b_yp][b_xp] - DCPrediction( in_data.DC(Y_COMP) , in_data.Mode() ); const ValueType abs_valY = std::abs( valY ); for (ValueType bin = 1; bin <= abs_valY; ++bin) EncodeSymbol( 0 , ChooseYDCContext( in_data , bin ) ); EncodeSymbol( 1 , ChooseYDCContext (in_data , abs_valY + 1 ) ); if (valY != 0) EncodeSymbol( ( (valY > 0)? 1 : 0) , ChooseYDCSignContext( in_data ) ); //now do U and V if necessary if (m_cformat != Yonly) { //continue with U and V DC values const int valU = in_data.DC(U_COMP)[b_yp][b_xp] - DCPrediction(in_data.DC( U_COMP ) , in_data.Mode()); const int abs_valU = std::abs( valU ); for (ValueType bin = 1; bin<=abs_valU ; ++bin) EncodeSymbol( 0 , ChooseUDCContext( in_data , bin ) ); EncodeSymbol( 1 , ChooseUDCContext( in_data , abs_valU + 1 ) ); if (valU != 0) EncodeSymbol( ( (valU > 0) ? 1 : 0) , ChooseUDCSignContext( in_data ) ); const int valV = in_data.DC( V_COMP )[b_yp][b_xp] - DCPrediction( in_data.DC( V_COMP ) , in_data.Mode() ); const int abs_valV = std::abs( valV ); for (ValueType bin = 1; bin<=abs_valV ; ++bin) EncodeSymbol( 0 , ChooseVDCContext( in_data , bin ) ); EncodeSymbol( 1 , ChooseVDCContext( in_data , abs_valV + 1 ) ); if (valV != 0) EncodeSymbol( ( (valV > 0)? 1 : 0) , ChooseVDCSignContext( in_data ) ); } }
void MvDataCodec::DecodePredmode( MvData& out_data ) { int val = 0; int bin = 1; bool bit; do { DecodeSymbol( bit , ChoosePredContext( out_data , bin ) ); if (!bit) val++; bin++; } while (!bit && val != 3); out_data.Mode()[b_yp][b_xp] = PredMode( ( val + BlockModePrediction (out_data.Mode() ) ) %4); }
void MvDataCodec::DecodeMv2( MvData& out_data ) { MVector pred = Mv2Prediction( out_data.Vectors(2) , out_data.Mode() ); int val = 0; int bin = 1; bool bit; do { DecodeSymbol( bit , ChooseREF2xContext( out_data , bin ) ); if ( !bit ) val++; bin++; } while ( !bit ); if (val != 0) { DecodeSymbol( bit , ChooseREF2xSignContext( out_data ) ); if (!bit) val = -val; } out_data.Vectors(2)[b_yp][b_xp].x = val + pred.x; val = 0; bin = 1; do { DecodeSymbol( bit , ChooseREF2yContext( out_data , bin ) ); if ( !bit ) val++; bin++; } while ( !bit ); if (val != 0) { DecodeSymbol( bit , ChooseREF2ySignContext( out_data ) ); if ( !bit ) val = -val; } out_data.Vectors(2)[b_yp][b_xp].y = val + pred.y; }
// Main decode function void PredModeCodec::DoWorkDecode( MvData& out_data) { int step,max; int split_depth; int xstart,ystart; // Then the prediction mode for (m_sb_yp = 0,m_sb_tlb_y = 0; m_sb_yp < out_data.SBSplit().LengthY(); ++m_sb_yp,m_sb_tlb_y += 4) { for (m_sb_xp = 0,m_sb_tlb_x = 0; m_sb_xp < out_data.SBSplit().LengthX(); ++m_sb_xp,m_sb_tlb_x += 4) { split_depth = out_data.SBSplit()[m_sb_yp][m_sb_xp]; step = 4 >> (split_depth); max = (1 << split_depth); //now do all the block mvs in the mb for (int j = 0; j < max; ++j) { for (int i = 0; i < max; ++i) { xstart = m_b_xp = m_sb_tlb_x + i * step; ystart = m_b_yp = m_sb_tlb_y + j * step; DecodeVal(out_data); // propagate throughout SB for (m_b_yp = ystart; m_b_yp < ystart+step; m_b_yp++) { for (m_b_xp = xstart; m_b_xp < xstart+step; m_b_xp++) { out_data.Mode()[m_b_yp][m_b_xp] = out_data.Mode()[ystart][xstart]; }//m_b_xp }//m_b_yp }//i }//j }//m_sb_xp }//m_sb_yp }
void MotionCompensator::CompensateComponent( Picture* pic , Picture* refsptr[2] , const MvData& mv_data , const CompSort cs ) { // Set up references to pictures and references PicArray& pic_data_out = pic->Data( cs ); // Size of picture component being motion compensated const PicArray& ref1up = refsptr[0]->UpData( cs ); const PicArray& ref2up = refsptr[1]->UpData( cs ); // Set up a row of blocks which will contain the MC data, which // we'll add or subtract to pic_data_out TwoDArray<ValueType> pic_data(m_bparams.Yblen(), pic_data_out.LengthX(), 0 ); // Factors to compensate for subsampling of chroma int xscale_shift = 0; int yscale_shift = 0; if ( cs != Y_COMP ) { if (m_cformat == format420) { xscale_shift = 1; yscale_shift = 1; } else if (m_cformat == format422) { xscale_shift = 1; yscale_shift = 0; } } ImageCoords pic_size(pic->GetPparams().Xl(), pic->GetPparams().Yl()); if ( cs != Y_COMP ) { pic_size.x = pic->GetPparams().ChromaXl(); pic_size.y = pic->GetPparams().ChromaYl(); } // Reference to the relevant DC array const TwoDArray<ValueType>& dcarray = mv_data.DC( cs ); // Set up references to the vectors const int num_refs = pic->GetPparams().Refs().size(); const MvArray* mv_array1; const MvArray* mv_array2; mv_array1 = &mv_data.Vectors(1); if (num_refs ==2 ) mv_array2 = &mv_data.Vectors(2); else mv_array2 = &mv_data.Vectors(1); ReConfig();//set all the weighting blocks up //Blocks are listed left to right, line by line. MVector mv1,mv2; PredMode block_mode; //Coords of the top-left corner of a block ImageCoords pos; //Loop for each block in the output image. //The CompensateBlock function will use the image pointed to by ref1up //and add the compensated pixels to the image pointed to by pic_data. size_t wgt_idx; int save_from_row = m_bparams.Ybsep()-m_bparams.Yoffset(); // unpadded picture dimensions const int x_end_data = pic_data_out.FirstX() + std::min(pic_data_out.LengthX(), pic_size.x ); const int y_end_data = pic_data_out.FirstY() + std::min(pic_data_out.LengthY(), pic_size.y ); const int blocks_per_mb_row = m_predparams.XNumBlocks()/m_predparams.XNumSB(); const int blocks_per_sb_row = blocks_per_mb_row>>1; // The picture does not contain integral number of blocks. So not all // blocks need to be processed. Compute the relevant blocks to be // processed int y_num_blocks = std::min((NUM_USED_BLKS(pic_size.y,m_bparams.Ybsep(),m_bparams.Yblen())), m_predparams.YNumBlocks()); int x_num_blocks = std::min((NUM_USED_BLKS(pic_size.x,m_bparams.Xbsep(),m_bparams.Xblen())), m_predparams.XNumBlocks()); //Loop over all the block rows pos.y = -m_bparams.Yoffset(); for(int yblock = 0; yblock < y_num_blocks; ++yblock) { pos.x = -m_bparams.Xoffset(); int xincr, xb_incr = 0; //loop over all the blocks in a row for(int xblock = 0 ; xblock < x_num_blocks; xblock+=xb_incr) { int split_mode = mv_data.SBSplit()[yblock/blocks_per_mb_row][xblock/blocks_per_mb_row]; int blk_x, blk_y = 1; switch (split_mode) { case 0: // processing superblock blk_x = blocks_per_mb_row; break; case 1: // processing sub-superblock blk_x = blocks_per_sb_row; break; case 2: // processing block default: blk_x = 1; break; } //Decide which weights to use. if (pos.x >=0 && (xblock+blk_x) < x_num_blocks) { // block is entirely within picture in x direction if (pos.y < 0) wgt_idx = 1; else if ((yblock+blk_y) < y_num_blocks) wgt_idx = 4; else wgt_idx = 7; } else if (pos.x < 0) { // left edge of block is outside picture in x direction if (pos.y < 0) wgt_idx = 0; else if ((yblock+blk_y) < y_num_blocks) wgt_idx = 3; else wgt_idx = 6; } else { // right edge of block is outside picture in x direction if (pos.y < 0) wgt_idx = 2; else if ((yblock+blk_y) < y_num_blocks) wgt_idx = 5; else wgt_idx = 8; } block_mode = mv_data.Mode()[yblock][xblock]; TwoDArray<ValueType> *wt; if (split_mode == 0) //Block part of a MacroBlock { wt = &m_macro_block_weights[wgt_idx]; xb_incr = blocks_per_mb_row; } else if (split_mode == 1) //Block part of a SubBlock { wt = &m_sub_block_weights[wgt_idx]; xb_incr = blocks_per_sb_row; } else { wt = &m_block_weights[wgt_idx]; xb_incr = 1; } xincr = m_bparams.Xbsep() * xb_incr; mv1 = (*mv_array1)[yblock][xblock]; mv1.x >>= xscale_shift; mv1.y >>= yscale_shift; mv2 = (*mv_array2)[yblock][xblock]; mv2.x >>= xscale_shift; mv2.y >>= yscale_shift; CompensateBlock(pic_data, pos, pic_size, block_mode, dcarray[yblock][xblock], ref1up, mv1, ref2up, mv2, *wt); //Increment the block horizontal position pos.x += xincr; }//xblock // Update the pic data // Use only the first Ybsep rows since the remaining rows are // needed for the next row of blocks since we are using overlapped // blocks motion compensation if (m_add_or_sub == SUBTRACT) { int start_y = std::max(pic_data_out.FirstY() , pos.y) ; int end_y = std::min (pic_data_out.FirstY() + pos.y + m_bparams.Ybsep() , y_end_data); if (yblock == y_num_blocks - 1) { end_y = pic_data_out.LengthY(); if (end_y > y_end_data) end_y = y_end_data; } for ( int i = start_y, pos_y = 0; i < end_y; i++, pos_y++) { ValueType *pic_row = pic_data[pos_y]; ValueType *out_row = pic_data_out[i]; for ( int j =pic_data_out.FirstX(); j < x_end_data; ++j) { out_row[j] -= static_cast<ValueType>( (pic_row[j] + 32) >> 6 ); } // Okay, we've done all the actual blocks. Now if the picture is further padded // we need to set the padded values to zero beyond the last block in the row, // for all the picture lines in the block row. Need only do this when we're // subtracting. for (int j=pic_size.x; j<pic_data_out.LengthX() ; ++j ) { out_row[pic_data_out.FirstX()+j] = 0; } } } else // (m_add_or_sub == ADD) {
void MvDataCodec::DecodeDC( MvData& out_data ) { //begin with Y DC value ValueType val = 0; int bin = 1; bool bit; do { DecodeSymbol( bit , ChooseYDCContext( out_data , bin ) ); if ( !bit ) val++; bin++; } while ( !bit ); if (val != 0) { DecodeSymbol( bit , ChooseYDCSignContext( out_data ) ); if (!bit) val = -val; } out_data.DC( Y_COMP )[b_yp][b_xp] = val + DCPrediction( out_data.DC( Y_COMP ) , out_data.Mode()); if (m_cformat != Yonly) { //move onto U and V DC values val = 0; bin = 1; do { DecodeSymbol( bit , ChooseUDCContext( out_data , bin ) ); if (!bit) val++; bin++; } while (!bit); if (val != 0) { DecodeSymbol( bit , ChooseUDCSignContext ( out_data ) ); if (!bit) val = -val; } out_data.DC( U_COMP )[b_yp][b_xp] = val + DCPrediction( out_data.DC( U_COMP ) , out_data.Mode()); val = 0; bin = 1; do { DecodeSymbol( bit , ChooseVDCContext( out_data , bin ) ); if ( !bit ) val++; bin++; } while ( !bit ); if (val != 0) { DecodeSymbol( bit , ChooseVDCSignContext( out_data ) ); if ( !bit ) val = -val; } out_data.DC( V_COMP )[b_yp][b_xp] = val + DCPrediction( out_data.DC( V_COMP ) , out_data.Mode() ); } }
void MvDataCodec::DoWorkDecode( MvData& out_data, int num_bits) { int step,max; int pstep,pmax; int split_depth; bool common_ref; int xstart,ystart; for (mb_yp = 0,mb_tlb_y = 0; mb_yp < out_data.MBSplit().LengthY(); ++mb_yp,mb_tlb_y += 4) { for (mb_xp = 0,mb_tlb_x = 0; mb_xp < out_data.MBSplit().LengthX(); ++mb_xp,mb_tlb_x += 4) { //start with split mode DecodeMBSplit( out_data ); split_depth = out_data.MBSplit()[mb_yp][mb_xp]; step = 4 >> (split_depth); max = (1 << split_depth); //next do common_ref if(split_depth != 0) { DecodeMBCom( out_data ); pstep = step; pmax = max; } else { out_data.MBCommonMode()[mb_yp][mb_xp] = true; pstep = 4; pmax = 1; } common_ref = out_data.MBCommonMode()[mb_yp][mb_xp]; // do prediction modes for (b_yp = mb_tlb_y; b_yp < mb_tlb_y + 4; b_yp += pstep) { for (b_xp = mb_tlb_x; b_xp < mb_tlb_x + 4; b_xp += pstep) { DecodePredmode(out_data); // propagate throughout MB for (int y = b_yp; y < b_yp + pstep; y++) for (int x = b_xp; x < b_xp + pstep; x++) out_data.Mode()[y][x] = out_data.Mode()[b_yp][b_xp]; } } //now do all the block mvs in the mb for (int j = 0; j < max; ++j) { for (int i = 0; i < max; ++i) { xstart = b_xp = mb_tlb_x + i * step; ystart = b_yp = mb_tlb_y + j * step; if (out_data.Mode()[b_yp][b_xp] == REF1_ONLY || out_data.Mode()[b_yp][b_xp] == REF1AND2 ) DecodeMv1( out_data ); if (out_data.Mode()[b_yp][b_xp] == REF2_ONLY || out_data.Mode()[b_yp][b_xp] == REF1AND2 ) DecodeMv2( out_data ); if(out_data.Mode()[b_yp][b_xp] == INTRA) DecodeDC( out_data ); //propagate throughout MB for (b_yp = ystart; b_yp < ystart+step; b_yp++) { for (b_xp = xstart; b_xp < xstart+step; b_xp++) { out_data.Vectors(1)[b_yp][b_xp].x = out_data.Vectors(1)[ystart][xstart].x; out_data.Vectors(1)[b_yp][b_xp].y = out_data.Vectors(1)[ystart][xstart].y; out_data.Vectors(2)[b_yp][b_xp].x = out_data.Vectors(2)[ystart][xstart].x; out_data.Vectors(2)[b_yp][b_xp].y = out_data.Vectors(2)[ystart][xstart].y; out_data.DC( Y_COMP )[b_yp][b_xp] = out_data.DC( Y_COMP )[ystart][xstart]; out_data.DC( U_COMP )[b_yp][b_xp] = out_data.DC( U_COMP )[ystart][xstart]; out_data.DC( V_COMP )[b_yp][b_xp] = out_data.DC( V_COMP )[ystart][xstart]; }//b_xp }//b_yp }//i }//j }//mb_xp }//mb_yp }
void MvDataCodec::DoWorkCode( MvData& in_data ) { int step,max; int pstep,pmax; int split_depth; bool common_ref; MB_count = 0; for (mb_yp = 0, mb_tlb_y = 0; mb_yp < in_data.MBSplit().LengthY(); ++mb_yp, mb_tlb_y += 4) { for (mb_xp = 0,mb_tlb_x = 0; mb_xp < in_data.MBSplit().LengthX(); ++mb_xp,mb_tlb_x += 4) { //start with split mode CodeMBSplit(in_data); split_depth = in_data.MBSplit()[mb_yp][mb_xp]; step = 4 >> (split_depth); max = (1 << split_depth); //next do common_ref if(split_depth != 0) { CodeMBCom(in_data); pstep = step; pmax = max; } else { pstep = 4; pmax = 1; } common_ref = in_data.MBCommonMode()[mb_yp][mb_xp]; //do prediction modes for (b_yp = mb_tlb_y; b_yp < mb_tlb_y+4; b_yp += pstep) for (b_xp = mb_tlb_x; b_xp < mb_tlb_x+4; b_xp += pstep) CodePredmode(in_data); step = 4 >> (split_depth); //now do all the block mvs in the mb for (b_yp = mb_tlb_y; b_yp < mb_tlb_y+4; b_yp += step) { for (b_xp = mb_tlb_x; b_xp < mb_tlb_x+4; b_xp += step) { if (in_data.Mode()[b_yp][b_xp] == REF1_ONLY || in_data.Mode()[b_yp][b_xp] == REF1AND2 ) CodeMv1(in_data); if (in_data.Mode()[b_yp][b_xp] == REF2_ONLY || in_data.Mode()[b_yp][b_xp] == REF1AND2 ) CodeMv2(in_data); if(in_data.Mode()[b_yp][b_xp] == INTRA) CodeDC(in_data); }//b_xp }//b_yp //TODO: Update all contexts here? }//mb_xp }//mb_yp }
void MotionCompensator::CompensateComponent(Frame& picframe, const Frame &ref1frame, const Frame& ref2frame, const MvData& mv_data,const CompSort cs) { // Set up references to pictures and references PicArray& pic_data_out = picframe.Data( cs ); const PicArray& ref1up = ref1frame.UpData( cs ); const PicArray& ref2up = ref2frame.UpData( cs ); // Set up another picture which will contain the MC data, which // we'll add or subtract to pic_data_out TwoDArray<CalcValueType> pic_data(pic_data_out.LengthY(), pic_data_out.LengthX() , 0); // Factors to compensate for subsampling of chroma int xscale_factor = 1; int yscale_factor = 1; if ( cs != Y_COMP ) { if (m_cformat == format420) { xscale_factor = 2; yscale_factor = 2; } else if (m_cformat == format422) { xscale_factor = 2; yscale_factor = 1; } else if (m_cformat == format411) { xscale_factor = 4; yscale_factor = 1; } } // Reference to the relevant DC array const TwoDArray<ValueType>& dcarray = mv_data.DC( cs ); // Set up references to the vectors const int num_refs = picframe.GetFparams().Refs().size(); const MvArray* mv_array1; const MvArray* mv_array2; mv_array1 = &mv_data.Vectors(1); if (num_refs ==2 ) mv_array2 = &mv_data.Vectors(2); else mv_array2 = &mv_data.Vectors(1); ReConfig();//set all the weighting blocks up //Blocks are listed left to right, line by line. MVector mv1,mv2; PredMode block_mode; ValueType dc; //Coords of the top-left corner of a block ImageCoords pos; //Loop for each block in the output image. //The CompensateBlock function will use the image pointed to by ref1up //and add the compensated pixels to the image pointed to by pic_data. size_t wgt_idx; //Loop over all the block rows pos.y = -m_bparams.Yoffset(); for(int yblock = 0; yblock < m_cparams.YNumBlocks(); ++yblock) { pos.x = -m_bparams.Xoffset(); //loop over all the blocks in a row for(int xblock = 0 ; xblock < m_cparams.XNumBlocks(); ++xblock) { //Decide which weights to use. if((xblock != 0)&&(xblock < m_cparams.XNumBlocks() - 1)) { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 4; else if(yblock == 0) wgt_idx = 1; else wgt_idx= 7; } else if(xblock == 0) { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 3; else if(yblock == 0) wgt_idx = 0; else wgt_idx = 6; } else { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 5; else if(yblock == 0) wgt_idx = 2; else wgt_idx = 8; } block_mode = mv_data.Mode()[yblock][xblock]; mv1 = (*mv_array1)[yblock][xblock]; mv1.x /= xscale_factor; mv1.y /= yscale_factor; mv2 = (*mv_array2)[yblock][xblock]; mv2.x /= xscale_factor; mv2.y /= yscale_factor; dc = dcarray[yblock][xblock]<<2;// DC is only given 8 bits, // so need to shift to get 10-bit data if(block_mode == REF1_ONLY) { CompensateBlock(pic_data, ref1up, mv1, pos, m_block_weights[wgt_idx]); } else if (block_mode == REF2_ONLY) { CompensateBlock(pic_data, ref2up, mv2, pos, m_block_weights[wgt_idx]); } else if(block_mode == REF1AND2) { CompensateBlock(pic_data, ref1up, mv1, pos, m_half_block_weights[wgt_idx]); CompensateBlock(pic_data, ref2up, mv2, pos, m_half_block_weights[wgt_idx]); } else {//we have a DC block. DCBlock(pic_data, dc,pos, m_block_weights[wgt_idx]); } //Increment the block horizontal position pos.x += m_bparams.Xbsep(); }//xblock //Increment the block vertical position pos.y += m_bparams.Ybsep(); }//yblock if ( m_add_or_sub == SUBTRACT) { int x_end_data = std::min(pic_data.LastX(), m_cparams.XNumBlocks()*m_bparams.Xbsep() ); int y_end_data = std::min(pic_data.LastY(), m_cparams.YNumBlocks()*m_bparams.Ybsep() ); for ( int i =pic_data.FirstY(); i <= y_end_data; i++) { for ( int j =pic_data.FirstX(); j <= x_end_data; ++j) { pic_data_out[i][j] -= static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 ); } // Okay, we've done all the actual blocks. Now if the picture is further padded // we need to set the padded values to zero beyond the last block in the row, // for all the picture lines in the block row. Need only do this when we're // subtracting. for (int j=( m_cparams.XNumBlocks()*m_bparams.Xbsep() ); j<pic_data.LengthX() ; ++j ) { pic_data_out[i][j] = 0; } } // Finally, now we've done all the blocks, we must set all padded lines below // the last row equal to 0, if we're subtracting for ( int y=m_cparams.YNumBlocks()*m_bparams.Ybsep() ; y<pic_data.LengthY() ; ++y ) { for ( int x=0 ; x<pic_data.LengthX() ; ++x ) { pic_data_out[y][x] = 0; } } }