- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

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