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