Dirac - A Video Codec

Created by the British Broadcasting Corporation.


band_codec_template.h
Go to the documentation of this file.
1 
4 
5 using namespace dirac;
6 
8 template<typename EntropyCodec>
10  size_t number_of_contexts,
11  const SubbandList & band_list,
12  int band_num,
13  const bool is_intra):
14  EntropyCodec(subband_byteio,number_of_contexts),
15  m_is_intra(is_intra),
16  m_bnum(band_num),
17  m_node(band_list(band_num)),
18  m_last_qf_idx(m_node.QuantIndex())
19 {
20  if (m_node.Parent()!=0)
21  m_pnode=band_list(m_node.Parent());
22 }
23 
24 
25 //encoding function
26 template<typename EntropyCodec>
28 {
29 
30  const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
31 
32  // coeff blocks can be skipped only if SpatialPartitioning is
33  // enabled i.e. more than one code-block per subband
34  bool code_skip = (block_list.LengthX() > 1 || block_list.LengthY() > 1);
35  // Now loop over the blocks and code
36  for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
37  {
38  CodeBlock *block = block_list[j];
39  for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
40  {
41  if (code_skip)
42  EntropyCodec::EncodeSymbol(block[i].Skipped() , BLOCK_SKIP_CTX );
43  if ( !block[i].Skipped() )
44  CodeCoeffBlock( block[i] , in_data );
45  else
46  ClearBlock (block[i] , in_data);
47  }// i
48  }// j
49 
50 }
51 
52 template<typename EntropyCodec>
54 {
55  //main coding function, using binarisation
56 
57  const int xbeg = code_block.Xstart();
58  const int ybeg = code_block.Ystart();
59  const int xend = code_block.Xend();
60  const int yend = code_block.Yend();
61 
62  const int qf_idx = code_block.QuantIndex();
63 
64  bool has_parent = m_node.Parent() != 0;
65 
66  if ( m_node.UsingMultiQuants() )
67  {
68  CodeQuantIndexOffset( qf_idx - m_last_qf_idx);
69  m_last_qf_idx = qf_idx;
70  }
71 
72  m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
73  if (m_is_intra)
74  m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
75  else
76  m_offset = dirac_quantiser_lists.InterQuantOffset4( qf_idx );
77 
78  for ( int ypos=ybeg; ypos<yend ;++ypos)
79  {
80  m_pypos=(( ypos-m_node.Yp() )>>1)+m_pnode.Yp();
81  for ( int xpos=xbeg; xpos<xend ;++xpos)
82  {
83  m_pxpos=(( xpos-m_node.Xp() )>>1)+m_pnode.Xp();
84 
85  m_nhood_nonzero = false;
86  if (ypos > m_node.Yp())
87  m_nhood_nonzero |= bool(in_data[ypos-1][xpos]);
88  if (xpos > m_node.Xp())
89  m_nhood_nonzero |= bool(in_data[ypos][xpos-1]);
90  if (ypos > m_node.Yp() && xpos > m_node.Xp())
91  m_nhood_nonzero |= bool(in_data[ypos-1][xpos-1]);
92 
93  if (has_parent)
94  m_parent_notzero = static_cast<bool> ( in_data[m_pypos][m_pxpos] );
95  else
96  m_parent_notzero = false;
97 
98  CodeCoeff( in_data , xpos , ypos );
99 
100  }// xpos
101  }// ypos
102 
103 }
104 
105 template<typename EntropyCodec>
106 void GenericBandCodec<EntropyCodec>::CodeCoeff( CoeffArray& in_data, const int xpos, const int ypos)
107 {
108  CodeVal( in_data , xpos , ypos , in_data[ypos][xpos] );
109 }
110 
111 
112 /*
113 Coefficient magnitude value and differential quantiser index magnitude are
114 coded using interleaved exp-Golomb coding for binarisation. In this scheme, a
115 value N>=0 is coded by writing N+1 in binary form of a 1 followed by K other
116 bits: 1bbbbbbb (adding 1 ensures there'll be a leading 1). These K bits ("info
117 bits") are interleaved with K zeroes ("follow bits") each of which means
118 "another bit coming", followed by a terminating 1:
119 
120  0b0b0b ...0b1
121 
122 (Conventional exp-Golomb coding has the K zeroes at the beginning, followed
123 by the 1 i.e 00...01bb .. b, but interleaving allows the decoder to run a
124 single loop and avoid counting the number of zeroes, sparing a register.)
125 
126 All bits are arithmetically coded. The follow bits have separate contexts
127 based on position, and have different contexts from the info bits.
128 */
129 
130 template<typename EntropyCodec>
132  const int xpos ,
133  const int ypos ,
134  const CoeffType val )
135 {
136  unsigned int abs_val( std::abs(val) );
137  abs_val <<= 2;
138  abs_val /= m_qf;
139 
140  const int N = abs_val+1;
141  int num_follow_zeroes=0;
142 
143  while ( N >= (1<<num_follow_zeroes) )
144  ++num_follow_zeroes;
145  --num_follow_zeroes;
146 
147  for ( int i=num_follow_zeroes-1, c=1; i>=0; --i, ++c )
148  {
149  EntropyCodec::EncodeSymbol( 0, ChooseFollowContext( c ) );
150  EntropyCodec::EncodeSymbol( N&(1<<i), ChooseInfoContext() );
151  }
152  EntropyCodec::EncodeSymbol( 1, ChooseFollowContext( num_follow_zeroes+1 ) );
153 
154  in_data[ypos][xpos] = static_cast<CoeffType>( abs_val );
155 
156  if ( abs_val )
157  {
158  // Must code sign bits and reconstruct
159  in_data[ypos][xpos] *= m_qf;
160  in_data[ypos][xpos] += m_offset+2;
161  in_data[ypos][xpos] >>= 2;
162 
163  if ( val>0 )
164  {
165  EntropyCodec::EncodeSymbol( 0 , ChooseSignContext( in_data , xpos , ypos ) );
166  }
167  else
168  {
169  EntropyCodec::EncodeSymbol( 1 , ChooseSignContext( in_data , xpos , ypos ) );
170  in_data[ypos][xpos] = -in_data[ypos][xpos];
171  }
172  }
173 }
174 
175 template<typename EntropyCodec>
177 {
178 
179  const int abs_val = std::abs( offset );
180 
181  int N = abs_val+1;
182  int num_follow_zeroes=0;
183 
184  while ( N>= (1<<num_follow_zeroes) )
185  ++num_follow_zeroes;
186  --num_follow_zeroes;
187 
188  for ( int i=num_follow_zeroes-1, c=1; i>=0; --i, ++c )
189  {
190  EntropyCodec::EncodeSymbol( 0 , Q_OFFSET_FOLLOW_CTX );
191  EntropyCodec::EncodeSymbol( N&(1<<i), Q_OFFSET_INFO_CTX );
192  }
193  EntropyCodec::EncodeSymbol( 1 , Q_OFFSET_FOLLOW_CTX );
194 
195  if ( abs_val )
196  {
197  if ( offset>0 )
198  EntropyCodec::EncodeSymbol( 0 , Q_OFFSET_SIGN_CTX );
199  else
200  EntropyCodec::EncodeSymbol( 1 , Q_OFFSET_SIGN_CTX );
201  }
202 }
203 
204 template<typename EntropyCodec>
206 {
207  const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
208 
209  // coeff blocks can be skipped only if SpatialPartitioning is
210  // enabled i.e. more than one code-block per subband
211  bool decode_skip= (block_list.LengthX() > 1 || block_list.LengthY() > 1);
212  // Now loop over the blocks and decode
213  for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
214  {
215  CodeBlock *block = block_list[j];
216  for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
217  {
218  if (decode_skip)
219  block[i].SetSkip( EntropyCodec::DecodeSymbol( BLOCK_SKIP_CTX ) );
220  if ( !block[i].Skipped() )
221  DecodeCoeffBlock( block[i] , out_data );
222  else
223  ClearBlock (block[i] , out_data);
224 
225  }// i
226  }// j
227 
228 }
229 
230 template<typename EntropyCodec>
232 {
233 
234 
235  const int xbeg = code_block.Xstart();
236  const int ybeg = code_block.Ystart();
237  const int xend = code_block.Xend();
238  const int yend = code_block.Yend();
239 
240  int qf_idx = m_node.QuantIndex();
241 
242  bool has_parent = m_node.Parent() != 0;
243 
244  if ( m_node.UsingMultiQuants() )
245  {
246  qf_idx = m_last_qf_idx+DecodeQuantIndexOffset();
247  m_last_qf_idx = qf_idx;
248  }
249 
250  if (qf_idx > (int)dirac_quantiser_lists.MaxQuantIndex())
251  {
252  std::ostringstream errstr;
253  errstr << "Quantiser index out of range [0.."
254  << (int)dirac_quantiser_lists.MaxQuantIndex() << "]";
257  errstr.str(),
259  }
260 
261  m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
262 
263  if (m_is_intra)
264  m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
265  else
266  m_offset = dirac_quantiser_lists.InterQuantOffset4( qf_idx );
267 
268  //Work
269 
270  for ( int ypos=ybeg; ypos<yend ;++ypos)
271  {
272  m_pypos=(( ypos-m_node.Yp() )>>1)+m_pnode.Yp();
273  CoeffType *p_out_data = NULL;
274  if (has_parent)
275  p_out_data = out_data[m_pypos];
276  CoeffType *c_out_data_1 = NULL;
277  if (ypos!=m_node.Yp())
278  c_out_data_1 = out_data[ypos-1];
279  CoeffType *c_out_data_2 = out_data[ypos];
280  for ( int xpos=xbeg; xpos<xend ;++xpos)
281  {
282  m_pxpos=(( xpos-m_node.Xp() )>>1)+m_pnode.Xp();
283 
284  m_nhood_nonzero = false;
285  /* c_out_data_1 is the line above the current
286  * c_out_data_2 is the current line */
287  if (ypos > m_node.Yp())
288  m_nhood_nonzero |= bool(c_out_data_1[xpos]);
289  if (xpos > m_node.Xp())
290  m_nhood_nonzero |= bool(c_out_data_2[xpos-1]);
291  if (ypos > m_node.Yp() && xpos > m_node.Xp())
292  m_nhood_nonzero |= bool(c_out_data_1[xpos-1]);
293 
294  if (has_parent)
295  m_parent_notzero = ( p_out_data[m_pxpos] != 0 );
296  else
297  m_parent_notzero = false;
298 
299  DecodeCoeff( out_data , xpos , ypos );
300 
301  }// xpos
302  }// ypos
303 }
304 
305 template<typename EntropyCodec>
306 void GenericBandCodec<EntropyCodec>::DecodeCoeff( CoeffArray& in_data, const int xpos, const int ypos)
307 {
308  DecodeVal( in_data , xpos , ypos );
309 }
310 
311 
312 /*
313 Coefficient magnitude value and differential quantiser index value is coded
314 using interleaved exp-Golomb coding for binarisation. In this scheme, a value
315 N>=0 is coded by writing N+1 in binary form of a 1 followed by K other bits:
316 1bbbbbbb (adding 1 ensures there'll be a leading 1). These K bits ("info bits")
317 are interleaved with K zeroes ("follow bits") each of which means "another bit
318 coming", followed by a terminating 1:
319 
320  0b0b0b ...0b1
321 
322 (Conventional exp-Golomb coding has the K zeroes at the beginning, followed
323 by the 1 i.e 00...01bb .. b, but interleaving allows the decoder to run a
324 single loop and avoid counting the number of zeroes, sparing a register.)
325 
326 All bits are arithmetically coded. The follow bits have separate contexts
327 based on position, and have different contexts from the info bits.
328 */
329 template<typename EntropyCodec>
330 inline void GenericBandCodec<EntropyCodec>::DecodeVal( CoeffArray& out_data , const int xpos , const int ypos )
331 {
332 
333  CoeffType& out_pixel = out_data[ypos][xpos];
334 
335  out_pixel = 1;
336  int bit_count=1;
337 
338  while ( !EntropyCodec::DecodeSymbol( ChooseFollowContext( bit_count ) ) )
339  {
340  out_pixel <<= 1;
341  out_pixel |= EntropyCodec::DecodeSymbol( ChooseInfoContext() );
342  bit_count++;
343  };
344  --out_pixel;
345 
346  if ( out_pixel )
347  {
348  out_pixel *= m_qf;
349  out_pixel += m_offset+2;
350  out_pixel >>= 2;
351 
352  if ( EntropyCodec::DecodeSymbol( ChooseSignContext(out_data, xpos, ypos)) )
353  out_pixel = -out_pixel;
354  }
355 }
356 
357 template<typename EntropyCodec>
358 inline int GenericBandCodec<EntropyCodec>::ChooseFollowContext( const int bin_number ) const
359 {
360  //condition on neighbouring values and parent values
361 
362  if (!m_parent_notzero)
363  {
364  switch ( bin_number )
365  {
366  case 1 :
367  if(m_nhood_nonzero == false)
368  return Z_FBIN1z_CTX;
369 
370  return Z_FBIN1nz_CTX;
371 
372  case 2 :
373  return Z_FBIN2_CTX;
374  case 3 :
375  return Z_FBIN3_CTX;
376  case 4 :
377  return Z_FBIN4_CTX;
378  case 5 :
379  return Z_FBIN5_CTX;
380  default :
381  return Z_FBIN6plus_CTX;
382  }
383  }
384  else
385  {
386  switch ( bin_number )
387  {
388  case 1 :
389  if(m_nhood_nonzero == false)
390  return NZ_FBIN1z_CTX;
391 
392  return NZ_FBIN1nz_CTX;
393 
394  case 2 :
395  return NZ_FBIN2_CTX;
396  case 3 :
397  return NZ_FBIN3_CTX;
398  case 4 :
399  return NZ_FBIN4_CTX;
400  case 5 :
401  return NZ_FBIN5_CTX;
402  default :
403  return NZ_FBIN6plus_CTX;
404  }
405 
406  }
407 
408  /* not reachable, but dumb compilers can't spot that */
409  return 0;
410 }
411 
412 template<typename EntropyCodec>
414 {
415  return INFO_CTX;
416 }
417 
418 template<typename EntropyCodec>
419 inline int GenericBandCodec<EntropyCodec>::ChooseSignContext( const CoeffArray& data , const int xpos , const int ypos ) const
420 {
421  if ( m_node.Yp()==0 && m_node.Xp()!=0 )
422  {
423  //we're in a vertically oriented subband
424  if (ypos == 0)
425  return SIGN0_CTX;
426  else
427  {
428  if (data[ypos-1][xpos]>0)
429  return SIGN_POS_CTX;
430  else if (data[ypos-1][xpos]<0)
431  return SIGN_NEG_CTX;
432  else
433  return SIGN0_CTX;
434  }
435  }
436  else if ( m_node.Xp()==0 && m_node.Yp()!=0 )
437  {
438  //we're in a horizontally oriented subband
439  if (xpos == 0)
440  return SIGN0_CTX;
441  else
442  {
443  if ( data[ypos][xpos-1] > 0 )
444  return SIGN_POS_CTX;
445  else if ( data[ypos][xpos-1] < 0 )
446  return SIGN_NEG_CTX;
447  else
448  return SIGN0_CTX;
449  }
450  }
451  else
452  return SIGN0_CTX;
453 }
454 
455 template<typename EntropyCodec>
457 {
458  int offset = 1;
459 
460  while ( !EntropyCodec::DecodeSymbol( Q_OFFSET_FOLLOW_CTX ) )
461  {
462  offset <<= 1;
463  offset |= EntropyCodec::DecodeSymbol( Q_OFFSET_INFO_CTX );
464  }
465  --offset;
466 
467  if ( offset )
468  {
469  if ( EntropyCodec::DecodeSymbol( Q_OFFSET_SIGN_CTX ) )
470  offset = -offset;
471  }
472  return offset;
473 }
474 
475 template<typename EntropyCodec>
476 void GenericBandCodec<EntropyCodec>::SetToVal( const CodeBlock& code_block , CoeffArray& pic_data , const CoeffType val)
477 {
478  for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
479  {
480  for (int i=code_block.Xstart() ; i<code_block.Xend() ; i++)
481  {
482  pic_data[j][i] = val;
483  }// i
484  }// j
485 }
486 
487 template<typename EntropyCodec>
489 {
490  for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
491  {
492  CoeffType *pic = &coeff_data[j][code_block.Xstart()];
493  memset (pic, 0, (code_block.Xend()-code_block.Xstart())*sizeof(CoeffType));
494  }// j
495 
496 }
497 
498 /* Decode a single coefficient using error-feedback DC quantization */
499 template<typename EntropyCodec>
501 {
503  /* do prediction for this block */
504  for ( int ypos=code_block.Ystart() ; ypos<code_block.Yend() ; ++ypos)
505  {
506  for ( int xpos=code_block.Xstart() ; xpos<code_block.Xend() ; ++xpos)
507  {
508  out_data[ypos][xpos] += GetPrediction( out_data , xpos , ypos );
509  }
510  }
511 }
512 
513 /* after coding a skipped DC codeblock, reconstruct in_data by predicting the values
514  * and not adding any error term (they were all skipped). This is required to correctly
515  * predict the values in the next codeblock */
516 
517 template<typename EntropyCodec>
519 {
520  for (int ypos=code_block.Ystart() ; ypos<code_block.Yend() ; ++ypos)
521  {
522  for (int xpos=code_block.Xstart() ; xpos<code_block.Xend() ; ++xpos)
523  {
524  /* NB, it is correct to overwrite the old value */
525  coeff_data[ypos][xpos] = GetPrediction( coeff_data , xpos , ypos );
526  } // i
527  } // j
528 }
529 
530 template<typename EntropyCodec>
531 CoeffType GenericIntraDCBandCodec<EntropyCodec>::GetPrediction( const CoeffArray& data , const int xpos , const int ypos ) const
532 {
533  /* NB, 4.5.3 integer division
534  * numbers are rounded down towards -ve infinity, differing from
535  * C's convention that rounds towards 0
536  */
537  if (ypos!=0)
538  {
539  if (xpos!=0)
540  {
541  int sum = data[ypos][xpos-1] + data[ypos-1][xpos-1] + data[ypos-1][xpos] + 3/2;
542  if (sum<0)
543  return (sum-2)/3;
544  else
545  return sum/3;
546  }
547  else
548  return data[ypos - 1][0];
549  }
550  else
551  {
552  if(xpos!=0)
553  return data[0][xpos - 1];
554  else
555  return 0;
556  }
557 }

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