1 /* ***** BEGIN LICENSE BLOCK *****
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
20 * Portions created by the Initial Developer are Copyright (C) 2004.
21 * All Rights Reserved.
23 * Contributor(s): Thomas Davies (Original Author),
26 * Anuradha Suraparaju,
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
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
;
61 PictureCompressor::PictureCompressor( EncoderParams
& encp
) :
66 m_global_pred_mode(REF1_ONLY
),
68 m_medata_avail(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);
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
;
116 if (pparams
.NumRefs()>1 && cost
<=cost_threshold
){
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
));
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 ){
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
] );
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;
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()
196 mean_complexity
+= enc_pic
.GetComplexity();
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();
218 if ( pparams
.IsBPicture())
219 lambda
= m_encparams
.L2MELambda();
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();
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
);
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;
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
)
277 // Divide the motion vectors by 2 to convert back to pixel
278 // accurate motion vectors and reset MV precision to
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;
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();
308 for ( int j
=0 ; j
<modes
.LengthY() ; ++j
)
310 for ( int i
=0 ; i
<modes
.LengthX() ; ++i
)
312 if ( modes
[j
][i
] == INTRA
)
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
,
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]);
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
);
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
);
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();
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];
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 ) );
428 /* Do the wavelet transforms and select the component
429 * quantisers using perceptual weighting
432 if (pparams
.PicSort().IsIntra() ){
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
)
463 void PictureCompressor::CodeMVData(EncQueue
& my_buffer
, int pnum
, PictureByteIO
* pic_byteio
)
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
475 Code the global motion parameters
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();
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();
541 if ( psort
.IsIntra() ){
543 lambda
= m_encparams
.L1Lambda()/8;
545 lambda
= m_encparams
.ILambda();
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 );
558 double log_picture_lambda
;
559 if (pparams
.IsBPicture() )
560 log_picture_lambda
= std::log10( m_encparams
.L2Lambda() );
562 log_picture_lambda
= std::log10( m_encparams
.L1Lambda() );
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();
575 lambda
*= m_encparams
.UFactor();
577 lambda
*= m_encparams
.VFactor();
582 void PictureCompressor::SetupCodeBlocks( SubbandList
& bands
)
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();
599 bands( band_num
).SetNumBlocks( yregions
, xregions
);
603 void PictureCompressor::SelectQuantisers( CoeffArray
& coeff_data
,
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
617 // b. Current subband has more than one block
619 cb_mode
== QUANT_MULTIPLE
&&
620 (bands(b
).GetCodeBlocks().LengthX() > 1 ||
621 bands(b
).GetCodeBlocks().LengthY() > 1)
623 bands(b
).SetUsingMultiQuants( true );
625 bands(b
).SetUsingMultiQuants( false );
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 );
641 est_bits
[bands
.Length()] = SelectMultiQuants( coeff_data
, bands
, bands
.Length(), lambda
,
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
,
650 for ( int b
=bands
.Length() ; b
>=1 ; --b
){
651 bands(b
).SetQuantIndex( 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 );
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
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 );
687 node
.SetSkip( false );
693 void PictureCompressor::AddSubAverage( CoeffArray
& coeff_data
, int xl
, int yl
,
697 ValueType last_val
=0;
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
;
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
];