Dirac - A Video Codec

Created by the British Broadcasting Corporation.


arith_codec.h

Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002 *
00003 * $Id: arith_codec.h,v 1.40 2007/11/16 04:48:44 asuraparaju Exp $ $Name: Dirac_1_0_2 $
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):   Richard Felton (Original Author),
00024                     Thomas Davies,
00025                     Scott R Ladd,
00026                     Peter Bleackley,
00027                     Steve Bearcroft,
00028                     Anuradha Suraparaju,
00029                     Tim Borer (major refactor February 2006)
00030                     Andrew Kennedy
00031 *
00032 * Alternatively, the contents of this file may be used under the terms of
00033 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
00034 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
00035 * the GPL or the LGPL are applicable instead of those above. If you wish to
00036 * allow use of your version of this file only under the terms of the either
00037 * the GPL or LGPL and not to allow others to use your version of this file
00038 * under the MPL, indicate your decision by deleting the provisions above
00039 * and replace them with the notice and other provisions required by the GPL
00040 * or LGPL. If you do not delete the provisions above, a recipient may use
00041 * your version of this file under the terms of any one of the MPL, the GPL
00042 * or the LGPL.
00043 * ***** END LICENSE BLOCK ***** */
00044 
00045 
00046 #ifndef _ARITH_CODEC_H_
00047 #define _ARITH_CODEC_H_
00048 
00057 
00058 #include <libdirac_common/common.h>
00059 #include <libdirac_byteio/byteio.h>
00060 #include <vector>
00061 
00062 namespace dirac
00063 {
00064 
00065     class Context {
00066     public:
00067 
00069 
00072         inline Context();
00073 
00074         //Class is POD
00075         //Use built in copy constructor, assignment and destructor.
00076 
00078 
00079         inline unsigned int GetScaledProb0( ) const{ return m_prob0;}
00080 
00082         inline void Update( bool symbol ) {
00083           if (symbol) m_prob0 -= lut[m_prob0>>8];
00084           else m_prob0 += lut[255-(m_prob0>>8)];
00085         }
00086 
00087     private:
00088 
00089         int m_prob0;
00090         static const unsigned int lut[256]; //Probability update table
00091     };
00092     
00093     Context::Context(): m_prob0( 0x8000 ) {}
00094 
00095     class ArithCodecBase {
00096 
00097     public:
00098 
00100 
00106         ArithCodecBase(ByteIO* p_byteio, size_t number_of_contexts);
00107 
00109 
00112         virtual ~ArithCodecBase();
00113 
00114     protected:
00115 
00116         //core encode functions
00118 
00120         void InitEncoder();
00121 
00123         void EncodeSymbol(const bool symbol, const int context_num);
00124 
00125         void EncodeUInt(const unsigned int value, const int bin1, const int max_bin);
00126 
00127         void EncodeSInt(const int value, const int bin1, const int max_bin);
00128 
00130         void FlushEncoder();
00131 
00132         int ByteCount() const;     
00133 
00134         // core decode functions
00136 
00138         void InitDecoder(int num_bytes);                    
00139 
00141         bool DecodeSymbol( int context_num );
00142 
00143         unsigned int DecodeUInt(const int bin1, const int max_bin);
00144 
00145         int DecodeSInt(const int bin1, const int max_bin);
00146         
00148         std::vector<Context> m_context_list;
00149 
00150     private:
00151         
00153         ArithCodecBase(const ArithCodecBase & cpy);
00154 
00156         ArithCodecBase & operator = (const ArithCodecBase & rhs);
00157              
00158                      
00159         // Decode functions
00161 
00163         void ReadAllData(int num_bytes);
00164 
00166         inline bool InputBit();
00167 
00168         // Codec data
00170  
00171  unsigned int m_scount;
00172  
00174         unsigned int m_low_code;
00175         
00177         unsigned int m_range;
00178 
00180         ByteIO *m_byteio;
00181 
00182         // For encoder only
00183 
00185         int m_underflow;
00186 
00188         char* m_decode_data_ptr;
00189 
00191         char* m_data_ptr;
00192 
00194         int m_input_bits_left;
00195 
00197         unsigned int m_code;
00198 
00199     };
00200 
00201 
00202     inline bool ArithCodecBase::DecodeSymbol( int context_num )
00203     {
00204  
00205         // Determine the next symbol value by placing code within
00206         // the [low,high] interval.
00207 
00208         // Fetch the statistical context to be used
00209         Context& ctx  = m_context_list[context_num];
00210 
00211         // Decode as per updated specification
00212         const unsigned int count = m_code - m_low_code ; 
00213         const unsigned int range_x_prob = ( m_range* ctx.GetScaledProb0())>>16;
00214         const bool symbol = ( count >= range_x_prob );
00215 
00216         // Rescale the interval
00217         if( symbol )    //symbol is 1
00218         {
00219             m_low_code += range_x_prob;
00220             m_range -= range_x_prob;
00221         }
00222         else            //symbol is 0, so m_low_code unchanged
00223         {
00224             m_range = range_x_prob;
00225         }
00226 
00227         // Update the statistical context
00228         ctx.Update( symbol );
00229 
00230         while ( m_range<=0x4000 )
00231         {
00232             if( ( (m_low_code+m_range-1)^m_low_code)>=0x8000 )
00233             {
00234                 // Straddle condition
00235                 // We must have an underflow situation with
00236                 // low = 0x01... and high = 0x10...
00237                 // Flip 2nd bit prior to rescaling
00238                 m_code      ^= 0x4000;
00239                 m_low_code  ^= 0x4000;
00240             }
00241 
00242             // Double low and range, throw away top bit of low
00243             m_low_code  <<= 1;
00244             m_range <<= 1;
00245             m_low_code   &= 0xFFFF;
00246 
00247             // Shift in another bit of code
00248             m_code      <<= 1;
00249             m_code       += InputBit();
00250             m_code       &= 0xFFFF;
00251       
00252         }
00253 
00254         return symbol;
00255     }
00256 
00257     inline unsigned int ArithCodecBase::DecodeUInt(const int bin1, const int max_bin) {
00258         const int info_ctx = (max_bin+1);
00259         int bin = bin1;
00260         unsigned int value = 1;
00261         while (!DecodeSymbol(bin)) {
00262             value <<= 1;
00263             if (DecodeSymbol(info_ctx)) value+=1;
00264             if (bin<max_bin) bin+=1;
00265         }
00266         value -= 1;
00267         return value;
00268     }
00269 
00270     inline int ArithCodecBase::DecodeSInt(const int bin1, const int max_bin) {
00271         int value = 0;
00272         const int magnitude = DecodeUInt(bin1, max_bin);
00273         if (magnitude!=0) {
00274             if (DecodeSymbol(max_bin+2)) value=-magnitude;
00275             else value=magnitude;
00276         }
00277         return value;
00278     }
00279 
00280     inline void ArithCodecBase::EncodeSymbol(const bool symbol, const int context_num)
00281     {
00282 
00283         // Adjust high and low (rescale interval) based on the symbol we are encoding
00284 
00285         Context& ctx = m_context_list[context_num];
00286 
00287         const unsigned int range_x_prob = ( m_range* ctx.GetScaledProb0())>>16;
00288 
00289         if ( symbol )    //symbol is 1
00290         {
00291             m_low_code += range_x_prob;
00292             m_range -= range_x_prob;  
00293         }
00294         else             // symbol is 0, so m_low_code unchanged
00295         {
00296             m_range = range_x_prob;
00297         }
00298         
00299         // Update the statistical context
00300         ctx.Update( symbol );
00301 
00302         while ( m_range <= 0x4000 )
00303         { 
00304             if ( ( (m_low_code+m_range-1)^m_low_code)>=0x8000 )
00305             {    
00306                 // Straddle condition
00307                 // We must have an underflow situation with
00308                 // low = 0x01... and high = 0x10...
00309 
00310                 m_low_code  ^= 0x4000;
00311                 m_underflow++;
00312 
00313             }
00314             else
00315             {
00316                 // Bits agree - output them
00317                 m_byteio->WriteBit( m_low_code & 0x8000);
00318                 for (; m_underflow > 0; m_underflow-- )
00319                     m_byteio->WriteBit(~m_low_code & 0x8000);
00320             }
00321 
00322             // Double low value and range
00323             m_low_code  <<= 1;
00324             m_range <<= 1;
00325 
00326             // keep low to 16 bits - throw out top bit
00327             m_low_code   &= 0xFFFF;
00328 
00329          }
00330     }
00331 
00332     inline void ArithCodecBase::EncodeUInt(const unsigned int the_int,
00333                                            const int bin1, const int max_bin) {
00334         const int value = (the_int+1);
00335         const int info_ctx = (max_bin+1);
00336         int bin = bin1;
00337         int top_bit = 1;
00338         {
00339             int max_value = 1;
00340             while (value>max_value) {
00341                 top_bit <<= 1;
00342                 max_value <<= 1;
00343                 max_value += 1;
00344             }
00345         }
00346         bool stop = (top_bit==1);
00347         EncodeSymbol(stop, bin);
00348         while (!stop) {
00349             top_bit >>= 1;
00350             EncodeSymbol( (value&top_bit), info_ctx);
00351             if ( bin < max_bin) bin+=1;
00352             stop = (top_bit==1);
00353             EncodeSymbol(stop, bin);
00354         }
00355     }
00356 
00357     inline void ArithCodecBase::EncodeSInt(const int value,
00358                                            const int bin1, const int max_bin) {
00359         EncodeUInt(std::abs(value), bin1, max_bin);
00360         if (value != 0) {
00361             EncodeSymbol( (value < 0), max_bin+2 );
00362         }
00363     }
00364 
00365 
00367 
00373     template<class T> //T is container/array type
00374     class ArithCodec
00375         : public ArithCodecBase
00376     {
00377     public:
00378 
00380 
00386         ArithCodec(ByteIO* p_byteio, size_t number_of_contexts);
00387 
00388       
00390 
00393         virtual ~ArithCodec() {}
00394 
00396 
00404         int Compress(T & in_data);
00405     
00407 
00415         void Decompress(T & out_data, const int num_bytes);
00416 
00417     protected:
00418 
00419         //virtual encode-only functions
00421 
00423         virtual void DoWorkCode(T & in_data) = 0; 
00424 
00427         virtual void DoWorkDecode(T & out_data)=0;
00428    };
00429 
00430     //Implementation - core functions
00432 
00433     template<class T>
00434     ArithCodec<T>::ArithCodec(ByteIO* p_byteio, size_t number_of_contexts):
00435         ArithCodecBase(p_byteio, number_of_contexts) {}
00436 
00437 
00438 
00439     template<class T>
00440     int ArithCodec<T>::Compress(T &in_data)
00441     {
00442         InitEncoder();                
00443         DoWorkCode(in_data);
00444         FlushEncoder();
00445         return ByteCount();
00446     }
00447 
00448     template<class T>
00449     void ArithCodec<T>::Decompress( T &out_data, const int num_bytes )
00450     {
00451         InitDecoder(num_bytes);
00452         DoWorkDecode( out_data );
00453     }
00454 
00455    inline bool ArithCodecBase::InputBit()
00456     {
00457         if (m_input_bits_left == 0)
00458         {
00459             m_data_ptr++;
00460             m_input_bits_left = 8;
00461         }
00462         m_input_bits_left--;
00463         // MSB to LSB
00464         return bool( ( (*m_data_ptr) >> m_input_bits_left ) & 1 );
00465     }
00466 
00467 }// namespace dirac
00468 #endif
00469 

© 2004 British Broadcasting Corporation. Dirac code licensed under the Mozilla Public License (MPL) Version 1.1.
HTML documentation generated by Dimitri van Heesch's excellent Doxygen tool.