1 /*!
2  *************************************************************************************
3  * \file mmco.c
4  *
5  * \brief
6  *    MMCO example operations.
7  *
8  * \author
9  *    Main contributors (see contributors.h for copyright, address and affiliation details)
10  *     - Alexis Michael Tourapis                     <alexismt@ieee.org>
11  *     - Athanasios Leontaris                        <aleon@dolby.com>
12  *************************************************************************************
13  */
14 
15 #include "contributors.h"
16 
17 #include <ctype.h>
18 #include <limits.h>
19 #include "global.h"
20 
21 #include "image.h"
22 #include "nalucommon.h"
23 #include "report.h"
24 
25 
mmco_long_term(VideoParameters * p_Vid,int current_pic_num)26 void mmco_long_term(VideoParameters *p_Vid, int current_pic_num)
27 {
28   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2;
29 
30   if ( !p_Vid->currentPicture->idr_flag )
31   {
32     if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
33       return;
34 
35     if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
36       no_mem_exit("poc_based_ref_management: tmp_drpm");
37 
38     tmp_drpm->Next=NULL;
39 
40     tmp_drpm->memory_management_control_operation = 0;
41 
42     if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
43       no_mem_exit("poc_based_ref_management: tmp_drpm2");
44     tmp_drpm2->Next=tmp_drpm;
45 
46     tmp_drpm2->memory_management_control_operation = 3;
47     tmp_drpm2->long_term_frame_idx = current_pic_num;
48     p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2;
49   }
50   else
51   {
52     p_Vid->long_term_reference_flag = TRUE;
53   }
54 }
55 
56 #if HM50_LIKE_MMCO
hm50_ref_management_frame_pic(DecodedPictureBuffer * p_Dpb,int current_pic_num)57 void hm50_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num)
58 {
59   VideoParameters *p_Vid = p_Dpb->p_Vid;
60   unsigned i;
61   int pic_num = 0;
62 
63   int target_poc=-1;
64   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2;
65 
66   // only support GOP Size = 8, 4 reference frames, 2 in list0 and 2 in list1
67   if ( p_Vid->p_Inp->NumberBFrames != 7 ||
68        p_Vid->p_Inp->num_ref_frames != 4 ||
69        p_Vid->p_Inp->B_List0_refs[0] != 2 ||
70        p_Vid->p_Inp->B_List1_refs[0] != 2 )
71   {
72     return;
73   }
74 
75 #if CRA
76   // for CRA pictures, we have MMCO already
77   if ( p_Vid->p_Inp->useCRA )
78   {
79     if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 )
80     {
81       if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 )
82       {
83         return;
84       }
85     }
86   }
87 #endif
88 
89   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
90     return;
91 
92   if ( p_Vid->currentPicture->idr_flag )
93     return;
94 
95   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
96     return;
97 
98   switch ( p_Vid->currentSlice->ThisPOC / 2 % 8 )
99   {
100   case 0:
101     target_poc = p_Vid->currentSlice->ThisPOC - 32;
102     break;
103   case 4:
104     target_poc = p_Vid->currentSlice->ThisPOC - 16;
105     break;
106   case 2:
107     target_poc = p_Vid->currentSlice->ThisPOC - 8;
108     break;
109   case 6:
110     target_poc = p_Vid->currentSlice->ThisPOC - 8;
111     break;
112   default:
113     target_poc = -1;
114     break;
115   }
116 
117   if ( target_poc < 0 )
118     return;
119 
120 
121   for (i = 0; i < p_Dpb->used_size; i++)
122   {
123     if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc == target_poc)
124     {
125       pic_num = p_Dpb->fs[i]->frame->pic_num;
126     }
127   }
128 
129   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
130     no_mem_exit("poc_based_ref_management: tmp_drpm");
131   tmp_drpm->Next=NULL;
132 
133   tmp_drpm->memory_management_control_operation = 0;
134 
135   if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
136     no_mem_exit("poc_based_ref_management: tmp_drpm2");
137   tmp_drpm2->Next=tmp_drpm;
138 
139   tmp_drpm2->memory_management_control_operation = 1;
140 
141   if ( p_Vid->num_of_layers == 1 )
142     tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1;
143   else
144     tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1;
145 
146   p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2;
147 }
148 #endif
149 
150 #if CRA
cra_ref_management_frame_pic(DecodedPictureBuffer * p_Dpb,int current_pic_num)151 void cra_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num)
152 {
153   VideoParameters *p_Vid = p_Dpb->p_Vid;
154   unsigned i;
155   int pic_num = 0;
156 
157   //int min_poc=INT_MAX;
158   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2;
159 
160   int last_intra_poc = p_Vid->currentSlice->ThisPOC / 2 / p_Vid->p_Inp->intra_period * p_Vid->p_Inp->intra_period * 2;
161 
162   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
163     return;
164 
165   if ( p_Vid->currentPicture->idr_flag )
166     return;
167 
168   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
169     return;
170 
171   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
172     no_mem_exit("poc_based_ref_management: tmp_drpm");
173   tmp_drpm->Next=NULL;
174 
175   tmp_drpm->memory_management_control_operation = 0;
176 
177   for (i = 0; i < p_Dpb->used_size; i++)
178   {
179     if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < last_intra_poc)
180     {
181       if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
182         no_mem_exit("poc_based_ref_management: tmp_drpm2");
183       tmp_drpm2->Next=tmp_drpm;
184       tmp_drpm2->memory_management_control_operation = 1;
185 
186       pic_num = p_Dpb->fs[i]->frame->pic_num;
187 
188       if ( p_Vid->num_of_layers == 1 )
189         tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1;
190       else
191         tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1;
192 
193       if ( tmp_drpm2->difference_of_pic_nums_minus1 < 0 )
194       {
195         tmp_drpm2->difference_of_pic_nums_minus1 += p_Vid->currentSlice->max_frame_num;
196       }
197       if ( tmp_drpm2->difference_of_pic_nums_minus1 >= (int) p_Vid->currentSlice->max_frame_num )
198       {
199         tmp_drpm2->difference_of_pic_nums_minus1 -= p_Vid->currentSlice->max_frame_num;
200       }
201 
202       tmp_drpm = tmp_drpm2;
203     }
204   }
205 
206   p_Vid->dec_ref_pic_marking_buffer = tmp_drpm;
207 }
208 #endif
209 
210 #if LD_REF_SETTING
low_delay_ref_management_frame_pic(DecodedPictureBuffer * p_Dpb,int current_pic_num)211 void low_delay_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num)
212 {
213   VideoParameters *p_Vid = p_Dpb->p_Vid;
214   unsigned i;
215   int pic_num = 0;
216 
217   int min_poc=INT_MAX;
218   int min_poc_not_4x = INT_MAX;
219   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2;
220 
221 #if CRA
222   // for CRA pictures, we have MMCO already
223   if ( p_Vid->p_Inp->useCRA )
224   {
225     if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 )
226     {
227       if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 )
228       {
229         return;
230       }
231     }
232   }
233 #endif
234 
235   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
236     return;
237 
238   if ( p_Vid->currentPicture->idr_flag )
239     return;
240 
241   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
242     return;
243 
244   for (i = 0; i < p_Dpb->used_size; i++)
245   {
246     if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc)
247     {
248       min_poc = p_Dpb->fs[i]->frame->poc ;
249       pic_num = p_Dpb->fs[i]->frame->pic_num;
250     }
251   }
252   for (i = 0; i < p_Dpb->used_size; i++)
253   {
254     if((p_Vid->currentSlice->ThisPOC/2-p_Dpb->fs[i]->poc/2)>4)
255     {
256       if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) &&  p_Dpb->fs[i]->poc < min_poc_not_4x && (p_Dpb->fs[i]->poc/2)%(p_Vid->p_Inp->NumberBFrames+1)!=0 )
257       {
258         min_poc_not_4x = p_Dpb->fs[i]->frame->poc ;
259         pic_num = p_Dpb->fs[i]->frame->pic_num;
260       }
261     }
262     else
263     {
264       if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) &&  p_Dpb->fs[i]->poc < min_poc_not_4x && (p_Dpb->fs[i]->poc/2)%((p_Vid->p_Inp->NumberBFrames+1)/2)!=0 )
265       {
266         min_poc_not_4x = p_Dpb->fs[i]->frame->poc ;
267         pic_num = p_Dpb->fs[i]->frame->pic_num;
268       }
269     }
270   }
271 
272   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
273     no_mem_exit("poc_based_ref_management: tmp_drpm");
274   tmp_drpm->Next=NULL;
275 
276   tmp_drpm->memory_management_control_operation = 0;
277 
278   if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
279     no_mem_exit("poc_based_ref_management: tmp_drpm2");
280   tmp_drpm2->Next=tmp_drpm;
281 
282   tmp_drpm2->memory_management_control_operation = 1;
283 
284   if ( p_Vid->num_of_layers == 1 )
285     tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1;
286   else
287     tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1;
288 
289   p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2;
290 }
291 #endif
292 
293 /*!
294 ************************************************************************
295 * \brief
296 *    POC-based reference management (FRAME)
297 ************************************************************************
298 */
299 
poc_based_ref_management_frame_pic(DecodedPictureBuffer * p_Dpb,int current_pic_num)300 void poc_based_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num)
301 {
302   VideoParameters *p_Vid = p_Dpb->p_Vid;
303   unsigned i;
304   int pic_num = 0;
305 
306   int min_poc=INT_MAX;
307   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2;
308 
309 #if CRA
310   // for CRA pictures, we have MMCO already
311   if ( p_Vid->p_Inp->useCRA )
312   {
313     if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 )
314     {
315       if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 )
316       {
317         return;
318       }
319     }
320   }
321 #endif
322 
323 #if HM50_LIKE_MMCO
324   if ( p_Vid->p_Inp->HM50RefStructure )
325   {
326     // for the case that we already have MMCO, just return
327     if ( p_Vid->p_Inp->NumberBFrames != 7 ||
328       p_Vid->p_Inp->num_ref_frames != 4 ||
329       p_Vid->p_Inp->B_List0_refs[0] != 2 ||
330       p_Vid->p_Inp->B_List1_refs[0] != 2 )
331     {
332       return;
333     }
334   }
335 #endif
336 
337   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
338     return;
339 
340   if ( p_Vid->currentPicture->idr_flag )
341     return;
342 
343   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
344     return;
345 
346   for (i = 0; i < p_Dpb->used_size; i++)
347   {
348     if (p_Dpb->fs[i]->is_reference  && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc)
349     {
350       min_poc = p_Dpb->fs[i]->frame->poc ;
351       pic_num = p_Dpb->fs[i]->frame->pic_num;
352     }
353   }
354 
355   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
356     no_mem_exit("poc_based_ref_management: tmp_drpm");
357   tmp_drpm->Next=NULL;
358 
359   tmp_drpm->memory_management_control_operation = 0;
360 
361   if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
362     no_mem_exit("poc_based_ref_management: tmp_drpm2");
363   tmp_drpm2->Next=tmp_drpm;
364 
365   tmp_drpm2->memory_management_control_operation = 1;
366   tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1;
367 
368   p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2;
369 }
370 
371 /*!
372 ************************************************************************
373 * \brief
374 *    POC-based reference management (FIELD)
375 ************************************************************************
376 */
377 
poc_based_ref_management_field_pic(DecodedPictureBuffer * p_Dpb,int current_pic_num)378 void poc_based_ref_management_field_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num)
379 {
380   VideoParameters *p_Vid = p_Dpb->p_Vid;
381   unsigned int i;
382   int pic_num1 = 0, pic_num2 = 0;
383 
384   int min_poc=INT_MAX;
385   DecRefPicMarking_t *tmp_drpm,*tmp_drpm2, *tmp_drpm3;
386 
387   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
388     return;
389 
390   if ( p_Vid->currentPicture->idr_flag )
391     return;
392 
393   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
394     return;
395 
396   if ( p_Vid->structure == TOP_FIELD )
397   {
398     for (i=0; i<p_Dpb->used_size;i++)
399     {
400       if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc)
401       {
402         min_poc  = p_Dpb->fs[i]->poc;
403         pic_num1 = p_Dpb->fs[i]->top_field->pic_num;
404         pic_num2 = p_Dpb->fs[i]->bottom_field->pic_num;
405       }
406     }
407   }
408 
409   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm");
410   tmp_drpm->Next=NULL;
411   tmp_drpm->memory_management_control_operation = 0;
412 
413   if ( p_Vid->structure == BOTTOM_FIELD )
414   {
415     p_Vid->dec_ref_pic_marking_buffer = tmp_drpm;
416     return;
417   }
418 
419   if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm2");
420   tmp_drpm2->Next=tmp_drpm;
421   tmp_drpm2->memory_management_control_operation = 1;
422   tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num1 - 1;
423 
424   if (NULL==(tmp_drpm3=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm3");
425   tmp_drpm3->Next=tmp_drpm2;
426   tmp_drpm3->memory_management_control_operation = 1;
427   tmp_drpm3->difference_of_pic_nums_minus1 = current_pic_num - pic_num2 - 1;
428 
429   p_Vid->dec_ref_pic_marking_buffer = tmp_drpm3;
430 }
431 
432 
433 /*!
434 ************************************************************************
435 * \brief
436 *    Temporal layer-based reference management (FRAME)
437 ************************************************************************
438 */
439 
tlyr_based_ref_management_frame_pic(VideoParameters * p_Vid,int current_pic_num)440 void tlyr_based_ref_management_frame_pic(VideoParameters *p_Vid, int current_pic_num)
441 {
442   unsigned i, first = 1;
443   DecRefPicMarking_t *drpm = NULL, *current_drpm = NULL, *tmp_drpm = NULL;
444   struct decoded_picture_buffer *p_Dpb = p_Vid->p_Dpb_layer[0];
445 
446   if (p_Vid->dec_ref_pic_marking_buffer!=NULL)
447     return;
448 
449   if ( p_Vid->currentPicture->idr_flag )
450     return;
451 
452   if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0)
453     return;
454 
455   for (i = 0; i < p_Dpb->used_size; i++)
456   {
457     if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->frame->temporal_layer > p_Vid->enc_picture->temporal_layer)
458     {
459       if (NULL == (tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
460         no_mem_exit("poc_based_ref_management: tmp_drpm2");
461       tmp_drpm->memory_management_control_operation = 1;
462       tmp_drpm->difference_of_pic_nums_minus1 = current_pic_num - p_Dpb->fs[i]->frame->pic_num - 1;
463 
464       if (first)
465       {
466         drpm = current_drpm = tmp_drpm;
467         first = 0;
468       }
469       else
470       {
471         current_drpm->Next = tmp_drpm;
472         current_drpm = current_drpm->Next;
473       }
474     }
475   }
476 
477   if (first)
478     return;
479 
480   if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t))))
481     no_mem_exit("poc_based_ref_management: tmp_drpm");
482   tmp_drpm->Next=NULL;
483 
484   tmp_drpm->memory_management_control_operation = 0;
485 
486   current_drpm->Next=tmp_drpm;
487 
488   p_Vid->dec_ref_pic_marking_buffer = drpm;
489 }
490 
491