Created by the British Broadcasting Corporation.
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.