//Called to perform motion compensated addition/subtraction on an entire frame. void MotionCompensator::CompensateFrame(FrameBuffer& my_buffer,int fnum,const MvData& mv_data) { int ref1_idx,ref2_idx; Frame& my_frame=my_buffer.GetFrame(fnum); const FrameSort& fsort=my_frame.GetFparams().FSort(); m_cformat = my_frame.GetFparams().CFormat(); if (fsort!=I_frame) {//we can motion compensate const vector<int>& refs=my_frame.GetFparams().Refs(); if (refs.size()>0) { //extract the references ref1_idx=refs[0]; if (refs.size()>1) ref2_idx=refs[1]; else ref2_idx=refs[0]; const Frame& ref1frame=my_buffer.GetFrame(ref1_idx); const Frame& ref2frame=my_buffer.GetFrame(ref2_idx); luma_or_chroma = true; //now do all the components CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , Y_COMP); if ( m_cformat != Yonly ) { luma_or_chroma = false; CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , U_COMP); CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , V_COMP); } } } }
void MotionEstimator::DoME(const FrameBuffer& my_buffer, int frame_num, MEData& me_data) { const FrameParams& fparams = my_buffer.GetFrame(frame_num).GetFparams(); // Step 1. //Initial search gives vectors for each reference accurate to 1 pixel PixelMatcher pix_match( m_encparams ); pix_match.DoSearch( my_buffer , frame_num , me_data); float lambda; // Get the references const std::vector<int>& refs = my_buffer.GetFrame(frame_num).GetFparams().Refs(); const int num_refs = refs.size(); if ( fparams.IsBFrame()) lambda = m_encparams.L2MELambda(); else lambda = m_encparams.L1MELambda(); // Set up the lambda to be used me_data.SetLambdaMap( num_refs , lambda ); MVPrecisionType orig_prec = m_encparams.MVPrecision(); // Step 2. // Pixel accurate vectors are then refined to sub-pixel accuracy if (orig_prec != MV_PRECISION_PIXEL) { SubpelRefine pelrefine( m_encparams ); pelrefine.DoSubpel( my_buffer , frame_num , me_data ); } else { // FIXME: HACK HACK // Mutiplying the motion vectors by 2 and setting MV precision to // HALF_PIXEL to implement pixel accurate motion estimate MvArray &mv_arr1 = me_data.Vectors(1); for (int j = 0; j < mv_arr1.LengthY(); ++j) { for (int i = 0; i < mv_arr1.LengthX(); ++i) mv_arr1[j][i] = mv_arr1[j][i] << 1; } if (num_refs > 1) { MvArray &mv_arr2 = me_data.Vectors(2); for (int j = 0; j < mv_arr2.LengthY(); ++j) { for (int i = 0; i < mv_arr2.LengthX(); ++i) mv_arr2[j][i] = mv_arr2[j][i] << 1; } } m_encparams.SetMVPrecision(MV_PRECISION_HALF_PIXEL); } // Step3. // We now have to decide how each macroblock should be split // and which references should be used, and so on. ModeDecider my_mode_dec( m_encparams ); my_mode_dec.DoModeDecn( my_buffer , frame_num , me_data ); if (orig_prec == MV_PRECISION_PIXEL) { // FIXME: HACK HACK // Divide the motion vectors by 2 to convert back to pixel // accurate motion vectors and reset MV precision to // PIXEL accuracy MvArray &mv_arr1 = me_data.Vectors(1); for (int j = 0; j < mv_arr1.LengthY(); ++j) { for (int i = 0; i < mv_arr1.LengthX(); ++i) mv_arr1[j][i] = mv_arr1[j][i] >> 1; } if (num_refs > 1) { MvArray &mv_arr2 = me_data.Vectors(2); for (int j = 0; j < mv_arr2.LengthY(); ++j) { for (int i = 0; i < mv_arr2.LengthX(); ++i) mv_arr2[j][i] = mv_arr2[j][i]>>1; } }
//Called to perform motion compensated addition/subtraction on an entire frame. void MotionCompensator::CompensateFrame( const AddOrSub direction , FrameBuffer& my_buffer , int fnum , const MvData& mv_data) { m_add_or_sub = direction; int ref1_idx,ref2_idx; Frame& my_frame=my_buffer.GetFrame(fnum); const FrameSort& fsort=my_frame.GetFparams().FSort(); m_cformat = my_frame.GetFparams().CFormat(); if (fsort.IsInter()) { //we can motion compensate const std::vector<int>& refs=my_frame.GetFparams().Refs(); if (refs.size()>0) { //extract the references ref1_idx = refs[0]; if ( refs.size()>1 ) ref2_idx = refs[1]; else ref2_idx = refs[0]; const Frame& ref1frame = my_buffer.GetFrame(ref1_idx); const Frame& ref2frame = refs.size() > 0 ? my_buffer.GetFrame(ref2_idx) : ref1frame; // Now check that references are marked correctly if ( !ref1frame.GetFparams().FSort().IsRef() ) { std::cout<<std::endl<<"WARNING! Reference frame (number "<<ref1_idx; std::cout<<") being used is not marked as a reference. Incorrect output is likely."; } if ( ref1frame.GetFparams().FrameNum() != ref1_idx) { std::cout<<std::endl<<"WARNING! Reference frame (number "<<ref1_idx; std::cout<<") not available in buffer. Incorrect output is likely."; } if ( refs.size()>1 ) { if ( !ref2frame.GetFparams().FSort().IsRef() ) { std::cout<<std::endl<<"WARNING! Reference frame (number "; std::cout<<ref2_idx<<") being used is not marked as a reference. Incorrect output is likely."; } if ( ref2frame.GetFparams().FrameNum() != ref2_idx) { std::cout<<std::endl<<"WARNING! Reference frame (number "<<ref2_idx; std::cout<<") not available in buffer. Incorrect output is likely."; } } luma_or_chroma = true; //now do all the components CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , Y_COMP); luma_or_chroma = false; CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , U_COMP); CompensateComponent( my_frame , ref1frame , ref2frame , mv_data , V_COMP); } } }
void FrameCompressor::Compress( FrameBuffer& my_buffer, const FrameBuffer& orig_buffer , int fnum ) { FrameOutputManager& foutput = m_encparams.BitsOut().FrameOutput(); Frame& my_frame = my_buffer.GetFrame( fnum ); const FrameParams& fparams = my_frame.GetFparams(); const FrameSort& fsort = fparams.FSort(); const ChromaFormat cformat = fparams.CFormat(); // number of bits written, without byte alignment unsigned int num_mv_bits; m_medata_avail = false; CompCompressor my_compcoder(m_encparams , fparams ); if (m_me_data) { delete m_me_data; m_me_data = 0; } if ( fsort != I_frame ) { m_me_data = new MEData( m_encparams.XNumMB() , m_encparams.YNumMB()); // Motion estimate first MotionEstimator my_motEst( m_encparams ); bool is_a_cut = my_motEst.DoME( orig_buffer , fnum , *m_me_data ); // If we have a cut, and an L1 frame, then turn into an I-frame if ( is_a_cut ) { my_frame.SetFrameSort( I_frame ); if ( m_encparams.Verbose() ) std::cerr<<std::endl<<"Cut detected and I-frame inserted!"; } } // Write the frame header. We wait until after motion estimation, since // this allows us to do cut-detection and (possibly) to decide whether // or not to skip a frame before actually encoding anything. However we // can do this at any point prior to actually writing any frame data. WriteFrameHeader( my_frame.GetFparams() ); if ( !m_skipped ) { // If not skipped we continue with the coding ... if ( fsort != I_frame) { // Code the MV data // If we're using global motion parameters, code them if (m_use_global) { /* Code the global motion parameters TBC .... */ } // If we're using block motion vectors, code them if ( m_use_block_mv ) { MvDataCodec my_mv_coder( &( foutput.MVOutput().Data() ) , 50 , cformat); my_mv_coder.InitContexts();//may not be necessary num_mv_bits = my_mv_coder.Compress( *m_me_data ); UnsignedGolombCode( foutput.MVOutput().Header() , num_mv_bits); } // Then motion compensate MotionCompensator mycomp( m_encparams , SUBTRACT); mycomp.CompensateFrame( my_buffer , fnum , *m_me_data ); }//?fsort //code component data my_compcoder.Compress( my_buffer.GetComponent( fnum , Y_COMP) ); if (cformat != Yonly) { my_compcoder.Compress( my_buffer.GetComponent( fnum , U_COMP) ); my_compcoder.Compress( my_buffer.GetComponent( fnum , V_COMP) ); } //motion compensate again if necessary if ( fsort != I_frame ) { MotionCompensator mycomp( m_encparams , ADD); mycomp.CompensateFrame( my_buffer , fnum , *m_me_data ); // Set me data available flag m_medata_avail = true; }//?fsort //finally clip the data to keep it in range my_buffer.GetFrame(fnum).Clip(); }//?m_skipped }
void ModeDecider::DoModeDecn(const FrameBuffer& my_buffer, int frame_num, MEData& me_data) { // We've got 'raw' block motion vectors for up to two reference frames. Now we want // to make a decision as to mode. In this initial implementation, this is bottom-up // i.e. find mvs for MBs and sub-MBs and see whether it's worthwhile merging. int ref1,ref2; // Initialise // //////////////// fsort = my_buffer.GetFrame(frame_num).GetFparams().FSort(); if (fsort.IsInter()) { // Extract the references const vector<int>& refs = my_buffer.GetFrame(frame_num).GetFparams().Refs(); num_refs = refs.size(); ref1 = refs[0]; // The picture we're doing estimation from m_pic_data = &(my_buffer.GetComponent( frame_num , Y_COMP)); // Set up the hierarchy of motion vector data objects m_me_data_set[0] = new MEData( m_encparams.XNumMB() , m_encparams.YNumMB() , m_encparams.XNumBlocks()/4 , m_encparams.YNumBlocks()/4, num_refs ); m_me_data_set[1] = new MEData( m_encparams.XNumMB() , m_encparams.YNumMB() , m_encparams.XNumBlocks()/2 , m_encparams.YNumBlocks()/2, num_refs ); m_me_data_set[2] = &me_data; // Set up the lambdas to use per block m_me_data_set[0]->SetLambdaMap( 0 , me_data.LambdaMap() , 1.0/m_level_factor[0] ); m_me_data_set[1]->SetLambdaMap( 1 , me_data.LambdaMap() , 1.0/m_level_factor[1] ); // Set up the reference pictures m_ref1_updata = &(my_buffer.GetUpComponent( ref1 , Y_COMP)); if (num_refs>1) { ref2 = refs[1]; m_ref2_updata = &(my_buffer.GetUpComponent( ref2 , Y_COMP)); // Create an object for computing bi-directional prediction calculations if ( m_encparams.MVPrecision()==MV_PRECISION_EIGHTH_PIXEL ) m_bicheckdiff = new BiBlockEighthPel( *m_ref1_updata , *m_ref2_updata , *m_pic_data ); else if ( m_encparams.MVPrecision()==MV_PRECISION_QUARTER_PIXEL ) m_bicheckdiff = new BiBlockQuarterPel( *m_ref1_updata , *m_ref2_updata , *m_pic_data ); else m_bicheckdiff = new BiBlockHalfPel( *m_ref1_updata , *m_ref2_updata , *m_pic_data ); } else { ref2 = ref1; } // Create an object for doing intra calculations m_intradiff = new IntraBlockDiff( *m_pic_data ); // Loop over all the macroblocks, doing the work // /////////////////////////////////////////////////// for (m_ymb_loc=0 ; m_ymb_loc<m_encparams.YNumMB() ; ++m_ymb_loc ) { for (m_xmb_loc=0 ; m_xmb_loc<m_encparams.XNumMB(); ++m_xmb_loc ) { DoMBDecn(); }//m_xmb_loc }//m_ymb_loc delete m_intradiff; if (num_refs>1) delete m_bicheckdiff; } }