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