Updating Contact email
[BrunelResearch-dirac.git] / libdirac_motionest / me_mode_decn.cpp
blob61756267d5b0bde5c356c70ccce97ab1e02a00a9
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 * Tim Borer
26 * Alternatively, the contents of this file may be used under the terms of
27 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
28 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
29 * the GPL or the LGPL are applicable instead of those above. If you wish to
30 * allow use of your version of this file only under the terms of the either
31 * the GPL or LGPL and not to allow others to use your version of this file
32 * under the MPL, indicate your decision by deleting the provisions above
33 * and replace them with the notice and other provisions required by the GPL
34 * or LGPL. If you do not delete the provisions above, a recipient may use
35 * your version of this file under the terms of any one of the MPL, the GPL
36 * or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include <libdirac_motionest/me_mode_decn.h>
40 #include <libdirac_encoder/enc_queue.h>
41 using namespace dirac;
43 #include <algorithm>
45 using std::vector;
47 ModeDecider::ModeDecider( const EncoderParams& encp):
48 m_encparams( encp ),
49 m_level_factor(3),
50 m_mode_factor(3),
51 m_me_data_set(3)
57 ModeDecider::~ModeDecider()
59 if (m_psort.IsInter())
61 delete m_me_data_set[0];
62 delete m_me_data_set[1];
66 void ModeDecider::DoModeDecn( EncQueue& my_buffer, int pic_num )
69 m_predparams = &(my_buffer.GetPicture(pic_num).GetMEData().GetPicPredParams() );
71 // The following factors normalise costs for sub-SBs and SBs to those of
72 // blocks, so that the overlap is take into account (e.g. a sub-SB has
73 // length XBLEN+XBSEP and YBLEN+YBSEP). The SB costs for a 1x1
74 // decomposition are not directly comprable to those for other decompositions
75 // because of the block overlaps. These factors remove these effects, so that
76 // all SAD costs are normalised to the area corresponding to non-overlapping
77 // 16 blocks of size XBLEN*YBLEN.
79 m_level_factor[0] = float( 16 * m_predparams->LumaBParams(2).Xblen() * m_predparams->LumaBParams(2).Yblen() )/
80 float( m_predparams->LumaBParams(0).Xblen() * m_predparams->LumaBParams(0).Yblen() );
82 m_level_factor[1] = float( 4 * m_predparams->LumaBParams(2).Xblen() * m_predparams->LumaBParams(2).Yblen() )/
83 float( m_predparams->LumaBParams(1).Xblen() * m_predparams->LumaBParams(1).Yblen() );
85 m_level_factor[2] = 1.0f;
87 for (int i=0 ; i<=2 ; ++i)
88 m_mode_factor[i] = 80.0*std::pow(0.8 , 2-i);
90 // We've got 'raw' block motion vectors for up to two reference pictures. Now we want
91 // to make a decision as to mode. In this initial implementation, this is bottom-up
92 // i.e. find mvs for SBs and sub-SBs and see whether it's worthwhile merging.
94 int ref1,ref2;
96 // Initialise //
97 ////////////////
99 m_psort = my_buffer.GetPicture(pic_num).GetPparams().PicSort();
100 if (m_psort.IsInter())
102 // Extract the references
103 const vector<int>& refs = my_buffer.GetPicture(pic_num).GetPparams().Refs();
104 num_refs = refs.size();
105 ref1 = refs[0];
107 // The picture we're doing estimation from
108 m_pic_data = &(my_buffer.GetPicture( pic_num ).DataForME(m_encparams.CombinedME()) );
110 // Set up the hierarchy of motion vector data objects
111 PicturePredParams predparams0 = *m_predparams;
112 predparams0.SetXNumBlocks( m_predparams->XNumBlocks()/4 );
113 predparams0.SetYNumBlocks( m_predparams->YNumBlocks()/4 );
115 PicturePredParams predparams1 = *m_predparams;
116 predparams1.SetXNumBlocks( m_predparams->XNumBlocks()/2 );
117 predparams1.SetYNumBlocks( m_predparams->YNumBlocks()/2 );
119 m_me_data_set[0] = new MEData( predparams0, num_refs );
120 m_me_data_set[1] = new MEData( predparams1, num_refs );
122 m_me_data_set[2] = &my_buffer.GetPicture(pic_num).GetMEData();
124 // Set up the lambdas to use per block
125 m_me_data_set[0]->SetLambdaMap( 0 , m_me_data_set[2]->LambdaMap() , 1.0/m_level_factor[0] );
126 m_me_data_set[1]->SetLambdaMap( 1 , m_me_data_set[2]->LambdaMap() , 1.0/m_level_factor[1] );
128 // Set up the reference pictures
129 m_ref1_updata = &(my_buffer.GetPicture( ref1 ).UpDataForME(m_encparams.CombinedME()) );
131 if (num_refs>1)
133 ref2 = refs[1];
134 m_ref2_updata = &(my_buffer.GetPicture( ref2).UpDataForME(m_encparams.CombinedME()) );
135 // Create an object for computing bi-directional prediction calculations
136 if ( m_predparams->MVPrecision()==MV_PRECISION_EIGHTH_PIXEL )
137 m_bicheckdiff = new BiBlockEighthPel( *m_ref1_updata ,
138 *m_ref2_updata ,
139 *m_pic_data );
140 else if ( m_predparams->MVPrecision()==MV_PRECISION_QUARTER_PIXEL )
141 m_bicheckdiff = new BiBlockQuarterPel( *m_ref1_updata ,
142 *m_ref2_updata ,
143 *m_pic_data );
144 else
145 m_bicheckdiff = new BiBlockHalfPel( *m_ref1_updata ,
146 *m_ref2_updata ,
147 *m_pic_data );
149 else
151 ref2 = ref1;
155 // Create an object for doing intra calculations
156 m_intradiff = new IntraBlockDiff( *m_pic_data );
158 // Loop over all the superblocks, doing the work //
159 ///////////////////////////////////////////////////
161 for (m_ysb_loc=0 ; m_ysb_loc<m_predparams->YNumSB() ; ++m_ysb_loc ){
162 for (m_xsb_loc=0 ; m_xsb_loc<m_predparams->XNumSB(); ++m_xsb_loc ){
163 DoSBDecn();
164 }//m_xsb_loc
165 }//m_ysb_loc
167 delete m_intradiff;
168 if (num_refs>1)
169 delete m_bicheckdiff;
172 // Finally, although not strictly part of motion estimation,
173 // we have to assign DC values for
174 // blocks we're decided are intra.
175 SetDC( my_buffer , pic_num );
179 void ModeDecider::DoSBDecn()
181 // Does the mode decision for the given SB, in three stages
183 // Start with 4x4 modes
184 DoLevelDecn(2);
185 float old_best_SB_cost = m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc];
187 // Next do 2x2 modes
188 DoLevelDecn(1);
190 // Do 1x1 mode if merging worked before
191 if ( m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc] <= old_best_SB_cost)
193 old_best_SB_cost = m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc];
194 DoLevelDecn(0);
199 void ModeDecider::DoLevelDecn( int level )
201 // Computes the best costs if we were to
202 // stick to a decomposition at this level
204 // Looks at two cases: the prediction mode is
205 // constant across the SB; and the pred mode
206 // for each constituent is different.
208 // The limits of the prediction units
209 const int xstart = m_xsb_loc <<level;
210 const int ystart = m_ysb_loc <<level;
212 const int xend = xstart + (1<<level);
213 const int yend = ystart + (1<<level);
215 // Case 1: prediction modes are all different
217 float SB_cost = 0.0;
218 for ( int j=ystart ; j<yend ; ++j)
220 for (int i=xstart ; i<xend ; ++i)
222 if ( level<2 )
223 DoME( i , j , level);
224 SB_cost += DoUnitDecn( i , j ,level );
226 }// i
227 }// j
229 // if we've improved on the best cost, we should propagate data in
230 // the base level motion vector set
231 if (level == 2)
233 m_me_data_set[2]->SBSplit()[m_ysb_loc][m_xsb_loc] = 2;
234 m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc] = SB_cost;
237 if ( level<2 && SB_cost <= m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc] )
239 m_me_data_set[2]->SBCosts()[m_ysb_loc][m_xsb_loc] = SB_cost;
240 m_me_data_set[2]->SBSplit()[m_ysb_loc][m_xsb_loc] = level;
242 // Parameters of the base-level blocks corresponding to each
243 // prediction unit
244 int xblock_start;
245 int yblock_start;
246 int xblock_end;
247 int yblock_end;
249 for ( int j=ystart ; j<yend ; ++j )
251 yblock_start = j<<(2-level);
252 yblock_end = (j+1)<<(2-level);
253 for ( int i=xstart ; i<xend ; ++i )
255 xblock_start = i<<(2-level);
256 xblock_end = (i+1)<<(2-level);
258 for ( int v=yblock_start ; v<yblock_end ; ++v )
260 for ( int u=xblock_start ; u<xblock_end ; ++u )
262 m_me_data_set[2]->Mode()[v][u] = m_me_data_set[level]->Mode()[j][i];
263 m_me_data_set[2]->DC( Y_COMP )[v][u] = m_me_data_set[level]->DC( Y_COMP )[j][i];
264 m_me_data_set[2]->Vectors(1)[v][u] = m_me_data_set[level]->Vectors(1)[j][i];
265 if ( num_refs>1 )
266 m_me_data_set[2]->Vectors(2)[v][u] = m_me_data_set[level]->Vectors(2)[j][i];
268 }// u
269 }// v
271 }// i
272 }// j
279 void ModeDecider::DoME(const int xpos , const int ypos , const int level)
281 // Do motion estimation for a prediction unit using the
282 // four vectors derived from the next level as a guide
284 MEData& me_data = *(m_me_data_set[level]);
285 const MEData& guide_data = *(m_me_data_set[level+1]);
287 // The corresponding location of the guide data
288 const int guide_xpos = xpos<<1;
289 const int guide_ypos = ypos<<1;
291 // The location of the lowest level vectors
292 const int xblock = xpos << ( 2 - level);
293 const int yblock = ypos << ( 2 - level);
295 // The list of potential candidate vectors
296 CandidateList cand_list;
298 // The lambda to use for motion estimation
299 const float lambda = me_data.LambdaMap()[ypos][xpos];
301 // The predicting motion vector
302 MVector mv_pred;
304 for ( int j=0 ; j<2 ; ++j )
305 for (int i=0 ; i<2 ; ++i )
306 AddNewVlist( cand_list , guide_data.Vectors(1)[guide_ypos+j][guide_xpos+i] , 0 , 0 );
308 if (xblock>0 && yblock>0)
309 mv_pred = MvMedian( m_me_data_set[2]->Vectors(1)[yblock][xblock-1] ,
310 m_me_data_set[2]->Vectors(1)[yblock-1][xblock-1],
311 m_me_data_set[2]->Vectors(1)[yblock-1][xblock]);
312 else if (xblock==0 && yblock>0)
313 mv_pred = MvMean( m_me_data_set[2]->Vectors(1)[yblock-1][xblock],
314 m_me_data_set[2]->Vectors(1)[yblock-1][xblock+1]);
315 else if (xblock>0 && yblock==0)
316 mv_pred = MvMean( m_me_data_set[2]->Vectors(1)[yblock][xblock-1],
317 m_me_data_set[2]->Vectors(1)[yblock+1][xblock-1]);
318 else{
319 mv_pred.x = 0;
320 mv_pred.y = 0;
323 BlockMatcher my_bmatch1( *m_pic_data ,
324 *m_ref1_updata ,
325 m_predparams->LumaBParams(level) ,
326 m_predparams->MVPrecision(),
327 me_data.Vectors(1) , me_data.PredCosts(1) );
328 me_data.PredCosts(1)[ypos][xpos].total = 100000000.0f;
329 my_bmatch1.FindBestMatchSubp( xpos , ypos , cand_list, mv_pred, lambda );
331 if (num_refs>1)
332 {//do the same for the other reference
334 cand_list.clear();
336 for ( int j=0 ; j<2 ; ++j )
337 for (int i=0 ; i<2 ; ++i )
338 AddNewVlist( cand_list , guide_data.Vectors(2)[guide_ypos+j][guide_xpos+i] , 0 , 0 );
340 if (xblock>0 && yblock>0)
341 mv_pred = MvMedian( m_me_data_set[2]->Vectors(2)[yblock][xblock-1] ,
342 m_me_data_set[2]->Vectors(2)[yblock-1][xblock-1],
343 m_me_data_set[2]->Vectors(2)[yblock-1][xblock]);
344 else if (xblock==0 && yblock>0)
345 mv_pred = MvMean( m_me_data_set[2]->Vectors(2)[yblock-1][xblock],
346 m_me_data_set[2]->Vectors(2)[yblock-1][xblock+1]);
347 else if (xblock>0 && yblock==0)
348 mv_pred = MvMean( m_me_data_set[2]->Vectors(2)[yblock][xblock-1],
349 m_me_data_set[2]->Vectors(2)[yblock+1][xblock-1]);
350 else{
351 mv_pred.x = 0;
352 mv_pred.y = 0;
355 BlockMatcher my_bmatch2( *m_pic_data ,
356 *m_ref2_updata ,
357 m_predparams->LumaBParams(level) ,
358 m_predparams->MVPrecision(),
359 me_data.Vectors(2) , me_data.PredCosts(2) );
360 me_data.PredCosts(2)[ypos][xpos].total = 100000000.0f;
361 my_bmatch2.FindBestMatchSubp( xpos , ypos , cand_list, mv_pred, lambda );
368 float ModeDecider::DoUnitDecn(const int xpos , const int ypos , const int level )
370 // For a given prediction unit (SB, subSB or block) find the best
371 // mode, given that the REF1 and REF2 motion estimation has
372 // already been done.
374 MEData& me_data = *( m_me_data_set[level] );
376 // Coords of the top-leftmost block belonging to this unit
377 // const int xblock = xpos<<(2-level);
378 // const int yblock = ypos<<(2-level);
380 const float loc_lambda = me_data.LambdaMap()[ypos][xpos];
382 float unit_cost;
383 float mode_cost(0.0);
384 float min_unit_cost;
385 float best_SAD_value;
387 BlockDiffParams dparams;
389 dparams.SetBlockLimits( m_predparams->LumaBParams( level ) , *m_pic_data, xpos , ypos);
391 // First check REF1 costs //
392 /**************************/
394 // mode_cost = ModeCost( xblock , yblock )*m_mode_factor[level];
395 me_data.Mode()[ypos][xpos] = REF1_ONLY;
396 me_data.PredCosts(1)[ypos][xpos].total *= m_level_factor[level];
397 min_unit_cost = me_data.PredCosts(1)[ypos][xpos].total + mode_cost;
398 best_SAD_value = me_data.PredCosts(1)[ypos][xpos].SAD;
400 if (num_refs>1)
402 // Next check REF2 costs //
403 /*************************/
405 // mode_cost = ModeCost( xblock , yblock )*m_mode_factor[level];
406 me_data.PredCosts(2)[ypos][xpos].total *= m_level_factor[level];
407 unit_cost = me_data.PredCosts(2)[ypos][xpos].total + mode_cost;
408 if ( unit_cost<min_unit_cost )
410 me_data.Mode()[ypos][xpos] = REF2_ONLY;
411 min_unit_cost = unit_cost;
412 best_SAD_value = me_data.PredCosts(2)[ypos][xpos].SAD;
415 // Calculate the cost if we were to use bi-predictions //
416 /****************************************************************/
417 // mode_cost = ModeCost( xpos , ypos )*m_mode_factor[level];
419 me_data.BiPredCosts()[ypos][xpos].mvcost =
420 me_data.PredCosts(1)[ypos][xpos].mvcost+
421 me_data.PredCosts(2)[ypos][xpos].mvcost;
423 me_data.BiPredCosts()[ypos][xpos].SAD = m_bicheckdiff->Diff(dparams ,
424 me_data.Vectors(1)[ypos][xpos] ,
425 me_data.Vectors(2)[ypos][xpos] );
427 me_data.BiPredCosts()[ypos][xpos].SetTotal( loc_lambda );
429 me_data.BiPredCosts()[ypos][xpos].total *= m_level_factor[level];
430 unit_cost = me_data.BiPredCosts()[ypos][xpos].total + mode_cost;
432 if ( unit_cost<min_unit_cost )
434 me_data.Mode()[ypos][xpos] = REF1AND2;
435 min_unit_cost = unit_cost;
436 best_SAD_value = me_data.BiPredCosts()[ypos][xpos].SAD;
441 // Calculate the cost if we were to code the block as intra //
442 /************************************************************/
444 if ( level==2 && best_SAD_value> 4.0*m_predparams->LumaBParams( level ).Xblen()*
445 m_predparams->LumaBParams( level ).Yblen() )
447 // mode_cost = ModeCost( xblock , yblock ) * m_mode_factor[level];
448 me_data.IntraCosts()[ypos][xpos] = m_intradiff->Diff( dparams , me_data.DC( Y_COMP )[ypos][xpos] );
449 // me_data.IntraCosts()[ypos][xpos] += loc_lambda *
450 // GetDCVar( me_data.DC( Y_COMP )[ypos][xpos] , GetDCPred( xblock , yblock ) );
451 me_data.IntraCosts()[ypos][xpos] *= m_level_factor[level];
452 unit_cost = me_data.IntraCosts()[ypos][xpos] + mode_cost;
454 if ( unit_cost<min_unit_cost && me_data.IntraCosts()[ypos][xpos]<0.85*best_SAD_value)
456 me_data.Mode()[ypos][xpos] = INTRA;
457 min_unit_cost = unit_cost;
461 return min_unit_cost;
464 ValueType ModeDecider::GetDCPred( int xblock , int yblock )
466 ValueType dc_pred = 0;
468 if ( xblock>0 && m_me_data_set[2]->Mode()[yblock][xblock-1] == INTRA )
470 dc_pred = m_me_data_set[2]->DC( Y_COMP )[yblock][xblock-1];
471 if ( yblock>0 && m_me_data_set[2]->Mode()[yblock-1][xblock] == INTRA )
473 dc_pred += m_me_data_set[2]->DC( Y_COMP )[yblock-1][xblock];
474 dc_pred >>= 1;
478 return dc_pred;
481 float ModeDecider::ModeCost(const int xindex , const int yindex)
483 // Computes the variation of the given mode, predmode, from its immediate neighbours
484 // First, get a prediction for the mode
486 unsigned int mode_predictor = (unsigned int)(REF1_ONLY);
487 const TwoDArray<PredMode>& preddata( m_me_data_set[2]->Mode() );
489 unsigned int num_ref1_nbrs( 0 );
490 unsigned int num_ref2_nbrs( 0 );
492 if (xindex > 0 && yindex > 0)
494 num_ref1_nbrs += ((unsigned int)( preddata[yindex-1][xindex] ) ) & 1;
495 num_ref1_nbrs += ((unsigned int)( preddata[yindex-1][xindex-1] ) ) & 1;
496 num_ref1_nbrs += ((unsigned int)( preddata[yindex][xindex-1] ) ) & 1;
498 mode_predictor = num_ref1_nbrs>>1;
500 num_ref2_nbrs += ((unsigned int)( preddata[yindex-1][xindex] ) ) & 2;
501 num_ref2_nbrs += ((unsigned int)( preddata[yindex-1][xindex-1] ) ) & 2;
502 num_ref2_nbrs += ((unsigned int)( preddata[yindex][xindex-1] ) ) & 2;
503 num_ref2_nbrs >>= 1;
505 mode_predictor ^= ( (num_ref2_nbrs>>1)<<1 );
507 else if (xindex > 0 && yindex == 0)
508 mode_predictor = (unsigned int)( preddata[0][xindex-1] );
509 else if (xindex == 0 && yindex > 0)
510 mode_predictor = (unsigned int)( preddata[yindex-1][0] );
512 unsigned int var = (mode_predictor & 1)+((mode_predictor>>1) &1);
514 return var*m_me_data_set[2]->LambdaMap()[yindex][xindex];
518 float ModeDecider::GetDCVar( const ValueType dc_val , const ValueType dc_pred)
520 return 4.0*std::abs( static_cast<float>( dc_val - dc_pred ) );
523 ValueType ModeDecider::GetBlockDC(const PicArray& pic_data,
524 int xunit , int yunit , int split, CompSort cs)
526 BlockDiffParams dparams;
528 if ( cs!=Y_COMP )
529 dparams.SetBlockLimits( m_predparams->ChromaBParams( split ) ,
530 pic_data, xunit , yunit);
531 else
532 dparams.SetBlockLimits( m_predparams->LumaBParams( split ) ,
533 pic_data, xunit , yunit);
535 IntraBlockDiff intradiff( pic_data );
537 return intradiff.CalcDC( dparams );
540 void ModeDecider::SetDC( const PicArray& pic_data , MEData& me_data , CompSort cs )
543 TwoDArray<ValueType>& dcarray = me_data.DC( cs );
544 TwoDArray<ValueType> temp_dcarray (dcarray.LengthY(), dcarray.LengthX() );
546 for ( int y=0 ; y<dcarray.LengthY() ; ++y ){
547 for ( int x=0 ; x<dcarray.LengthX() ; ++x ){
548 temp_dcarray[y][x] = GetBlockDC( pic_data , x , y , 2, cs );
552 for ( int x=0 ; x<dcarray.LengthX() ; ++x ){
553 dcarray[0][x] = temp_dcarray[0][x];
555 for ( int y=1 ; y<dcarray.LengthY()-1 ; ++y ){
556 dcarray[y][0] = temp_dcarray[y][0];
557 for ( int x=1 ; x<dcarray.LengthX()-1 ; ++x ){
558 dcarray[y][x] = (temp_dcarray[y-1][x-1]+3*temp_dcarray[y-1][x]+temp_dcarray[y-1][x+1]+
559 3*temp_dcarray[y][x-1]+ 3*temp_dcarray[y][x+1]+
560 temp_dcarray[y+1][x-1]+3*temp_dcarray[y+1][x]+temp_dcarray[y+1][x+1]+8 )>>4;
562 dcarray[y][dcarray.LastX()] = temp_dcarray[y][dcarray.LastX()];
566 void ModeDecider::SetDC( EncQueue& my_buffer , int pic_num )
568 MEData& me_data = my_buffer.GetPicture(pic_num).GetMEData();
569 SetDC( my_buffer.GetPicture( pic_num ).OrigData(Y_COMP) , me_data , Y_COMP );
570 SetDC( my_buffer.GetPicture( pic_num ).OrigData(U_COMP) , me_data , U_COMP );
571 SetDC( my_buffer.GetPicture( pic_num ).OrigData(V_COMP) , me_data , V_COMP );