seq_compress.cpp

00001 /* ***** BEGIN LICENSE BLOCK *****
00002 *
00003 * $Id: seq_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 *                 Anuradha Suraparaju
00026 *
00027 * Alternatively, the contents of this file may be used under the terms of
00028 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
00029 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
00030 * the GPL or the LGPL are applicable instead of those above. If you wish to
00031 * allow use of your version of this file only under the terms of the either
00032 * the GPL or LGPL and not to allow others to use your version of this file
00033 * under the MPL, indicate your decision by deleting the provisions above
00034 * and replace them with the notice and other provisions required by the GPL
00035 * or LGPL. If you do not delete the provisions above, a recipient may use
00036 * your version of this file under the terms of any one of the MPL, the GPL
00037 * or the LGPL.
00038 * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include <libdirac_encoder/seq_compress.h>
00042 #include <libdirac_common/dirac_assertions.h>
00043 #include <libdirac_common/golomb.h>
00044 using namespace dirac;
00045 
00046 SequenceCompressor::SequenceCompressor( StreamPicInput* pin , 
00047                                         std::ostream* outfile ,
00048                                         EncoderParams& encp
00049                                         ): 
00050     m_all_done(false),
00051     m_just_finished(true),
00052     m_encparams(encp),
00053     m_pic_in(pin),
00054     m_current_display_fnum(-1),
00055     m_current_code_fnum(0),
00056     m_show_fnum(-1),m_last_frame_read(-1), 
00057     m_delay(1),
00058     m_qmonitor( m_encparams , m_pic_in->GetSeqParams() ),
00059     m_fcoder( m_encparams )
00060 {
00061     // Set up the compression of the sequence
00062 
00063     const SeqParams& sparams=m_pic_in->GetSeqParams();
00064 
00065     //TBD: put into the constructor for EncoderParams
00066     m_encparams.SetEntropyFactors( new EntropyCorrector(4) );
00067     m_encparams.SetBitsOut( new SequenceOutputManager( outfile ) );
00068     WriteStreamHeader();
00069 
00070     //We have to set up the block parameters and file padding. This needs to take into
00071     //account both blocks for motion compensation and also wavelet transforms
00072 
00073     //Amount of horizontal padding for Y,U and V components
00074     int xpad_luma,xpad_chroma;
00075 
00076     //Amount of vertical padding for Y,U and V components
00077     int ypad_luma,ypad_chroma;
00078 
00079     //scaling factors for chroma based on chroma format
00080     int x_chroma_fac,y_chroma_fac;    
00081 
00082     //First, we need to have sufficient padding to take account of the blocksizes.
00083     //It's sufficient to check for chroma
00084 
00085     
00086     if (sparams.CFormat() == format411)
00087     {
00088         x_chroma_fac = 4; 
00089         y_chroma_fac = 1;
00090     }
00091     else if (sparams.CFormat()==format420)
00092     {
00093         x_chroma_fac = 2;
00094         y_chroma_fac = 2;
00095     }
00096     else if (sparams.CFormat() == format422)
00097     {
00098         x_chroma_fac = 2;
00099         y_chroma_fac = 1;
00100     }
00101     else
00102     {
00103         x_chroma_fac = 1;
00104         y_chroma_fac = 1;
00105     }
00106 
00107     int xl_chroma = sparams.Xl() / x_chroma_fac;
00108     int yl_chroma = sparams.Yl() / y_chroma_fac;
00109 
00110     // Make sure we have enough macroblocks to cover the pictures
00111     m_encparams.SetXNumMB( xl_chroma/m_encparams.ChromaBParams(0).Xbsep() );
00112     m_encparams.SetYNumMB( yl_chroma/m_encparams.ChromaBParams(0).Ybsep() );
00113     if ( m_encparams.XNumMB() * m_encparams.ChromaBParams(0).Xbsep() < xl_chroma )
00114     {
00115         m_encparams.SetXNumMB( m_encparams.XNumMB() + 1 );
00116         xpad_chroma = m_encparams.XNumMB()*m_encparams.ChromaBParams(0).Xbsep()-xl_chroma;
00117     }
00118     else
00119         xpad_chroma = 0;
00120 
00121     if ( m_encparams.YNumMB() * m_encparams.ChromaBParams(0).Ybsep() < yl_chroma )
00122     {
00123         m_encparams.SetYNumMB( m_encparams.YNumMB() + 1 );
00124         ypad_chroma = m_encparams.YNumMB() * m_encparams.ChromaBParams(0).Ybsep() - yl_chroma;
00125     }
00126     else
00127         ypad_chroma = 0;
00128 
00129     // Now we have an integral number of macroblocks in a picture and we set the number of blocks
00130     m_encparams.SetXNumBlocks( 4 * m_encparams.XNumMB() );
00131     m_encparams.SetYNumBlocks( 4 * m_encparams.YNumMB() );
00132 
00133     // Next we work out the additional padding due to the wavelet transform
00134     // For the moment, we'll fix the transform depth to be 4, so we need divisibility by 16.
00135     // In the future we'll want arbitrary transform depths. It's sufficient to check for
00136     // chroma only
00137 
00138     int xpad_len = xl_chroma+xpad_chroma;
00139     int ypad_len = yl_chroma+ypad_chroma;
00140     if ( xpad_len%16 != 0 )
00141         xpad_chroma = ( (xpad_len/16)+1 ) *16 - xl_chroma;
00142     if ( ypad_len%16 != 0 )
00143         ypad_chroma = ( (ypad_len/16)+1 ) * 16 - yl_chroma;
00144 
00145     xpad_luma = xpad_chroma * x_chroma_fac;
00146     ypad_luma = ypad_chroma * y_chroma_fac;
00147 
00148 
00149     //Set the resulting padding values
00150     m_pic_in->SetPadding(xpad_luma,ypad_luma);
00151 
00152     // Set up the frame buffers with the PADDED picture sizes
00153     m_fbuffer = new FrameBuffer( sparams.CFormat() , m_encparams.NumL1() , m_encparams.L1Sep() , 
00154             sparams.Xl() + xpad_luma , sparams.Yl() + ypad_luma );
00155 
00156     m_origbuffer = new FrameBuffer( sparams.CFormat() , m_encparams.NumL1() , m_encparams.L1Sep() , 
00157             sparams.Xl() + xpad_luma , sparams.Yl() + ypad_luma );
00158 }
00159 
00160 SequenceCompressor::~SequenceCompressor()
00161 {
00162 
00163     if ( m_encparams.Verbose())
00164         MakeSequenceReport();
00165 
00166     //TBD: put into the destructor for EncoderParams 
00167     delete &m_encparams.BitsOut();
00168     delete &m_encparams.EntropyFactors();
00169 
00170     delete m_fbuffer;
00171     delete m_origbuffer;
00172 }
00173 
00174 bool SequenceCompressor::LoadNextFrame()
00175 {
00176     m_fbuffer->PushFrame( m_pic_in , m_last_frame_read+1 );
00177 
00178     if ( m_pic_in->End() )
00179     {
00180         m_all_done = true;
00181         return false;
00182     }
00183     m_last_frame_read++;
00184     m_origbuffer->PushFrame( m_fbuffer->GetFrame( m_last_frame_read ) );
00185     return true;
00186 }
00187 
00188 Frame& SequenceCompressor::CompressNextFrame()
00189 {
00190 
00191     // This function codes the next frame in coding order and returns the next frame in display order
00192     // In general these will differ, and because of re-ordering there is a m_delay which needs to be imposed.
00193     // This creates problems at the start and at the end of the sequence which must be dealt with.
00194     // At the start we just keep outputting frame 0. At the end you will need to loop for longer to get all
00195     // the frames out. It's up to the calling function to do something with the decoded frames as they
00196     // come out - write them to screen or to file, or whatever. TJD 13Feb04.
00197 
00198     // current_fnum is the number of the current frame being coded in display order
00199     // m_current_code_fnum is the number of the current frame in coding order. This function increments
00200     // m_current_code_fnum by 1 each time and works out what the number is in display order.
00201     // m_show_fnum is the index of the frame number that can be shown when current_fnum has been coded.
00202     // Var m_delay is the m_delay caused by reordering (as distinct from buffering)
00203 
00204     TESTM (m_last_frame_read >= 0, "Data loaded before calling CompressNextFrame");
00205     m_current_display_fnum = CodedToDisplay( m_current_code_fnum );
00206 
00207     // If we're not at the beginning, clean the buffer
00208     if ( m_current_code_fnum != 0 )
00209     {
00210         m_fbuffer->Clean( m_show_fnum );
00211         m_origbuffer->Clean( m_show_fnum );
00212     }
00213 
00214     m_show_fnum = std::max( m_current_code_fnum - m_delay , 0 );
00215 
00216     bool can_encode = false;
00217 
00218     if (m_last_frame_read >= m_current_display_fnum )
00219         can_encode = true;
00220 
00221     if ( can_encode )
00222     {   // We haven't coded everything, so compress the next frame
00223 
00224         // True if we need to recode
00225         bool recode = false;
00226 
00227         if ( m_encparams.Verbose() )
00228         {
00229              std::cerr<<std::endl<<std::endl<<"Compressing frame "<<m_current_code_fnum<<", ";
00230             std::cerr<<m_current_display_fnum<<" in display order";
00231         }
00232  
00233         // A count of how many times we've recoded
00234         int count = 0;
00235         int max_count = 3;
00236 
00237 
00238         do
00239         {
00240       
00241             // Compress the frame//
00243 
00244             m_fcoder.Compress( *m_fbuffer , *m_origbuffer , m_current_display_fnum );
00245 
00246             // Adjust the Lagrangian parameters and check if we need to re-do the frame
00247             recode = m_qmonitor.UpdateModel( m_fbuffer->GetFrame( m_current_display_fnum ) , 
00248                                              m_origbuffer->GetFrame( m_current_display_fnum ) , count );
00249 
00250             ++count;
00251 
00252             if ( recode && count<max_count )
00253             {
00254                 if ( m_encparams.Verbose() )
00255                     std::cerr<<std::endl<<"Recoding!";
00256 
00257                 // Copy the original data back in
00258                 m_fbuffer->GetFrame( m_current_display_fnum ) = m_origbuffer->GetFrame( m_current_display_fnum );
00259 
00260                 // Reset the output
00261                 m_encparams.BitsOut().ResetFrame();
00262             }
00263 
00264         }
00265         while ( recode && count <max_count );
00266 
00267        // Finish by writing the compressed data out to file ...
00268        m_encparams.BitsOut().WriteFrameData();
00269 
00270        if ( m_encparams.Verbose() )
00271        {
00272            MakeFrameReport();
00273        }
00274     
00275         // Increment our position
00276         m_current_code_fnum++;
00277 
00278     }
00279 
00280     // Return the latest frame that can be shown
00281     return m_fbuffer->GetFrame(m_show_fnum);
00282 }
00283 
00284 const Frame *SequenceCompressor::GetFrameEncoded()
00285 {
00286     if (m_current_display_fnum >= 0)
00287         return &m_fbuffer->GetFrame( m_current_display_fnum );
00288 
00289     return 0;
00290 }
00291 
00292 const MEData *SequenceCompressor::GetMEData()
00293 {
00294     if ( m_fcoder.IsMEDataAvail())
00295         return m_fcoder.GetMEData();
00296 
00297     return 0;
00298 }
00299 void SequenceCompressor::EndSequence()
00300 {
00301     if (m_just_finished)
00302     {
00303         //Write end of sequence
00304         unsigned char seq_end[5] = { START_CODE_PREFIX_BYTE0, 
00305                                      START_CODE_PREFIX_BYTE1, 
00306                                      START_CODE_PREFIX_BYTE2, 
00307                                      START_CODE_PREFIX_BYTE3, 
00308                                      SEQ_END_CODE };
00309         m_encparams.BitsOut().TrailerOutput().OutputBytes((char *)seq_end, 5);
00310         m_encparams.BitsOut().WriteSeqTrailerToFile();
00311         m_just_finished = false;
00312         m_all_done = true;
00313     }
00314 }
00315 
00316 
00317 
00318 void SequenceCompressor::MakeSequenceReport()
00319 {
00320 
00321     std::cerr<<"Total bits for sequence="<<m_encparams.BitsOut().SequenceBytes() * 8;
00322     std::cerr<<" ( "<<m_encparams.BitsOut().SequenceHeadBytes() * 8<<" header )";
00323     
00324     std::cerr<<std::endl<<"Of these: "<<std::endl<<std::endl;
00325     std::cerr<<m_encparams.BitsOut().ComponentBytes( Y_COMP ) * 8<<" were Y, ";
00326     std::cerr<<std::endl<<m_encparams.BitsOut().ComponentBytes( U_COMP ) * 8<<" were U, ";
00327     std::cerr<<std::endl<<m_encparams.BitsOut().ComponentBytes( V_COMP ) * 8<<" were V, and ";
00328     std::cerr<<std::endl<<m_encparams.BitsOut().MVBytes() * 8<<" were motion vector data.";
00329 
00330     std::cerr<<std::endl<<std::endl<<"The resulting bit-rate at "<<m_pic_in->GetSeqParams().FrameRate()<<"Hz is ";
00331 
00332     std::cerr<<m_encparams.BitsOut().SequenceBytes() * 8 * ( m_pic_in->GetSeqParams().FrameRate() )
00333                                                          /  m_current_code_fnum <<" bits/sec.";
00334     std::cerr<<std::endl;
00335 
00336 }
00337 
00338 void SequenceCompressor::MakeFrameReport()
00339 {
00340     // Write out to screen a report of the number of bits written
00341     const FrameOutputManager& foutput = m_encparams.BitsOut().FrameOutput();
00342 
00343     unsigned int unit_bits = foutput.MVBytes() * 8;            
00344     unsigned int unit_head_bits = foutput.MVHeadBytes() * 8;
00345 
00346     std::cerr<<std::endl<<"Number of MV bits="<<unit_bits;
00347     std::cerr<<" ( "<<unit_head_bits<<" header bits)";
00348 
00349     unit_bits = foutput.ComponentBytes( Y_COMP ) * 8;
00350     unit_head_bits = foutput.ComponentHeadBytes( Y_COMP ) * 8;
00351 
00352     std::cerr<<std::endl<<"Number of bits for Y="<<unit_bits;
00353     std::cerr<<" ( "<<unit_head_bits<<" header bits)";
00354 
00355     unit_bits = foutput.ComponentBytes( U_COMP ) * 8;
00356     unit_head_bits = foutput.ComponentHeadBytes( U_COMP ) * 8;
00357 
00358     std::cerr<<std::endl<<"Number of bits for U="<<unit_bits;
00359     std::cerr<<" ( "<<unit_head_bits<<" header bits)";
00360 
00361     unit_bits = foutput.ComponentBytes( V_COMP ) * 8;
00362     unit_head_bits = foutput.ComponentHeadBytes( V_COMP ) * 8;
00363 
00364     std::cerr<<std::endl<<"Number of bits for V="<<unit_bits;
00365     std::cerr<<" ( "<<unit_head_bits<<" header bits)";
00366 
00367     unit_bits = foutput.FrameBytes() * 8;
00368     unit_head_bits = foutput.FrameHeadBytes() * 8;
00369 
00370     std::cerr<<std::endl<<std::endl<<"Total frame bits="<<unit_bits;
00371     std::cerr<<" ( "<<unit_head_bits<<" header bits)"<<std::endl<<std::endl;
00372 
00373 }
00374 
00375 
00376 void SequenceCompressor::WriteStreamHeader()
00377 {
00378      // Write out all the header data
00379     BasicOutputManager& stream_header = m_encparams.BitsOut().HeaderOutput();
00380 
00381         // Begin with the ID of the codec
00382      stream_header.OutputBytes("KW-DIRAC");
00383     
00384     unsigned char seq_start[5] = { START_CODE_PREFIX_BYTE0,
00385                                    START_CODE_PREFIX_BYTE1,
00386                                    START_CODE_PREFIX_BYTE2,
00387                                    START_CODE_PREFIX_BYTE3,
00388                                    RAP_START_CODE };
00389     
00390     stream_header.OutputBytes((char *)seq_start, 5);
00391 
00392     // bit stream version
00393     stream_header.OutputByte((char)BITSTREAM_VERSION);
00394 
00395         // Picture dimensions
00396      UnsignedGolombCode( stream_header ,(unsigned int) m_pic_in->GetSeqParams().Xl() );
00397      UnsignedGolombCode( stream_header ,(unsigned int) m_pic_in->GetSeqParams().Yl() );
00398 
00399      // Picture rate
00400      UnsignedGolombCode( stream_header , (unsigned int) m_pic_in->GetSeqParams().FrameRate());
00401 
00402      // Block parameters
00403      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.LumaBParams(2).Xblen() );
00404      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.LumaBParams(2).Yblen() );
00405      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.LumaBParams(2).Xbsep() );
00406      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.LumaBParams(2).Ybsep() );
00407 
00408      // Also send the number of blocks horizontally and vertically
00409      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.XNumBlocks() );
00410      UnsignedGolombCode( stream_header ,(unsigned int) m_encparams.YNumBlocks() );
00411 
00412      // Chroma format
00413      UnsignedGolombCode( stream_header ,(unsigned int) m_pic_in->GetSeqParams().CFormat() );
00414 
00415      // Interlace marker
00416      stream_header.OutputBit(m_pic_in->GetSeqParams().Interlace() );
00417 
00418      m_encparams.BitsOut().WriteSeqHeaderToFile();
00419 }
00420 
00421 int SequenceCompressor::CodedToDisplay( const int fnum )
00422 {
00423     int div;
00424 
00425     if (m_encparams.L1Sep()>0)
00426     {
00427         // We have L1 and L2 frames
00428         if (fnum==0)
00429             return 0;
00430         else if ((fnum-1)% m_encparams.L1Sep()==0)
00431         {//we have L1 or subsequent I frames
00432             div=(fnum-1)/m_encparams.L1Sep();
00433             return fnum+m_encparams.L1Sep()-1;
00434         }
00435         else//we have L2 frames
00436             return fnum-1;
00437     }
00438     else
00439     {//we just have I-frames, so no re-ordering
00440         return fnum;
00441     }
00442 }

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