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; } }