Updating Contact email
[BrunelResearch-dirac.git] / libdirac_encoder / picture_compress.cpp
blobff6e2ffd2a8cde8c1f71b02d2a4255f0a8f7f394
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): Thomas Davies (Original Author),
24 * Scott R Ladd,
25 * Chris Bowley,
26 * Anuradha Suraparaju,
27 * Tim Borer,
28 * Andrew Kennedy
30 * Alternatively, the contents of this file may be used under the terms of
31 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
32 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
33 * the GPL or the LGPL are applicable instead of those above. If you wish to
34 * allow use of your version of this file only under the terms of the either
35 * the GPL or LGPL and not to allow others to use your version of this file
36 * under the MPL, indicate your decision by deleting the provisions above
37 * and replace them with the notice and other provisions required by the GPL
38 * or LGPL. If you do not delete the provisions above, a recipient may use
39 * your version of this file under the terms of any one of the MPL, the GPL
40 * or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 //Compression of pictures//
44 /////////////////////////
46 #include <libdirac_encoder/picture_compress.h>
47 #include <libdirac_encoder/comp_compress.h>
48 #include <libdirac_encoder/prefilter.h>
49 #include <libdirac_common/mot_comp.h>
50 #include <libdirac_motionest/pixel_match.h>
51 #include <libdirac_motionest/me_subpel.h>
52 #include <libdirac_motionest/me_mode_decn.h>
53 #include <libdirac_common/mv_codec.h>
54 #include <libdirac_encoder/quant_chooser.h>
55 #include <libdirac_common/dirac_assertions.h>
56 using namespace dirac;
58 #include <iostream>
59 #include <sstream>
61 PictureCompressor::PictureCompressor( EncoderParams& encp ) :
62 m_encparams(encp),
63 m_skipped(false),
64 m_use_global(false),
65 m_use_block_mv(true),
66 m_global_pred_mode(REF1_ONLY),
67 m_me_data(NULL),
68 m_medata_avail(false),
69 m_is_a_cut(false)
72 PictureCompressor::~PictureCompressor()
76 void PictureCompressor::PixelME( EncQueue& my_buffer , int pnum )
78 PixelMatcher pix_match( m_encparams );
79 pix_match.DoSearch( my_buffer , pnum );
82 void PictureCompressor::CalcComplexity( EncQueue& my_buffer, int pnum , const OLBParams& olbparams )
84 EncPicture& my_picture = my_buffer.GetPicture( pnum );
85 PictureParams& pparams = my_picture.GetPparams();
87 if ( (my_picture.GetStatus()&DONE_PEL_ME) != 0 ){
88 MEData& me_data = my_picture.GetMEData();
90 TwoDArray<MvCostData>* pcosts1;
91 TwoDArray<MvCostData>* pcosts2;
93 pcosts1 = &me_data.PredCosts(1);
94 if (pparams.NumRefs()>1)
95 pcosts2 = &me_data.PredCosts(2);
96 else
97 pcosts2 = pcosts1;
99 float cost1, cost2, cost;
100 double total_cost1 = 0.0;
101 double total_cost2 = 0.0;
102 double total_cost = 0.0;
104 int count1=0;int count=0;
106 float cost_threshold = float(olbparams.Xblen()*olbparams.Yblen()*10);
108 for (int j=4; j<pcosts1->LengthY()-4; ++j){
109 for (int i=4; i<pcosts1->LengthX()-4; ++i){
110 cost1 = (*pcosts1)[j][i].SAD;
111 cost2 = (*pcosts2)[j][i].SAD;
112 cost = std::min(cost1, cost2);
113 total_cost1 += cost1;
114 total_cost2 += cost2;
115 total_cost += cost;
116 if (pparams.NumRefs()>1 && cost<=cost_threshold){
117 ++count;
118 if (cost1<=cost2)
119 ++count1;
124 total_cost1 *= olbparams.Xbsep()*olbparams.Ybsep();
125 total_cost1 /= olbparams.Xblen()*olbparams.Yblen();
127 total_cost2 *= olbparams.Xbsep()*olbparams.Ybsep();
128 total_cost2 /= olbparams.Xblen()*olbparams.Yblen();
130 if (pparams.NumRefs()>1){
131 my_picture.SetPredBias(float(count1)/float(count));
133 else
134 my_picture.SetPredBias(0.5);
136 total_cost *= olbparams.Xbsep()*olbparams.Ybsep();
137 total_cost /= olbparams.Xblen()*olbparams.Yblen();
139 // my_picture.SetComplexity( total_cost );
140 my_picture.SetComplexity( total_cost*total_cost );
146 void PictureCompressor::CalcComplexity2( EncQueue& my_buffer, int pnum )
148 // to be used after doing motion compensation
149 EncPicture& my_picture = my_buffer.GetPicture( pnum );
150 const PicArray& pic_data = my_picture.Data( Y_COMP );
152 if ( (my_picture.GetStatus()&DONE_MC) != 0 ){
154 float cost;
155 double total_sq_cost = 0.0;
156 double total_cost = 0.0;
158 for (int j=0; j<pic_data.LengthY(); ++j){
159 for (int i=0; i<pic_data.LengthX(); ++i){
160 cost = float( pic_data[j][i] );
161 total_cost += cost;
162 total_sq_cost += cost*cost;
167 total_cost /= ( pic_data.LengthX()*pic_data.LengthY() );
168 total_sq_cost /= ( pic_data.LengthX()*pic_data.LengthY() );
170 my_picture.SetComplexity( total_sq_cost - total_cost*total_cost );
178 void PictureCompressor::NormaliseComplexity( EncQueue& my_buffer, int pnum )
180 EncPicture& my_picture = my_buffer.GetPicture( pnum );
182 if ( (my_picture.GetStatus()&DONE_PIC_COMPLEXITY) != 0 ){
184 std::vector<int> queue_members = my_buffer.Members();
186 double mean_complexity = 0.0;
187 int count = 0;
188 for (size_t i=0; i<queue_members.size(); ++ i){
189 int n = queue_members[i];
190 EncPicture& enc_pic = my_buffer.GetPicture( n );
192 if ( (enc_pic.GetStatus()&DONE_PIC_COMPLEXITY) != 0
193 && enc_pic.GetPparams().PicSort().IsInter()
194 && n >= pnum - 10
195 && n <= pnum + 10){
196 mean_complexity += enc_pic.GetComplexity();
197 count++;
201 mean_complexity /= count;
202 my_picture.SetNormComplexity( my_picture.GetComplexity() / mean_complexity );
208 void PictureCompressor::SubPixelME( EncQueue& my_buffer , int pnum )
210 const std::vector<int>& refs = my_buffer.GetPicture(pnum).GetPparams().Refs();
211 const int num_refs = refs.size();
213 PictureParams& pparams = my_buffer.GetPicture(pnum).GetPparams();
214 MEData& me_data = my_buffer.GetPicture(pnum).GetMEData();
215 PicturePredParams& predparams = me_data.GetPicPredParams();
217 float lambda;
218 if ( pparams.IsBPicture())
219 lambda = m_encparams.L2MELambda();
220 else
221 lambda = m_encparams.L1MELambda();
223 //lambda *= my_buffer.GetPicture(pnum).GetNormComplexity();
225 // Set up the lambda to be used
226 me_data.SetLambdaMap( num_refs , lambda );
228 m_orig_prec = predparams.MVPrecision();
230 // Step 2.
231 // Pixel accurate vectors are then refined to sub-pixel accuracy
233 if (m_orig_prec != MV_PRECISION_PIXEL)
235 SubpelRefine pelrefine( m_encparams );
236 pelrefine.DoSubpel( my_buffer , pnum );
238 else
240 // FIXME: HACK HACK
241 // Mutiplying the motion vectors by 2 and setting MV precision to
242 // HALF_PIXEL to implement pixel accurate motion estimate
243 MvArray &mv_arr1 = me_data.Vectors(1);
244 for (int j = 0; j < mv_arr1.LengthY(); ++j)
246 for (int i = 0; i < mv_arr1.LengthX(); ++i)
247 mv_arr1[j][i] = mv_arr1[j][i] << 1;
249 if (num_refs > 1)
251 MvArray &mv_arr2 = me_data.Vectors(2);
252 for (int j = 0; j < mv_arr2.LengthY(); ++j)
254 for (int i = 0; i < mv_arr2.LengthX(); ++i)
255 mv_arr2[j][i] = mv_arr2[j][i] << 1;
258 predparams.SetMVPrecision(MV_PRECISION_HALF_PIXEL);
263 void PictureCompressor::ModeDecisionME( EncQueue& my_buffer, int pnum )
265 MEData& me_data = my_buffer.GetPicture(pnum).GetMEData();
266 PictureParams& pparams = my_buffer.GetPicture(pnum).GetPparams();
267 PicturePredParams& predparams = me_data.GetPicPredParams();
269 ModeDecider my_mode_dec( m_encparams );
270 my_mode_dec.DoModeDecn( my_buffer , pnum );
272 const int num_refs = pparams.NumRefs();
274 if (m_orig_prec == MV_PRECISION_PIXEL)
276 // FIXME: HACK HACK
277 // Divide the motion vectors by 2 to convert back to pixel
278 // accurate motion vectors and reset MV precision to
279 // PIXEL accuracy
280 MvArray &mv_arr1 = me_data.Vectors(1);
281 for (int j = 0; j < mv_arr1.LengthY(); ++j)
283 for (int i = 0; i < mv_arr1.LengthX(); ++i)
284 mv_arr1[j][i] = mv_arr1[j][i] >> 1;
286 if (num_refs > 1)
288 MvArray &mv_arr2 = me_data.Vectors(2);
289 for (int j = 0; j < mv_arr2.LengthY(); ++j)
291 for (int i = 0; i < mv_arr2.LengthX(); ++i)
292 mv_arr2[j][i] = mv_arr2[j][i]>>1;
295 predparams.SetMVPrecision(MV_PRECISION_PIXEL);
300 void PictureCompressor::IntraModeAnalyse( EncQueue& my_buffer, int pnum )
302 MEData& me_data = my_buffer.GetPicture(pnum).GetMEData();
304 // Count the number of intra blocks
305 const TwoDArray<PredMode>& modes = me_data.Mode();
307 int count_intra = 0;
308 for ( int j=0 ; j<modes.LengthY() ; ++j )
310 for ( int i=0 ; i<modes.LengthX() ; ++i )
312 if ( modes[j][i] == INTRA )
313 count_intra++;
315 }// j
317 me_data.SetIntraBlockRatio(static_cast<double>( count_intra ) /
318 static_cast<double>( modes.LengthX() * modes.LengthY() ) );
322 void PictureCompressor::MotionCompensate( EncQueue& my_buffer, int pnum,
323 AddOrSub dirn )
325 EncPicture* my_pic = &my_buffer.GetPicture(pnum);
326 std::vector<int>& my_refs = my_pic->GetPparams().Refs();
327 Picture* ref_pics[2];
329 ref_pics[0]=&my_buffer.GetPicture(my_refs[0]);
330 if (my_refs.size()>1)
331 ref_pics[1]=&my_buffer.GetPicture(my_refs[1]);
332 else
333 ref_pics[1]=&my_buffer.GetPicture(my_refs[0]);
335 PicturePredParams& predparams = my_pic->GetMEData().GetPicPredParams();
336 MotionCompensator::CompensatePicture( predparams , dirn ,
337 my_pic->GetMEData() , my_pic, ref_pics );
340 void PictureCompressor::Prefilter( EncQueue& my_buffer, int pnum )
342 Picture& my_picture = my_buffer.GetPicture( pnum );
344 for (int c=0; c<3; ++c ){
345 if ( m_encparams.Prefilter() == RECTLP )
346 LPFilter( my_picture.Data( (CompSort) c) , m_encparams.Qf(),
347 m_encparams.PrefilterStrength() );
349 if ( m_encparams.Prefilter() == DIAGLP )
350 // DiagFilter( my_picture.Data( (CompSort) c), 3.0, 5 );
351 DiagFilter( my_picture.Data( (CompSort) c) , m_encparams.Qf(),
352 m_encparams.PrefilterStrength() );
357 void PictureCompressor::DoDWT( EncQueue& my_buffer , int pnum, Direction dirn )
359 Picture& my_picture = my_buffer.GetPicture( pnum );
360 PictureParams& pparams = my_picture.GetPparams();
361 const PictureSort& psort = pparams.PicSort();
363 // Set the wavelet filter
364 if ( psort.IsIntra() ){
365 m_encparams.SetTransformFilter( m_encparams.IntraTransformFilter() );
366 m_encparams.SetUsualCodeBlocks( INTRA_PICTURE );
368 else{
369 m_encparams.SetTransformFilter( m_encparams.InterTransformFilter() );
370 m_encparams.SetUsualCodeBlocks( INTER_PICTURE );
373 const int depth=m_encparams.TransformDepth();
374 const WltFilter filter = m_encparams.TransformFilter();
375 WaveletTransform wtransform( depth, filter );
377 if ( dirn==FORWARD )
378 my_picture.InitWltData( depth );
380 for (int c=0; c<3; ++c){
382 PicArray& comp_data = my_buffer.GetPicture( pnum ).Data((CompSort) c );
383 CoeffArray& coeff_data = my_buffer.GetPicture( pnum ).WltData((CompSort) c );
385 wtransform.Transform( dirn , comp_data, coeff_data );
391 void PictureCompressor::CodeResidue( EncQueue& my_buffer ,
392 int pnum, PictureByteIO* p_picture_byteio )
394 EncPicture& my_picture = my_buffer.GetPicture( pnum );
396 PictureParams& pparams = my_picture.GetPparams();
398 if ( !m_skipped ){
399 // If not skipped we continue with the coding ...
400 if (m_encparams.Verbose() )
401 std::cout<<std::endl<<"Using QF: "<<m_encparams.Qf();
403 //Write Transform Header
404 TransformByteIO *p_transform_byteio = new TransformByteIO(pparams,
405 static_cast<CodecParams&>(m_encparams));
406 p_picture_byteio->SetTransformData(p_transform_byteio);
407 p_transform_byteio->Output();
409 /* Code component data */
410 /////////////////////////
412 CompCompressor my_compcoder(m_encparams , pparams );
414 const int depth=m_encparams.TransformDepth();
416 PicArray* comp_data[3];
417 CoeffArray* coeff_data[3];
418 OneDArray<unsigned int>* est_bits[3];
419 float lambda[3];
421 // Construction and definition of objects
422 for (int c=0;c<3;++c){
423 comp_data[c] = &my_picture.Data((CompSort) c );
424 coeff_data[c] = &my_picture.WltData((CompSort) c );
425 est_bits[c] = new OneDArray<unsigned int>( Range( 1, 3*depth+1 ) );
426 }// c
428 /* Do the wavelet transforms and select the component
429 * quantisers using perceptual weighting
431 double cpd_scale;
432 if (pparams.PicSort().IsIntra() ){
433 cpd_scale = 1.0;
435 else{
436 float intra_ratio = my_picture.GetMEData().IntraBlockRatio();
438 cpd_scale = 5.0*intra_ratio*1.0 + (1.0-5.0*intra_ratio)*0.125;
439 cpd_scale = std::max( 0.125, std::min( 1.2, cpd_scale ) );
441 for (int c=0; c<3; ++c){
442 lambda[c] = GetCompLambda( my_picture, (CompSort) c );
444 coeff_data[c]->SetBandWeights( m_encparams , pparams, (CompSort) c, cpd_scale);
446 SubbandList& bands = coeff_data[c]->BandList();
447 SetupCodeBlocks( bands );
448 SelectQuantisers( *(coeff_data[c]) , bands , lambda[c],
449 *est_bits[c] , m_encparams.GetCodeBlockMode(), pparams, (CompSort) c );
451 p_transform_byteio->AddComponent( my_compcoder.Compress(
452 *(coeff_data[c]), bands, (CompSort) c, *est_bits[c] ) );
455 // Destruction of objects
456 for (int c=0; c<3; ++c)
457 delete est_bits[c];
459 }//?m_skipped
463 void PictureCompressor::CodeMVData(EncQueue& my_buffer, int pnum, PictureByteIO* pic_byteio)
466 // Code the MV data
468 EncPicture& my_picture = my_buffer.GetPicture(pnum);
469 PictureParams& pparams = my_picture.GetPparams();
470 MvData& mv_data = static_cast<MvData&> (my_picture.GetMEData());
472 // If we're using global motion parameters, code them
473 if (m_use_global){
475 Code the global motion parameters
476 TBC ....
480 // If we're using block motion vectors, code them
481 if ( m_use_block_mv ){
482 MvDataByteIO *mv_byteio = new MvDataByteIO(pparams, mv_data.GetPicPredParams());
483 pic_byteio->SetMvData(mv_byteio);
485 SplitModeCodec smode_coder( mv_byteio->SplitModeData()->DataBlock(), TOTAL_MV_CTXS);
486 smode_coder.Compress( mv_data );
487 mv_byteio->SplitModeData()->Output();
489 PredModeCodec pmode_coder( mv_byteio->PredModeData()->DataBlock(), TOTAL_MV_CTXS, pparams.NumRefs() );
490 pmode_coder.Compress( mv_data );
491 mv_byteio->PredModeData()->Output();
493 VectorElementCodec vcoder1h( mv_byteio->MV1HorizData()->DataBlock(), 1,
494 HORIZONTAL, TOTAL_MV_CTXS);
495 vcoder1h.Compress( mv_data );
496 mv_byteio->MV1HorizData()->Output();
498 VectorElementCodec vcoder1v( mv_byteio->MV1VertData()->DataBlock(), 1,
499 VERTICAL, TOTAL_MV_CTXS);
500 vcoder1v.Compress( mv_data );
501 mv_byteio->MV1VertData()->Output();
503 if ( pparams.NumRefs()>1 )
505 VectorElementCodec vcoder2h( mv_byteio->MV2HorizData()->DataBlock(), 2,
506 HORIZONTAL, TOTAL_MV_CTXS);
507 vcoder2h.Compress( mv_data );
508 mv_byteio->MV2HorizData()->Output();
510 VectorElementCodec vcoder2v( mv_byteio->MV2VertData()->DataBlock(), 2,
511 VERTICAL, TOTAL_MV_CTXS);
512 vcoder2v.Compress( mv_data );
513 mv_byteio->MV2VertData()->Output();
516 DCCodec ydc_coder( mv_byteio->YDCData()->DataBlock(), Y_COMP, TOTAL_MV_CTXS);
517 ydc_coder.Compress( mv_data );
518 mv_byteio->YDCData()->Output();
520 DCCodec udc_coder( mv_byteio->UDCData()->DataBlock(), U_COMP, TOTAL_MV_CTXS);
521 udc_coder.Compress( mv_data );
522 mv_byteio->UDCData()->Output();
524 DCCodec vdc_coder( mv_byteio->VDCData()->DataBlock(), V_COMP, TOTAL_MV_CTXS);
525 vdc_coder.Compress( mv_data );
526 mv_byteio->VDCData()->Output();
528 mv_byteio->Output();
532 float PictureCompressor::GetCompLambda( const EncPicture& my_picture,
533 const CompSort csort )
535 const PictureParams& pparams = my_picture.GetPparams();
537 const PictureSort psort = pparams.PicSort();
539 float lambda;
541 if ( psort.IsIntra() ){
542 if ( m_is_a_cut )
543 lambda = m_encparams.L1Lambda()/8;
544 else
545 lambda = m_encparams.ILambda();
548 else{
549 double log_intra_lambda = std::log10( m_encparams.ILambda() );
551 double picture_lambda = m_encparams.L1Lambda() / my_picture.GetNormComplexity();
552 if (pparams.IsBPicture() )
553 picture_lambda *= 1.2;
555 double log_picture_lambda = std::log10( picture_lambda );
557 ///*
558 double log_picture_lambda;
559 if (pparams.IsBPicture() )
560 log_picture_lambda= std::log10( m_encparams.L2Lambda() );
561 else
562 log_picture_lambda= std::log10( m_encparams.L1Lambda() );
564 //*/
565 float intra_ratio = my_picture.GetMEData().IntraBlockRatio();
567 lambda= std::pow(10.0, 3.0*intra_ratio*log_intra_lambda+
568 (1.0-3.0*intra_ratio)*log_picture_lambda );
570 //lambda /= my_picture.GetNormComplexity();
574 if (csort == U_COMP)
575 lambda*= m_encparams.UFactor();
576 if (csort == V_COMP)
577 lambda*= m_encparams.VFactor();
579 return lambda;
582 void PictureCompressor::SetupCodeBlocks( SubbandList& bands )
584 int xregions;
585 int yregions;
587 for (int band_num = 1; band_num<=bands.Length() ; ++band_num){
588 if (m_encparams.SpatialPartition()){
589 int level = m_encparams.TransformDepth() - (band_num-1)/3;
590 const CodeBlocks &cb = m_encparams.GetCodeBlocks(level);
591 xregions = cb.HorizontalCodeBlocks();
592 yregions = cb.VerticalCodeBlocks();
594 else{
595 xregions = 1;
596 yregions = 1;
599 bands( band_num ).SetNumBlocks( yregions , xregions );
600 }// band_num
603 void PictureCompressor::SelectQuantisers( CoeffArray& coeff_data ,
604 SubbandList& bands ,
605 const float lambda,
606 OneDArray<unsigned int>& est_bits,
607 const CodeBlockMode cb_mode,
608 const PictureParams& pp,
609 const CompSort csort )
612 // Set up the multiquantiser mode
613 for ( int b=bands.Length() ; b>=1 ; --b ){
614 // Set multiquants flag in the subband only if
615 // a. Global m_cb_mode flag is set to QUANT_MULTIPLE in encparams
616 // and
617 // b. Current subband has more than one block
618 if (
619 cb_mode == QUANT_MULTIPLE &&
620 (bands(b).GetCodeBlocks().LengthX() > 1 ||
621 bands(b).GetCodeBlocks().LengthY() > 1)
623 bands(b).SetUsingMultiQuants( true );
624 else
625 bands(b).SetUsingMultiQuants( false );
626 }// b
628 // Select all the quantizers
629 if ( !m_encparams.Lossless() ){
631 if (pp.PicSort().IsIntra() == true ){
632 bands(bands.Length()).SetQuantIndex( 0 );
633 est_bits[bands.Length()] = 0;
634 TwoDArray<CodeBlock>& blocks = bands(bands.Length()).GetCodeBlocks();
635 for (int j=0; j<blocks.LengthY() ;++j)
636 for (int i=0; i<blocks.LengthX() ;++i)
637 blocks[j][i].SetQuantIndex( 0 );
640 else{
641 est_bits[bands.Length()] = SelectMultiQuants( coeff_data , bands , bands.Length(), lambda,
642 pp, csort );
644 // Now do the rest of the bands.
645 for ( int b=bands.Length()-1 ; b>=1 ; --b )
646 est_bits[b] = SelectMultiQuants( coeff_data , bands , b, lambda,
647 pp, csort );
649 else{
650 for ( int b=bands.Length() ; b>=1 ; --b ){
651 bands(b).SetQuantIndex( 0 );
652 est_bits[b] = 0;
653 TwoDArray<CodeBlock>& blocks = bands(b).GetCodeBlocks();
654 for (int j=0; j<blocks.LengthY() ;++j)
655 for (int i=0; i<blocks.LengthX() ;++i)
656 blocks[j][i].SetQuantIndex( 0 );
657 }// b
661 int PictureCompressor::SelectMultiQuants( CoeffArray& coeff_data , SubbandList& bands ,
662 const int band_num , const float lambda, const PictureParams& pp, const CompSort csort)
664 Subband& node( bands( band_num ) );
666 // Now select the quantisers //
667 ///////////////////////////////
669 QuantChooser qchooser( coeff_data , lambda );
671 // For the DC band in I pictures, remove the average
672 if ( band_num == bands.Length() && pp.PicSort().IsIntra() )
673 AddSubAverage( coeff_data , node.Xl() , node.Yl() , SUBTRACT);
675 // The total estimated bits for the subband
676 int band_bits( 0 );
677 qchooser.SetEntropyCorrection( m_encparams.EntropyFactors().Factor( band_num, pp, csort ) );
678 band_bits = qchooser.GetBestQuant( node );
680 // Put the DC band average back in if necessary
681 if ( band_num == bands.Length() && pp.PicSort().IsIntra() )
682 AddSubAverage( coeff_data , node.Xl() , node.Yl() , ADD);
684 if ( band_bits == 0 )
685 node.SetSkip( true );
686 else
687 node.SetSkip( false );
689 return band_bits;
693 void PictureCompressor::AddSubAverage( CoeffArray& coeff_data, int xl, int yl ,
694 AddOrSub dirn)
697 ValueType last_val=0;
698 ValueType last_val2;
700 if ( dirn == SUBTRACT )
702 for ( int j=0 ; j<yl ; j++)
704 for ( int i=0 ; i<xl ; i++)
706 last_val2 = coeff_data[j][i];
707 coeff_data[j][i] -= last_val;
708 last_val = last_val2;
709 }// i
710 }// j
712 else
714 for ( int j=0 ; j<yl ; j++)
716 for ( int i=0 ; i<xl; i++ )
718 coeff_data[j][i] += last_val;
719 last_val = coeff_data[j][i];
720 }// i
721 }// j