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.