# Dirac - A Video Codec

Created by the British Broadcasting Corporation.

# band_codec_template.h

Go to the documentation of this file.

    00001
    00002 #include <libdirac_common/band_codec.h>
    00003 #include <libdirac_byteio/subband_byteio.h>
    00004
    00005 using namespace dirac;
    00006
    00008 template<typename EntropyCodec>
    00009 GenericBandCodec<EntropyCodec>::GenericBandCodec(SubbandByteIO* subband_byteio,
    00010                      size_t number_of_contexts,
    00011                      const SubbandList & band_list,
    00012                      int band_num,
    00013                      const bool is_intra):
    00014     EntropyCodec(subband_byteio,number_of_contexts),
    00015     m_is_intra(is_intra),
    00016     m_bnum(band_num),
    00017     m_node(band_list(band_num)),
    00018     m_last_qf_idx(m_node.QuantIndex())
    00019 {
    00020     if (m_node.Parent()!=0)
    00021         m_pnode=band_list(m_node.Parent());
    00022 }
    00023
    00024
    00025 //encoding function
    00026 template<typename EntropyCodec>
    00027 void GenericBandCodec<EntropyCodec>::DoWorkCode(CoeffArray& in_data)
    00028 {
    00029
    00030     const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
    00031
    00032     // coeff blocks can be skipped only if SpatialPartitioning is
    00033     // enabled i.e. more than one code-block per subband
    00034     bool code_skip = (block_list.LengthX() > 1 || block_list.LengthY() > 1);
    00035     // Now loop over the blocks and code
    00036     for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
    00037     {
    00038         CodeBlock *block = block_list[j];
    00039         for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
    00040         {
    00041             if (code_skip)
    00042                 EntropyCodec::EncodeSymbol(block[i].Skipped() , BLOCK_SKIP_CTX );
    00043             if ( !block[i].Skipped() )
    00044                 CodeCoeffBlock( block[i] , in_data );
    00045             else
    00046                 ClearBlock (block[i] , in_data);
    00047         }// i
    00048     }// j
    00049
    00050 }
    00051
    00052 template<typename EntropyCodec>
    00053 void GenericBandCodec<EntropyCodec>::CodeCoeffBlock( const CodeBlock& code_block , CoeffArray& in_data )
    00054 {
    00055     //main coding function, using binarisation
    00056
    00057     const int xbeg = code_block.Xstart();
    00058     const int ybeg = code_block.Ystart();
    00059     const int xend = code_block.Xend();
    00060     const int yend = code_block.Yend();
    00061
    00062     const int qf_idx = code_block.QuantIndex();
    00063
    00064     bool has_parent = m_node.Parent() != 0;
    00065
    00066     if ( m_node.UsingMultiQuants() )
    00067     {
    00068           CodeQuantIndexOffset( qf_idx - m_last_qf_idx);
    00069           m_last_qf_idx = qf_idx;
    00070     }
    00071
    00072     m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
    00073     if (m_is_intra)
    00074         m_offset =  dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
    00075     else
    00076         m_offset =  dirac_quantiser_lists.InterQuantOffset4( qf_idx );
    00077
    00078     for ( int ypos=ybeg; ypos<yend ;++ypos)
    00079     {
    00080         m_pypos=(( ypos-m_node.Yp() )>>1)+m_pnode.Yp();
    00081         for ( int xpos=xbeg; xpos<xend ;++xpos)
    00082         {
    00083             m_pxpos=(( xpos-m_node.Xp() )>>1)+m_pnode.Xp();
    00084
    00085             m_nhood_nonzero = false;
    00086             if (ypos > m_node.Yp())
    00087                 m_nhood_nonzero |= bool(in_data[ypos-1][xpos]);
    00088             if (xpos > m_node.Xp())
    00089                 m_nhood_nonzero |= bool(in_data[ypos][xpos-1]);
    00090             if (ypos > m_node.Yp() && xpos > m_node.Xp())
    00091                 m_nhood_nonzero |= bool(in_data[ypos-1][xpos-1]);
    00092
    00093             if (has_parent)
    00094                 m_parent_notzero = static_cast<bool> ( in_data[m_pypos][m_pxpos] );
    00095             else
    00096                 m_parent_notzero = false;
    00097
    00098             CodeCoeff( in_data , xpos , ypos );
    00099
    00100         }// xpos
    00101     }// ypos
    00102
    00103 }
    00104
    00105 template<typename EntropyCodec>
    00106 void GenericBandCodec<EntropyCodec>::CodeCoeff( CoeffArray& in_data, const int xpos, const int ypos)
    00107 {
    00108     CodeVal( in_data , xpos , ypos , in_data[ypos][xpos] );
    00109 }
    00110
    00111
    00112 /*
    00113 Coefficient magnitude value and differential quantiser index magnitude are
    00114 coded using interleaved exp-Golomb coding for binarisation. In this scheme, a
    00115 value N>=0 is coded by writing N+1 in binary form of a 1 followed by K other
    00116 bits: 1bbbbbbb (adding 1 ensures there'll be a leading 1). These K bits ("info
    00117 bits") are interleaved with K zeroes ("follow bits") each of which means
    00118 "another bit coming", followed by a terminating 1:
    00119
    00120     0b0b0b ...0b1
    00121
    00122 (Conventional exp-Golomb coding has the K zeroes at the beginning, followed
    00123 by the 1 i.e 00...01bb .. b, but interleaving allows the decoder to run a
    00124 single loop and avoid counting the number of zeroes, sparing a register.)
    00125
    00126 All bits are arithmetically coded. The follow bits have separate contexts
    00127 based on position, and have different contexts from the info bits.
    00128 */
    00129
    00130 template<typename EntropyCodec>
    00131 inline void GenericBandCodec<EntropyCodec>::CodeVal( CoeffArray& in_data ,
    00132                                 const int xpos ,
    00133                                 const int ypos ,
    00134                                 const CoeffType val )
    00135 {
    00136     unsigned int abs_val( std::abs(val) );
    00137     abs_val <<= 2;
    00138     abs_val /= m_qf;
    00139
    00140     const int N = abs_val+1;
    00141     int num_follow_zeroes=0;
    00142
    00143     while ( N >= (1<<num_follow_zeroes) )
    00144         ++num_follow_zeroes;
    00145     --num_follow_zeroes;
    00146
    00147     for ( int i=num_follow_zeroes-1, c=1; i>=0; --i, ++c )
    00148     {
    00149         EntropyCodec::EncodeSymbol( 0, ChooseFollowContext( c ) );
    00150         EntropyCodec::EncodeSymbol( N&(1<<i), ChooseInfoContext() );
    00151     }
    00152     EntropyCodec::EncodeSymbol( 1, ChooseFollowContext( num_follow_zeroes+1 ) );
    00153
    00154     in_data[ypos][xpos] = static_cast<CoeffType>( abs_val );
    00155
    00156     if ( abs_val )
    00157     {
    00158         // Must code sign bits and reconstruct
    00159         in_data[ypos][xpos] *= m_qf;
    00160         in_data[ypos][xpos] += m_offset+2;
    00161         in_data[ypos][xpos] >>= 2;
    00162
    00163         if ( val>0 )
    00164         {
    00165             EntropyCodec::EncodeSymbol( 0 , ChooseSignContext( in_data , xpos , ypos ) );
    00166         }
    00167         else
    00168         {
    00169             EntropyCodec::EncodeSymbol( 1 , ChooseSignContext( in_data , xpos , ypos ) );
    00170             in_data[ypos][xpos]  = -in_data[ypos][xpos];
    00171         }
    00172     }
    00173 }
    00174
    00175 template<typename EntropyCodec>
    00176 void GenericBandCodec<EntropyCodec>::CodeQuantIndexOffset( const int offset )
    00177 {
    00178
    00179     const int abs_val = std::abs( offset );
    00180
    00181     int N = abs_val+1;
    00182     int num_follow_zeroes=0;
    00183
    00184     while ( N>= (1<<num_follow_zeroes) )
    00185         ++num_follow_zeroes;
    00186     --num_follow_zeroes;
    00187
    00188     for ( int i=num_follow_zeroes-1, c=1; i>=0; --i, ++c )
    00189     {
    00190         EntropyCodec::EncodeSymbol( 0 , Q_OFFSET_FOLLOW_CTX );
    00191         EntropyCodec::EncodeSymbol( N&(1<<i), Q_OFFSET_INFO_CTX );
    00192     }
    00193     EntropyCodec::EncodeSymbol( 1 , Q_OFFSET_FOLLOW_CTX );
    00194
    00195     if ( abs_val )
    00196     {
    00197         if ( offset>0 )
    00198             EntropyCodec::EncodeSymbol( 0 , Q_OFFSET_SIGN_CTX );
    00199         else
    00200             EntropyCodec::EncodeSymbol( 1 , Q_OFFSET_SIGN_CTX );
    00201     }
    00202 }
    00203
    00204 template<typename EntropyCodec>
    00205 void GenericBandCodec<EntropyCodec>::DoWorkDecode( CoeffArray& out_data )
    00206 {
    00207     const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
    00208
    00209     // coeff blocks can be skipped only if SpatialPartitioning is
    00210     // enabled i.e. more than one code-block per subband
    00211     bool decode_skip= (block_list.LengthX() > 1 || block_list.LengthY() > 1);
    00212     // Now loop over the blocks and decode
    00213     for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
    00214     {
    00215         CodeBlock *block = block_list[j];
    00216         for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
    00217         {
    00218             if (decode_skip)
    00219                 block[i].SetSkip( EntropyCodec::DecodeSymbol( BLOCK_SKIP_CTX ) );
    00220             if ( !block[i].Skipped() )
    00221                 DecodeCoeffBlock( block[i] , out_data );
    00222             else
    00223                 ClearBlock (block[i] , out_data);
    00224
    00225         }// i
    00226     }// j
    00227
    00228 }
    00229
    00230 template<typename EntropyCodec>
    00231 void GenericBandCodec<EntropyCodec>::DecodeCoeffBlock( const CodeBlock& code_block , CoeffArray& out_data )
    00232 {
    00233
    00234
    00235     const int xbeg = code_block.Xstart();
    00236     const int ybeg = code_block.Ystart();
    00237     const int xend = code_block.Xend();
    00238     const int yend = code_block.Yend();
    00239
    00240     int qf_idx = m_node.QuantIndex();
    00241
    00242     bool has_parent = m_node.Parent() != 0;
    00243
    00244     if ( m_node.UsingMultiQuants() )
    00245     {
    00246         qf_idx = m_last_qf_idx+DecodeQuantIndexOffset();
    00247         m_last_qf_idx = qf_idx;
    00248     }
    00249
    00250     if (qf_idx > (int)dirac_quantiser_lists.MaxQuantIndex())
    00251     {
    00252         std::ostringstream errstr;
    00253         errstr << "Quantiser index out of range [0.."
    00254                << (int)dirac_quantiser_lists.MaxQuantIndex() << "]";
    00255         DIRAC_THROW_EXCEPTION(
    00256             ERR_UNSUPPORTED_STREAM_DATA,
    00257             errstr.str(),
    00258             SEVERITY_PICTURE_ERROR);
    00259     }
    00260
    00261     m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
    00262
    00263     if (m_is_intra)
    00264         m_offset =  dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
    00265     else
    00266         m_offset =  dirac_quantiser_lists.InterQuantOffset4( qf_idx );
    00267
    00268     //Work
    00269
    00270     for ( int ypos=ybeg; ypos<yend ;++ypos)
    00271     {
    00272     m_pypos=(( ypos-m_node.Yp() )>>1)+m_pnode.Yp();
    00273         CoeffType *p_out_data = NULL;
    00274         if (has_parent)
    00275             p_out_data = out_data[m_pypos];
    00276         CoeffType *c_out_data_1 = NULL;
    00277         if (ypos!=m_node.Yp())
    00278             c_out_data_1 = out_data[ypos-1];
    00279         CoeffType *c_out_data_2 = out_data[ypos];
    00280         for ( int xpos=xbeg; xpos<xend ;++xpos)
    00281         {
    00282         m_pxpos=(( xpos-m_node.Xp() )>>1)+m_pnode.Xp();
    00283
    00284             m_nhood_nonzero = false;
    00285             /* c_out_data_1 is the line above the current
    00286              * c_out_data_2 is the current line */
    00287             if (ypos > m_node.Yp())
    00288                 m_nhood_nonzero |= bool(c_out_data_1[xpos]);
    00289             if (xpos > m_node.Xp())
    00290                 m_nhood_nonzero |= bool(c_out_data_2[xpos-1]);
    00291             if (ypos > m_node.Yp() && xpos > m_node.Xp())
    00292                 m_nhood_nonzero |= bool(c_out_data_1[xpos-1]);
    00293
    00294             if (has_parent)
    00295                 m_parent_notzero = ( p_out_data[m_pxpos] != 0 );
    00296             else
    00297                 m_parent_notzero = false;
    00298
    00299             DecodeCoeff( out_data , xpos , ypos );
    00300
    00301         }// xpos
    00302     }// ypos
    00303 }
    00304
    00305 template<typename EntropyCodec>
    00306 void GenericBandCodec<EntropyCodec>::DecodeCoeff( CoeffArray& in_data, const int xpos, const int ypos)
    00307 {
    00308     DecodeVal( in_data , xpos , ypos );
    00309 }
    00310
    00311
    00312 /*
    00313 Coefficient magnitude value and differential quantiser index value is coded
    00314 using interleaved exp-Golomb coding for binarisation. In this scheme, a value
    00315 N>=0 is coded by writing N+1 in binary form of a 1 followed by K other bits:
    00316 1bbbbbbb (adding 1 ensures there'll be a leading 1). These K bits ("info bits")
    00317 are interleaved with K zeroes ("follow bits") each of which means "another bit
    00318 coming", followed by a terminating 1:
    00319
    00320     0b0b0b ...0b1
    00321
    00322 (Conventional exp-Golomb coding has the K zeroes at the beginning, followed
    00323 by the 1 i.e 00...01bb .. b, but interleaving allows the decoder to run a
    00324 single loop and avoid counting the number of zeroes, sparing a register.)
    00325
    00326 All bits are arithmetically coded. The follow bits have separate contexts
    00327 based on position, and have different contexts from the info bits.
    00328 */
    00329 template<typename EntropyCodec>
    00330 inline void GenericBandCodec<EntropyCodec>::DecodeVal( CoeffArray& out_data , const int xpos , const int ypos )
    00331 {
    00332
    00333     CoeffType& out_pixel = out_data[ypos][xpos];
    00334
    00335     out_pixel = 1;
    00336     int bit_count=1;
    00337
    00338     while ( !EntropyCodec::DecodeSymbol( ChooseFollowContext( bit_count ) ) )
    00339     {
    00340         out_pixel <<= 1;
    00341         out_pixel |= EntropyCodec::DecodeSymbol( ChooseInfoContext() );
    00342         bit_count++;
    00343     };
    00344     --out_pixel;
    00345
    00346     if ( out_pixel )
    00347     {
    00348         out_pixel *= m_qf;
    00349         out_pixel += m_offset+2;
    00350         out_pixel >>= 2;
    00351
    00352         if ( EntropyCodec::DecodeSymbol( ChooseSignContext(out_data, xpos, ypos)) )
    00353             out_pixel = -out_pixel;
    00354     }
    00355 }
    00356
    00357 template<typename EntropyCodec>
    00358 inline int GenericBandCodec<EntropyCodec>::ChooseFollowContext( const int bin_number ) const
    00359 {
    00360     //condition on neighbouring values and parent values
    00361
    00362     if (!m_parent_notzero)
    00363     {
    00364         switch ( bin_number )
    00365         {
    00366             case 1 :
    00367                 if(m_nhood_nonzero == false)
    00368                     return Z_FBIN1z_CTX;
    00369
    00370                 return Z_FBIN1nz_CTX;
    00371
    00372             case 2 :
    00373                 return Z_FBIN2_CTX;
    00374             case 3 :
    00375                 return Z_FBIN3_CTX;
    00376             case 4 :
    00377                 return Z_FBIN4_CTX;
    00378             case 5 :
    00379                 return Z_FBIN5_CTX;
    00380             default :
    00381                 return Z_FBIN6plus_CTX;
    00382         }
    00383     }
    00384     else
    00385     {
    00386         switch ( bin_number )
    00387         {
    00388             case 1 :
    00389                 if(m_nhood_nonzero == false)
    00390                     return NZ_FBIN1z_CTX;
    00391
    00392                 return NZ_FBIN1nz_CTX;
    00393
    00394             case 2 :
    00395                 return NZ_FBIN2_CTX;
    00396             case 3 :
    00397                 return NZ_FBIN3_CTX;
    00398             case 4 :
    00399                 return NZ_FBIN4_CTX;
    00400             case 5 :
    00401                 return NZ_FBIN5_CTX;
    00402             default :
    00403                 return NZ_FBIN6plus_CTX;
    00404         }
    00405
    00406     }
    00407
    00408     /* not reachable, but dumb compilers can't spot that */
    00409     return 0;
    00410 }
    00411
    00412 template<typename EntropyCodec>
    00413 inline int GenericBandCodec<EntropyCodec>::ChooseInfoContext() const
    00414 {
    00415     return INFO_CTX;
    00416 }
    00417
    00418 template<typename EntropyCodec>
    00419 inline int GenericBandCodec<EntropyCodec>::ChooseSignContext( const CoeffArray& data , const int xpos , const int ypos ) const
    00420 {
    00421     if ( m_node.Yp()==0 && m_node.Xp()!=0 )
    00422     {
    00423         //we're in a vertically oriented subband
    00424         if (ypos == 0)
    00425             return SIGN0_CTX;
    00426         else
    00427         {
    00428             if (data[ypos-1][xpos]>0)
    00429                 return SIGN_POS_CTX;
    00430             else if (data[ypos-1][xpos]<0)
    00431                 return SIGN_NEG_CTX;
    00432             else
    00433                 return SIGN0_CTX;
    00434         }
    00435     }
    00436     else if ( m_node.Xp()==0 && m_node.Yp()!=0 )
    00437     {
    00438         //we're in a horizontally oriented subband
    00439         if (xpos == 0)
    00440             return SIGN0_CTX;
    00441         else
    00442         {
    00443             if ( data[ypos][xpos-1] > 0 )
    00444                 return SIGN_POS_CTX;
    00445             else if ( data[ypos][xpos-1] < 0 )
    00446                 return SIGN_NEG_CTX;
    00447             else
    00448                 return SIGN0_CTX;
    00449         }
    00450     }
    00451     else
    00452         return SIGN0_CTX;
    00453 }
    00454
    00455 template<typename EntropyCodec>
    00456 int GenericBandCodec<EntropyCodec>::DecodeQuantIndexOffset()
    00457 {
    00458     int offset = 1;
    00459
    00460     while ( !EntropyCodec::DecodeSymbol( Q_OFFSET_FOLLOW_CTX ) )
    00461     {
    00462         offset <<= 1;
    00463         offset |= EntropyCodec::DecodeSymbol( Q_OFFSET_INFO_CTX );
    00464     }
    00465     --offset;
    00466
    00467     if ( offset )
    00468     {
    00469         if ( EntropyCodec::DecodeSymbol( Q_OFFSET_SIGN_CTX ) )
    00470             offset = -offset;
    00471     }
    00472     return offset;
    00473 }
    00474
    00475 template<typename EntropyCodec>
    00476 void GenericBandCodec<EntropyCodec>::SetToVal( const CodeBlock& code_block , CoeffArray& pic_data , const CoeffType val)
    00477 {
    00478     for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
    00479     {
    00480           for (int i=code_block.Xstart() ; i<code_block.Xend() ; i++)
    00481            {
    00482             pic_data[j][i] = val;
    00483            }// i
    00484     }// j
    00485 }
    00486
    00487 template<typename EntropyCodec>
    00488 void GenericBandCodec<EntropyCodec>::ClearBlock( const CodeBlock& code_block , CoeffArray& coeff_data)
    00489 {
    00490     for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
    00491     {
    00492         CoeffType *pic = &coeff_data[j][code_block.Xstart()];
    00493         memset (pic, 0, (code_block.Xend()-code_block.Xstart())*sizeof(CoeffType));
    00494     }// j
    00495
    00496 }
    00497
    00498 /*  Decode a single coefficient using error-feedback DC quantization */
    00499 template<typename EntropyCodec>
    00500 void GenericIntraDCBandCodec<EntropyCodec>::DecodeCoeffBlock(const CodeBlock& code_block , CoeffArray& out_data)
    00501 {
    00502     GenericBandCodec<EntropyCodec>::DecodeCoeffBlock(code_block, out_data);
    00503     /* do prediction for this block */
    00504     for ( int ypos=code_block.Ystart() ; ypos<code_block.Yend() ; ++ypos)
    00505     {
    00506         for ( int xpos=code_block.Xstart() ; xpos<code_block.Xend() ; ++xpos)
    00507         {
    00508              out_data[ypos][xpos] += GetPrediction( out_data , xpos , ypos );
    00509         }
    00510     }
    00511 }
    00512
    00513 /* after coding a skipped DC codeblock, reconstruct in_data by predicting the values
    00514  * and not adding any error term (they were all skipped).  This is required to correctly
    00515  * predict the values in the next codeblock */
    00516
    00517 template<typename EntropyCodec>
    00518 void GenericIntraDCBandCodec<EntropyCodec>::ClearBlock( const CodeBlock& code_block , CoeffArray& coeff_data)
    00519 {
    00520     for (int ypos=code_block.Ystart() ; ypos<code_block.Yend() ; ++ypos)
    00521     {
    00522         for (int xpos=code_block.Xstart() ; xpos<code_block.Xend() ; ++xpos)
    00523         {
    00524             /* NB, it is correct to overwrite the old value */
    00525             coeff_data[ypos][xpos] = GetPrediction( coeff_data , xpos , ypos );
    00526         } // i
    00527     } // j
    00528 }
    00529
    00530 template<typename EntropyCodec>
    00531 CoeffType GenericIntraDCBandCodec<EntropyCodec>::GetPrediction( const CoeffArray& data , const int xpos , const int ypos ) const
    00532 {
    00533     /* NB, 4.5.3 integer division
    00534      * numbers are rounded down towards -ve infinity, differing from
    00535      * C's convention that rounds towards 0
    00536     */
    00537     if (ypos!=0)
    00538     {
    00539         if (xpos!=0)
    00540         {
    00541             int sum = data[ypos][xpos-1] + data[ypos-1][xpos-1] + data[ypos-1][xpos] + 3/2;
    00542             if (sum<0)
    00543                 return (sum-2)/3;
    00544             else
    00545                 return sum/3;
    00546         }
    00547         else
    00548             return data[ypos - 1][0];
    00549     }
    00550     else
    00551     {
    00552         if(xpos!=0)
    00553             return data[0][xpos - 1];
    00554         else
    00555             return 0;
    00556     }
    00557 }

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