frame_compress.cpp

00001 /* ***** BEGIN LICENSE BLOCK *****
00002 *
00003 * $Id: frame_compress.cpp,v 1.2 2005/01/30 05:11:41 gabest Exp $ $Name:  $
00004 *
00005 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006 *
00007 * The contents of this file are subject to the Mozilla Public License
00008 * Version 1.1 (the "License"); you may not use this file except in compliance
00009 * with the License. You may obtain a copy of the License at
00010 * http://www.mozilla.org/MPL/
00011 *
00012 * Software distributed under the License is distributed on an "AS IS" basis,
00013 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
00014 * the specific language governing rights and limitations under the License.
00015 *
00016 * The Original Code is BBC Research and Development code.
00017 *
00018 * The Initial Developer of the Original Code is the British Broadcasting
00019 * Corporation.
00020 * Portions created by the Initial Developer are Copyright (C) 2004.
00021 * All Rights Reserved.
00022 *
00023 * Contributor(s): Thomas Davies (Original Author), 
00024 *                 Scott R Ladd,
00025 *                 Chris Bowley,
00026 *                 Anuradha Suraparaju
00027 *
00028 * Alternatively, the contents of this file may be used under the terms of
00029 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
00030 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
00031 * the GPL or the LGPL are applicable instead of those above. If you wish to
00032 * allow use of your version of this file only under the terms of the either
00033 * the GPL or LGPL and not to allow others to use your version of this file
00034 * under the MPL, indicate your decision by deleting the provisions above
00035 * and replace them with the notice and other provisions required by the GPL
00036 * or LGPL. If you do not delete the provisions above, a recipient may use
00037 * your version of this file under the terms of any one of the MPL, the GPL
00038 * or the LGPL.
00039 * ***** END LICENSE BLOCK ***** */
00040 
00041 //Compression of frames//
00043 
00044 #include <libdirac_encoder/frame_compress.h>
00045 #include <libdirac_encoder/comp_compress.h>
00046 #include <libdirac_common/mot_comp.h>
00047 #include <libdirac_motionest/motion_estimate.h>
00048 #include <libdirac_common/mv_codec.h>
00049 #include <libdirac_common/golomb.h>
00050 #include <libdirac_common/bit_manager.h>
00051 #include <libdirac_common/dirac_assertions.h>
00052 using namespace dirac;
00053 
00054 #include <iostream>
00055 #include <sstream>
00056 
00057 FrameCompressor::FrameCompressor( EncoderParams& encp ) :
00058     m_encparams(encp),
00059     m_me_data(0),
00060     m_skipped(false),
00061     m_use_global(false),
00062     m_use_block_mv(true),
00063     m_global_pred_mode(REF1_ONLY),
00064     m_medata_avail(false)
00065 {
00066 }
00067 
00068 FrameCompressor::~FrameCompressor()
00069 {
00070     if (m_me_data)
00071         delete m_me_data;
00072 }
00073 
00074 void FrameCompressor::Compress( FrameBuffer& my_buffer, const FrameBuffer& orig_buffer , int fnum )
00075 {
00076     FrameOutputManager& foutput = m_encparams.BitsOut().FrameOutput();
00077 
00078     Frame& my_frame = my_buffer.GetFrame( fnum );
00079     const FrameParams& fparams = my_frame.GetFparams();
00080     const FrameSort& fsort = fparams.FSort();
00081     const ChromaFormat cformat = fparams.CFormat();
00082 
00083     // number of bits written, without byte alignment
00084     unsigned int num_mv_bits;
00085     m_medata_avail = false;
00086 
00087     CompCompressor my_compcoder(m_encparams , fparams );
00088 
00089     if (m_me_data)
00090     {
00091         delete m_me_data;
00092         m_me_data = 0;
00093     }
00094 
00095     if ( fsort != I_frame )
00096     {
00097 
00098         m_me_data = new MEData( m_encparams.XNumMB() , m_encparams.YNumMB());
00099 
00100         // Motion estimate first
00101         MotionEstimator my_motEst( m_encparams );
00102         bool is_a_cut = my_motEst.DoME( orig_buffer , fnum , *m_me_data );
00103 
00104         // If we have a cut, and an L1 frame, then turn into an I-frame
00105         if ( is_a_cut )
00106         {
00107             my_frame.SetFrameSort( I_frame );
00108             if ( m_encparams.Verbose() )
00109                 std::cerr<<std::endl<<"Cut detected and I-frame inserted!";
00110         }
00111 
00112     }
00113 
00114 
00115     // Write the frame header. We wait until after motion estimation, since
00116     // this allows us to do cut-detection and (possibly) to decide whether
00117     // or not to skip a frame before actually encoding anything. However we
00118     // can do this at any point prior to actually writing any frame data.
00119     WriteFrameHeader( my_frame.GetFparams() );
00120 
00121 
00122     if ( !m_skipped )
00123     {    // If not skipped we continue with the coding ...
00124 
00125         if ( fsort != I_frame)
00126         {
00127              // Code the MV data
00128 
00129             // If we're using global motion parameters, code them
00130             if (m_use_global)
00131             {
00132                 /*
00133                     Code the global motion parameters
00134                     TBC ....
00135                 */
00136             }
00137 
00138             // If we're using block motion vectors, code them
00139             if ( m_use_block_mv )
00140             {
00141                 MvDataCodec my_mv_coder( &( foutput.MVOutput().Data() ) , 50 , cformat);
00142 
00143                 my_mv_coder.InitContexts();//may not be necessary
00144                 num_mv_bits = my_mv_coder.Compress( *m_me_data );            
00145 
00146                 UnsignedGolombCode( foutput.MVOutput().Header() , num_mv_bits);
00147             }
00148 
00149              // Then motion compensate
00150 
00151             MotionCompensator mycomp( m_encparams , SUBTRACT);
00152             mycomp.CompensateFrame( my_buffer , fnum , *m_me_data );
00153 
00154         }//?fsort
00155 
00156         //code component data
00157         my_compcoder.Compress( my_buffer.GetComponent( fnum , Y_COMP) );
00158         if (cformat != Yonly)
00159         {
00160             my_compcoder.Compress( my_buffer.GetComponent( fnum , U_COMP) );
00161             my_compcoder.Compress( my_buffer.GetComponent( fnum , V_COMP) );
00162         }
00163 
00164         //motion compensate again if necessary
00165         if ( fsort != I_frame )
00166         {
00167             MotionCompensator mycomp( m_encparams , ADD);
00168             mycomp.CompensateFrame( my_buffer , fnum , *m_me_data );
00169             // Set me data available flag
00170             m_medata_avail = true;
00171         }//?fsort
00172 
00173          //finally clip the data to keep it in range
00174         my_buffer.GetFrame(fnum).Clip();
00175 
00176     }//?m_skipped
00177 }
00178 
00179 void FrameCompressor::WriteFrameHeader( const FrameParams& fparams )
00180 {
00181     BasicOutputManager& frame_header_op = m_encparams.BitsOut().FrameOutput().HeaderOutput();
00182 
00183     // Write the frame start code
00184     unsigned char frame_start[5] = { START_CODE_PREFIX_BYTE0, 
00185                                      START_CODE_PREFIX_BYTE1, 
00186                                      START_CODE_PREFIX_BYTE2, 
00187                                      START_CODE_PREFIX_BYTE3, 
00188                                      IFRAME_START_CODE };
00189     switch(fparams.FSort())
00190     {
00191     case I_frame:
00192         frame_start[4] = IFRAME_START_CODE;
00193         break;
00194 
00195     case L1_frame:
00196         frame_start[4] = L1FRAME_START_CODE;
00197         break;
00198 
00199     case L2_frame:
00200         frame_start[4] = L2FRAME_START_CODE;
00201          break;
00202 
00203     default:
00204 //         dirac_ASSERTM (false, "Frame type is I_frame or L1_frame or L2_frame");
00205          break;
00206     }
00207     frame_header_op.OutputBytes((char *)frame_start, 5);
00208 
00209     // Write the frame number
00210     UnsignedGolombCode(frame_header_op , fparams.FrameNum());
00211 
00212     //write whether the frame is m_skipped or not
00213     frame_header_op.OutputBit( m_skipped );
00214 
00215     if (!m_skipped)
00216     {// If we're not m_skipped, then we write the rest of the metadata
00217 
00218         // Write the expiry time relative to the frame number 
00219         UnsignedGolombCode( frame_header_op , fparams.ExpiryTime() );
00220 
00221         // Write the frame sort
00222         UnsignedGolombCode( frame_header_op , (unsigned int) fparams.FSort() );        
00223         if (fparams.FSort() != I_frame)
00224         {        
00225             // If not an I-frame, write how many references there are        
00226             UnsignedGolombCode( frame_header_op , (unsigned int) fparams.Refs().size() );
00227 
00228             // For each reference, write the reference number relative to the frame number
00229             for ( size_t i=0 ; i<fparams.Refs().size() ; ++i )
00230                 GolombCode( frame_header_op , fparams.Refs()[i]-fparams.FrameNum() );
00231 
00232             // Indicate whether or not there is global motion vector data
00233             frame_header_op.OutputBit( m_use_global );
00234 
00235             // Indicate whether or not there is block motion vector data
00236             frame_header_op.OutputBit( m_use_block_mv );
00237 
00238             // If there is global but no block motion vector data, indicate the 
00239             // prediction mode to use for the whole frame
00240             if ( m_use_global && !m_use_block_mv )
00241             {
00242                 UnsignedGolombCode( frame_header_op , (unsigned int) m_global_pred_mode );
00243             }
00244         }
00245 
00246     }// ?m_skipped
00247 }
00248 
00249 const MEData* FrameCompressor::GetMEData() const
00250 {
00251     TESTM (m_me_data != NULL, "m_medata allocated");
00252     TESTM (m_medata_avail == true, "ME Data available");
00253 
00254     return m_me_data;
00255 }

Generated on Tue Dec 13 14:47:16 2005 for guliverkli by  doxygen 1.4.5