Updating Contact email
[BrunelResearch-dirac.git] / libdirac_common / band_vlc.cpp
blobe4ea497d420edc2bb9abd1690156066af719f081
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id$ $Name$
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License
8 * Version 1.1 (the "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14 * the specific language governing rights and limitations under the License.
16 * The Original Code is BBC Research and Development code.
18 * The Initial Developer of the Original Code is the British Broadcasting
19 * Corporation.
20 * Portions created by the Initial Developer are Copyright (c) 2004.
21 * All Rights Reserved.
23 * Contributor(s): Anuradha Suraparaju (Original Author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
27 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
28 * the GPL or the LGPL are applicable instead of those above. If you wish to
29 * allow use of your version of this file only under the terms of the either
30 * the GPL or LGPL and not to allow others to use your version of this file
31 * under the MPL, indicate your decision by deleting the provisions above
32 * and replace them with the notice and other provisions required by the GPL
33 * or LGPL. If you do not delete the provisions above, a recipient may use
34 * your version of this file under the terms of any one of the MPL, the GPL
35 * or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 // System includes
39 #include <sstream>
41 // Dirac includes
42 #include <libdirac_common/band_vlc.h>
43 #include <libdirac_byteio/subband_byteio.h>
44 #include <libdirac_common/dirac_exception.h>
46 using namespace dirac;
48 // Constructor for encoding
49 BandVLC::BandVLC( SubbandByteIO* subband_byteio,
50 const SubbandList& band_list,
51 int band_num,
52 const bool is_intra) :
53 m_is_intra(is_intra),
54 m_bnum(band_num),
55 m_node(band_list(band_num)),
56 m_last_qf_idx(m_node.QuantIndex()),
57 m_byteio(subband_byteio)
61 // encoding functions
62 int BandVLC::Compress(CoeffArray &in_data)
64 DoWorkCode(in_data);
65 return m_byteio->GetSize();
68 void BandVLC::DoWorkCode(CoeffArray &in_data)
70 const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
71 // coeff blocks can be skipped only if SpatialPartitioning is
72 // enabled i.e. more than one code-block per subband
73 bool code_skip = (block_list.LengthX() > 1 || block_list.LengthY() > 1);
75 for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
77 CodeBlock *block = block_list[j];
78 for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
80 if (code_skip)
81 m_byteio->WriteBit(block[i].Skipped()); // encode skip flag
82 if ( !block[i].Skipped() )
84 CodeCoeffBlock( block[i] , in_data );
86 else
88 ClearBlock (block[i] , in_data);
90 }// i
91 }// j
94 void BandVLC::CodeCoeffBlock(const CodeBlock& code_block , CoeffArray& in_data)
96 //main coding function, using binarisation
98 const int xbeg = code_block.Xstart();
99 const int ybeg = code_block.Ystart();
100 const int xend = code_block.Xend();
101 const int yend = code_block.Yend();
103 const int qf_idx = code_block.QuantIndex();
105 if ( m_node.UsingMultiQuants() )
107 CodeQuantIndexOffset( qf_idx - m_last_qf_idx);
108 m_last_qf_idx = qf_idx;
111 m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
112 if (m_is_intra)
113 m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
114 else
115 m_offset = dirac_quantiser_lists.InterQuantOffset4( qf_idx );
117 for ( int ypos=ybeg; ypos<yend ;++ypos)
119 for ( int xpos=xbeg; xpos<xend ;++xpos)
121 CodeVal( in_data , xpos , ypos , in_data[ypos][xpos] );
122 }// xpos
123 }// ypos
127 void BandVLC::CodeQuantIndexOffset( const int offset )
129 m_byteio->WriteSint(offset);
132 inline void BandVLC::CodeVal( CoeffArray& in_data ,
133 const int xpos ,
134 const int ypos ,
135 const CoeffType val )
137 int qval( std::abs(val) );
138 qval <<= 2;
139 qval /= m_qf;
140 in_data[ypos][xpos] = static_cast<CoeffType>( qval );
142 // Code the quantised value into the bitstream
143 if (val < 0)
144 qval = -qval;
145 m_byteio->WriteSint(qval);
147 if (qval)
149 // Reconstruct
150 in_data[ypos][xpos] *= m_qf;
151 in_data[ypos][xpos] += m_offset+2;
152 in_data[ypos][xpos] >>= 2;
153 if (val < 0)
154 in_data[ypos][xpos] = -in_data[ypos][xpos];
161 // decoding functions
162 void BandVLC::Decompress(CoeffArray &out_data, int num_bytes)
164 m_byteio->SetBitsLeft(num_bytes * 8);
165 DoWorkDecode(out_data);
166 m_byteio->FlushInputB();
169 void BandVLC::DoWorkDecode(CoeffArray& out_data)
171 const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
173 // coeff blocks can be skipped only if SpatialPartitioning is
174 // enabled i.e. more than one code-block per subband
175 bool decode_skip= (block_list.LengthX() > 1 || block_list.LengthY() > 1);
176 // Now loop over the blocks and decode
177 for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
179 CodeBlock *block = block_list[j];
180 for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
182 if (decode_skip)
183 block[i].SetSkip( m_byteio->ReadBoolB() );
184 if ( !block[i].Skipped() )
186 DecodeCoeffBlock( block[i] , out_data );
188 else
190 ClearBlock (block[i] , out_data);
193 }// i
194 }// j
197 void BandVLC::DecodeCoeffBlock(const CodeBlock& code_block , CoeffArray& out_data)
199 const int xbeg = code_block.Xstart();
200 const int ybeg = code_block.Ystart();
201 const int xend = code_block.Xend();
202 const int yend = code_block.Yend();
204 int qf_idx = m_node.QuantIndex();
206 if ( m_node.UsingMultiQuants() )
208 qf_idx = m_last_qf_idx+DecodeQuantIndexOffset();
209 m_last_qf_idx = qf_idx;
212 if (qf_idx > (int)dirac_quantiser_lists.MaxQuantIndex())
214 std::ostringstream errstr;
215 errstr << "Quantiser index out of range [0.."
216 << (int)dirac_quantiser_lists.MaxQuantIndex() << "]";
217 DIRAC_THROW_EXCEPTION(
218 ERR_UNSUPPORTED_STREAM_DATA,
219 errstr.str(),
220 SEVERITY_PICTURE_ERROR);
223 m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
225 if (m_is_intra)
226 m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
227 else
228 m_offset = dirac_quantiser_lists.InterQuantOffset4( qf_idx );
230 //Work
232 for ( int ypos=ybeg; ypos<yend ;++ypos)
234 for ( int xpos=xbeg; xpos<xend ;++xpos)
236 DecodeVal( out_data , xpos , ypos );
237 }// xpos
238 }// ypos
241 int BandVLC::DecodeQuantIndexOffset( )
243 return m_byteio->ReadSintB();
246 inline void BandVLC::DecodeVal( CoeffArray& out_data , const int xpos , const int ypos )
248 // Read quantised coefs
249 int quant_coeff = m_byteio->ReadSintB();
250 CoeffType& out_pixel = out_data[ypos][xpos];
252 // Reconstruct
253 out_pixel = std::abs(quant_coeff);
254 if ( out_pixel )
256 out_pixel *= m_qf;
257 out_pixel += m_offset+2;
258 out_pixel >>= 2;
260 if ( quant_coeff < 0)
261 out_pixel = -out_pixel;
265 // general purpose functions
266 void BandVLC::ClearBlock( const CodeBlock& code_block , CoeffArray& coeff_data)
268 for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
270 CoeffType *pic = &coeff_data[j][code_block.Xstart()];
271 memset (pic, 0, (code_block.Xend()-code_block.Xstart())*sizeof(CoeffType));
272 }// j
276 void BandVLC::SetToVal( const CodeBlock& code_block , CoeffArray& pic_data , const CoeffType val)
278 for (int j=code_block.Ystart() ; j<code_block.Yend() ; j++)
280 for (int i=code_block.Xstart() ; i<code_block.Xend() ; i++)
282 pic_data[j][i] = val;
283 }// i
284 }// j
287 //////////////////////////////////////////////////////////////////////////////////
288 //Finally,special class incorporating prediction for the DC band of intra frames//
289 //////////////////////////////////////////////////////////////////////////////////
291 void IntraDCBandVLC::DoWorkCode(CoeffArray& in_data)
293 const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
295 // Now loop over the blocks and code. Note that DC blocks can't be skipped
296 for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
298 for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
300 CodeCoeffBlock( block_list[j][i] , in_data );
301 }// i
302 }// j
305 void IntraDCBandVLC::CodeCoeffBlock( const CodeBlock& code_block , CoeffArray& in_data)
307 // Main coding function, using binarisation
308 const int xbeg = code_block.Xstart();
309 const int ybeg = code_block.Ystart();
310 const int xend = code_block.Xend();
311 const int yend = code_block.Yend();
313 CoeffType val;
315 CoeffType prediction;
317 const int qf_idx = code_block.QuantIndex();
319 if ( m_node.UsingMultiQuants() )
321 CodeQuantIndexOffset( qf_idx - m_last_qf_idx);
322 m_last_qf_idx = qf_idx;
325 m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
327 m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
329 for ( int ypos=ybeg ; ypos < yend; ++ypos )
331 for (int xpos = xbeg ; xpos < xend; ++xpos )
333 prediction = GetPrediction( in_data , xpos , ypos );
334 val = in_data[ypos][xpos] - prediction;
335 CodeVal( in_data , xpos , ypos , val );
336 in_data[ypos][xpos] += prediction;
337 }//xpos
338 }//ypos
342 void IntraDCBandVLC::DoWorkDecode(CoeffArray& out_data)
344 const TwoDArray<CodeBlock>& block_list( m_node.GetCodeBlocks() );
346 // coeff blocks can be skipped only if SpatialPartitioning is
347 // enabled i.e. more than one code-block per subband
348 bool decode_skip= (block_list.LengthX() > 1 || block_list.LengthY() > 1);
350 // Now loop over the blocks and decode
351 for (int j=block_list.FirstY() ; j<=block_list.LastY() ; ++j)
353 for (int i=block_list.FirstX() ; i<=block_list.LastX() ; ++i)
355 if (decode_skip)
356 block_list[j][i].SetSkip( m_byteio->ReadBoolB() );
358 if ( !block_list[j][i].Skipped() )
359 DecodeCoeffBlock( block_list[j][i] , out_data );
360 else
361 ClearBlock( block_list[j][i] , out_data);
363 DCPrediction( block_list[j][i], out_data);
364 }// i
365 }// j
368 void IntraDCBandVLC::DecodeCoeffBlock( const CodeBlock& code_block , CoeffArray& out_data)
370 const int xbeg = code_block.Xstart();
371 const int ybeg = code_block.Ystart();
372 const int xend = code_block.Xend();
373 const int yend = code_block.Yend();
375 int qf_idx = m_node.QuantIndex();
377 if ( m_node.UsingMultiQuants() )
379 qf_idx = DecodeQuantIndexOffset()+m_last_qf_idx;
380 m_last_qf_idx = qf_idx;
383 m_qf = dirac_quantiser_lists.QuantFactor4( qf_idx );
385 m_offset = dirac_quantiser_lists.IntraQuantOffset4( qf_idx );
387 //Work
389 for ( int ypos=ybeg ; ypos<yend ; ++ypos)
391 for ( int xpos=xbeg ; xpos<xend ; ++xpos)
393 DecodeVal( out_data , xpos , ypos );
394 }//xpos
395 }//ypos
398 void IntraDCBandVLC::DCPrediction( const CodeBlock& code_block , CoeffArray& out_data)
400 const int xbeg = code_block.Xstart();
401 const int ybeg = code_block.Ystart();
402 const int xend = code_block.Xend();
403 const int yend = code_block.Yend();
405 for ( int ypos=ybeg ; ypos<yend ; ++ypos)
407 for ( int xpos=xbeg ; xpos<xend ; ++xpos)
409 out_data[ypos][xpos] += GetPrediction( out_data , xpos , ypos );
410 }//xpos
411 }//ypos
415 CoeffType IntraDCBandVLC::GetPrediction( const CoeffArray& data , const int xpos , const int ypos ) const
417 /* NB, 4.5.3 integer division
418 * numbers are rounded down towards -ve infinity, differing from
419 * C's convention that rounds towards 0
422 if (ypos!=0)
424 if (xpos!=0)
426 int sum = data[ypos][xpos-1] + data[ypos-1][xpos-1] + data[ypos-1][xpos] + 3/2;
427 if (sum<0)
428 return (sum-2)/3;
429 else
430 return sum/3;
432 else
433 return data[ypos - 1][0];
435 else
437 if(xpos!=0)
438 return data[0][xpos - 1];
439 else
440 return 0;