1 
2 /*!
3 *************************************************************************************
4 * \file wp_mcprec.c
5 *
6 * \brief
7 *    Improved Motion Compensation Precision Scheme using Weighted Prediction
8 *
9 * \author
10 *    Main contributors (see contributors.h for copyright, address and affiliation details)
11 *     - Athanasios Leontaris            <aleon@dolby.com>
12 *     - Alexis Michael Tourapis         <alexismt@ieee.org>
13 *************************************************************************************
14 */
15 #include "contributors.h"
16 
17 #include "global.h"
18 #include "image.h"
19 #include "slice.h"
20 #include "list_reorder.h"
21 #include "wp_mcprec.h"
22 #include "memalloc.h"
23 
24 /*!
25 ************************************************************************
26 * \brief
27 *    Initialize WPR object structure
28 ************************************************************************
29 */
30 
wpxInitWPXObject(VideoParameters * p_Vid)31 void wpxInitWPXObject( VideoParameters *p_Vid )
32 {
33   p_Vid->pWPX = (WPXObject *)malloc( sizeof( WPXObject ) );
34   if ( p_Vid->pWPX == NULL )
35   {
36     fprintf( stderr, "\n Error initializing memory for WPXObject. Exiting...\n" );
37     exit(1);
38   }
39 
40   // wp_ref_l0
41   if ((p_Vid->pWPX->wp_ref_list[LIST_0] = (WeightedPredRefX *) calloc(MAX_REFERENCE_PICTURES, sizeof(WeightedPredRefX))) == NULL)
42     no_mem_exit("wpxInitWPXObject: p_Vid->pWPX->wp_ref_list[0]");
43   // wp_ref_l1
44   if ((p_Vid->pWPX->wp_ref_list[LIST_1] = (WeightedPredRefX *) calloc(MAX_REFERENCE_PICTURES, sizeof(WeightedPredRefX))) == NULL)
45     no_mem_exit("wpxInitWPXObject: p_Vid->pWPX->wp_ref_list[1]");
46 }
47 
48 /*!
49 ************************************************************************
50 * \brief
51 *    Free WPR object structure
52 ************************************************************************
53 */
54 
wpxFreeWPXObject(VideoParameters * p_Vid)55 void wpxFreeWPXObject( VideoParameters *p_Vid )
56 {
57   // wp_ref_l0
58   if (p_Vid->pWPX->wp_ref_list[LIST_0])
59     free(p_Vid->pWPX->wp_ref_list[LIST_0]);
60   p_Vid->pWPX->wp_ref_list[LIST_0] = NULL;
61   // wp_ref_l1
62   if (p_Vid->pWPX->wp_ref_list[LIST_1])
63     free(p_Vid->pWPX->wp_ref_list[LIST_1]);
64   p_Vid->pWPX->wp_ref_list[LIST_1] = NULL;
65 
66   if ( p_Vid->pWPX != NULL )
67   {
68     free( p_Vid->pWPX );
69   }
70 }
71 
72 /*!
73 ************************************************************************
74 * \brief
75 *    Initialize WPR coding passes
76 ************************************************************************
77 */
78 
wpxInitWPXPasses(VideoParameters * p_Vid,InputParameters * p_Inp)79 void wpxInitWPXPasses( VideoParameters *p_Vid, InputParameters *p_Inp )
80 {
81   // initialize number of wp reference frames in each list
82   p_Vid->pWPX->num_wp_ref_list[LIST_0] = 0;
83   p_Vid->pWPX->num_wp_ref_list[LIST_1] = 0;
84 
85   switch( p_Inp->WPMCPrecision )
86   {
87   default:
88   case 0:
89     break;
90   case 1:
91     p_Vid->pWPX->wp_rd_passes[0].algorithm = WP_REGULAR;
92     p_Vid->pWPX->wp_rd_passes[1].algorithm = WP_MCPREC_MINUS0;
93     break;
94   case 2:
95     p_Vid->pWPX->wp_rd_passes[0].algorithm = WP_REGULAR;
96     p_Vid->pWPX->wp_rd_passes[1].algorithm = WP_MCPREC_MINUS0;
97     p_Vid->pWPX->wp_rd_passes[2].algorithm = WP_MCPREC_MINUS1;
98     break;
99   }
100 }
101 
102 /*!
103 ************************************************************************
104 * \brief
105 *    Modifies ref_pic_list for all lists
106 ************************************************************************
107 */
108 
wpxModifyRefPicList(Slice * currSlice)109 void wpxModifyRefPicList( Slice *currSlice )
110 {
111   VideoParameters *p_Vid = currSlice->p_Vid;
112   unsigned int i, j, cloned_refs;
113   int   default_order_list0[32];
114   int   default_order_list1[32];
115   int   re_order[32], *list_order;
116   int          pred_list;
117   DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb;
118 
119   StorablePicture **list;
120 
121   // set memory
122   memset( (void *)default_order_list0, 1<<20, 32 * sizeof( int ) );
123   memset( (void *)default_order_list1, 1<<20, 32 * sizeof( int ) );
124   memset( (void *)re_order,            1<<20, 32 * sizeof( int ) );
125 
126   // First assign default list orders
127   list = currSlice->listX[LIST_0];
128   for (i=0; i<(unsigned int)(currSlice->num_ref_idx_active[LIST_0]); i++)
129   {
130     default_order_list0[i] = list[i]->pic_num;
131   }
132   if ( currSlice->slice_type == B_SLICE )
133   {
134     list = currSlice->listX[LIST_1];
135     for (i=0; i<(unsigned int)(currSlice->num_ref_idx_active[LIST_1]); i++)
136     {
137       default_order_list1[i] = list[i]->pic_num;
138     }
139   }
140 
141   // obtain the ref_pic_list using POC-based reordering if currSlice->slice_type != B_SLICE
142   if ( currSlice->slice_type == P_SLICE )
143   {
144     int  list_sign[32];
145     int  poc_diff[32];
146     int  tmp_value;
147     int  abs_poc_dist;
148 
149     for (i=0; i < p_Dpb->ref_frames_in_buffer; i++)
150     {
151       re_order[i] = p_Dpb->fs_ref[i]->frame->pic_num;
152       if (p_Dpb->fs_ref[i]->is_used==3 && (p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term))
153       {
154         abs_poc_dist = iabs(p_Dpb->fs_ref[i]->frame->poc - p_Vid->enc_picture->poc) ;
155         poc_diff[i]  = abs_poc_dist;
156         list_sign[i] = (p_Vid->enc_picture->poc < p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1;
157       }
158     }
159 
160     // sort these references based on poc (temporal) distance
161     for (i=0; i< p_Dpb->ref_frames_in_buffer-1; i++)
162     {
163       for (j=i+1; j< p_Dpb->ref_frames_in_buffer; j++)
164       {
165         if (poc_diff[i]>poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i]))
166         {
167           tmp_value = poc_diff[i];
168           poc_diff[i] = poc_diff[j];
169           poc_diff[j] = tmp_value;
170           tmp_value  = re_order[i];
171           re_order[i] = re_order[j];
172           re_order[j] = tmp_value ;
173           tmp_value  = list_sign[i];
174           list_sign[i] = list_sign[j];
175           list_sign[j] = tmp_value ;
176         }
177       }
178     }
179   }
180   // end of POC-based reordering of P_SLICE
181 
182   // loop over two lists
183   for ( pred_list = 0; pred_list < (1 + ( currSlice->slice_type == B_SLICE ? 1 : 0 )); pred_list++ )
184   {
185     if ( pred_list == LIST_0 )
186     {
187       list_order = (currSlice->slice_type == P_SLICE) ? re_order : default_order_list0;
188     }
189     else
190     {
191       list_order = default_order_list1;
192     }
193 
194     // check algorithms (more flexibility for the future...)
195     switch( p_Vid->pWPX->curr_wp_rd_pass->algorithm )
196     {
197     default:
198     case WP_MCPREC_PLUS0:
199     case WP_MCPREC_PLUS1:
200     case WP_MCPREC_MINUS0:
201     case WP_MCPREC_MINUS1:
202       // ref 0 and 1 point to to the same reference
203       cloned_refs = p_Vid->pWPX->num_wp_ref_list[pred_list] = 2;
204       for ( j = 0; j < cloned_refs; j++ )
205       {
206         p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[0];
207       }
208       // shift the rest
209       for ( j = cloned_refs; j < p_Dpb->ref_frames_in_buffer; j++ )
210       {
211         p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[j - (cloned_refs - 1)];
212         p_Vid->pWPX->num_wp_ref_list[pred_list]++;
213       }
214       break;
215     case WP_MCPREC_MINUS_PLUS0:
216       // ref 0 and 1 point to to the same reference
217       cloned_refs = p_Vid->pWPX->num_wp_ref_list[pred_list] = 3;
218       for ( j = 0; j < cloned_refs; j++ )
219       {
220         p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[0];
221       }
222       // shift the rest
223       for ( j = cloned_refs; j < p_Dpb->ref_frames_in_buffer; j++ )
224       {
225         p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[j - (cloned_refs - 1)];
226         p_Vid->pWPX->num_wp_ref_list[pred_list]++;
227       }
228       break;
229     }
230     // constrain list length
231     p_Vid->pWPX->num_wp_ref_list[pred_list] = imin( p_Vid->pWPX->num_wp_ref_list[pred_list],
232       ( pred_list == LIST_0 ) ? currSlice->num_ref_idx_active[LIST_0] : currSlice->num_ref_idx_active[LIST_1] );
233   }
234 }
235 
236 /*!
237 ************************************************************************
238 * \brief
239 *    Determine whether it is fine to determine WP parameters
240 ************************************************************************
241 */
242 
wpxDetermineWP(Slice * currSlice,int clist,int n)243 int wpxDetermineWP( Slice *currSlice, int clist, int n )
244 {
245   VideoParameters *p_Vid = currSlice->p_Vid;
246   InputParameters *p_Inp = currSlice->p_Inp;
247   int i, j, determine_wp = 0;
248   short default_weight[3];
249   // we assume it's the same as in the WP functions
250   short luma_log_weight_denom   = 5;
251   short chroma_log_weight_denom = 5;
252   int cur_list = LIST_0;
253 
254   default_weight[0] = 1 << luma_log_weight_denom;
255   default_weight[1] = 1 << chroma_log_weight_denom;
256   default_weight[2] = 1 << chroma_log_weight_denom;
257 
258   if ( !p_Inp->WPMCPrecision )
259   {
260     determine_wp = 1;
261   }
262   else
263   {
264     determine_wp = 0;
265     // check slice type
266     if ( currSlice->slice_type == P_SLICE )
267     {
268       for (i = 0; i < 3; i++)
269       {
270         currSlice->wp_weight[clist][n][i] = default_weight[i];
271       }
272     }
273     else if ( currSlice->slice_type == B_SLICE )
274     {
275       cur_list = ((clist & 0x01) ==  LIST_1) ? LIST_0 : LIST_1;
276 
277       // single-list prediction
278       for (i = 0; i < 3; i++)
279       {
280         currSlice->wp_weight[clist][n][i] = default_weight[i];
281       }
282       // bi-pred
283       for (j = 0; j < currSlice->listXsize[cur_list]; j++)
284       {
285         for (i = 0; i < 3; i++)
286           currSlice->wbp_weight[clist][n][j][i] = default_weight[i];
287       }
288     }
289     // algorithm consideration
290     switch( p_Vid->pWPX->curr_wp_rd_pass->algorithm )
291     {
292     case WP_MCPREC_PLUS0:
293       for (i = 0; i < 3; i++)
294         currSlice->wp_offset[clist][n][i] = (n == 1) ? 1 : 0;
295       break;
296     case WP_MCPREC_MINUS0:
297       for (i = 0; i < 3; i++)
298         currSlice->wp_offset[clist][n][i] = (n == 1) ? -1 : 0;
299       break;
300     case WP_MCPREC_PLUS1:
301       for (i = 0; i < 3; i++)
302         currSlice->wp_offset[clist][n][i] = (n == 0) ? 1 : 0;
303       break;
304     case WP_MCPREC_MINUS1:
305       for (i = 0; i < 3; i++)
306         currSlice->wp_offset[clist][n][i] = (n == 0) ? -1 : 0;
307       break;
308     case WP_MCPREC_MINUS_PLUS0:
309       for (i = 0; i < 3; i++)
310         currSlice->wp_offset[clist][n][i] = (n == 1) ? -1 : ((n == 2) ? 1 : 0);
311       break;
312     default:
313     case WP_REGULAR:
314       determine_wp = 1;
315       break;
316     }
317     // check list (play with the WP factors)
318     if ( currSlice->slice_type == B_SLICE && cur_list == LIST_0 )
319     {
320       for (i = 0; i < 3; i++)
321         currSlice->wp_offset[clist][n][i] *= 2;
322     }
323     // zero out chroma offsets
324     for (i = 1; i < 3; i++)
325     {
326       currSlice->wp_offset[clist][n][i] = 0;
327     }
328   }
329 
330   return determine_wp;
331 }
332 
333 /*!
334 ************************************************************************
335 * \brief
336 *    Modify number of references
337 ************************************************************************
338 */
339 
wpxAdaptRefNum(Slice * currSlice)340 void wpxAdaptRefNum( Slice *currSlice )
341 {
342   InputParameters *p_Inp = currSlice->p_Inp;
343   VideoParameters *p_Vid = currSlice->p_Vid;
344 #if (MVC_EXTENSION_ENABLE)
345   int view_id = p_Vid->view_id;
346 #else
347   int view_id = 0;
348 #endif
349 
350   if ( p_Vid->pWPX->curr_wp_rd_pass->algorithm == WP_REGULAR )
351   {
352     switch( currSlice->slice_type )
353     {
354     default:
355     case I_SLICE:
356       break;
357     case P_SLICE:
358       if ( currSlice->num_ref_idx_active[LIST_0] == ( p_Inp->P_List0_refs[view_id] * ((currSlice->structure !=0) + 1) ) )
359       {
360         currSlice->listXsize[LIST_0] = currSlice->num_ref_idx_active[LIST_0] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_0] - ((currSlice->structure !=0) + 1) );
361       }
362       break;
363     case B_SLICE:
364       if ( currSlice->num_ref_idx_active[LIST_0] == ( p_Inp->B_List0_refs[view_id] * ((currSlice->structure !=0) + 1) ) )
365       {
366         currSlice->listXsize[LIST_0] = currSlice->num_ref_idx_active[LIST_0] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_0] - ((currSlice->structure !=0) + 1) );
367       }
368       if ( currSlice->num_ref_idx_active[LIST_1] == ( p_Inp->B_List1_refs[view_id] * ((currSlice->structure !=0) + 1) ) )
369       {
370         currSlice->listXsize[LIST_1] = currSlice->num_ref_idx_active[LIST_1] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_1] - ((currSlice->structure !=0) + 1) );
371       }
372       break;
373     }
374   }
375 }
376