1 /******************************************************************************
2  *
3  * Copyright (C) 2015 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 /**
21  *******************************************************************************
22  * @file
23  *  ih264_dpb_mgr.c
24  *
25  * @brief
26  *  Function definitions used for decoded picture buffer management
27  *
28  * @author
29  *  Srinivas T
30  *
31  * @par List of Functions:
32  *   - ih264_dpb_mgr_init()
33  *   - ih264_dpb_mgr_sort_short_term_fields_by_frame_num()
34  *   - ih264_dpb_mgr_sort_short_term_fields_by_poc_l0()
35  *   - ih264_dpb_mgr_sort_short_term_fields_by_poc_l1()
36  *   - ih264_dpb_mgr_sort_long_term_fields_by_frame_idx()
37  *   - ih264_dpb_mgr_alternate_ref_fields()
38  *   - ih264_dpb_mgr_insert_ref_field()
39  *   - ih264_dpb_mgr_insert_ref_frame()
40  *   - ih264_dpb_mgr_count_ref_frames()
41  *   - ih264_dpb_mgr_delete_ref_frame()
42  *   - ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx()
43  *   - ih264_dpb_mgr_delete_short_ref_frame()
44  *   - ih264_dpb_mgr_delete_all_ref_frames()
45  *   - ih264_dpb_mgr_reset()
46  *   - ih264_dpb_mgr_release_pics()
47  *
48  * @remarks
49  *  None
50  *
51  *******************************************************************************
52  */
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <assert.h>
57 
58 #include "ih264_typedefs.h"
59 #include "ih264_defs.h"
60 #include "ih264_macros.h"
61 #include "ih264_error.h"
62 #include "ih264_structs.h"
63 #include "ih264_buf_mgr.h"
64 #include "ih264_dpb_mgr.h"
65 #include "ih264_debug.h"
66 
67 /**
68  *******************************************************************************
69  *
70  * @brief
71  *  DPB manager initializer
72  *
73  * @par Description:
74  *  Initialises the DPB manager structure
75  *
76  * @param[in] ps_dpb_mgr
77  *  Pointer to the DPB manager structure
78  *
79  * @returns
80  *
81  * @remarks
82  *
83  *
84  *******************************************************************************
85  */
86 
ih264_dpb_mgr_init(dpb_mgr_t * ps_dpb_mgr)87 void ih264_dpb_mgr_init(dpb_mgr_t *ps_dpb_mgr)
88 {
89     UWORD32 i;
90     dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;
91     for(i = 0; i < MAX_DPB_BUFS; i++)
92     {
93         ps_dpb_info[i].ps_prev_dpb = NULL;
94         ps_dpb_info[i].ps_pic_buf = NULL;
95         ps_dpb_mgr->as_top_field_pics[i].i4_used_as_ref    = INVALID;
96         ps_dpb_mgr->as_bottom_field_pics[i].i4_used_as_ref = INVALID;
97         ps_dpb_mgr->as_top_field_pics[i].i1_field_type     = INVALID;
98         ps_dpb_mgr->as_bottom_field_pics[i].i1_field_type  = INVALID;
99         ps_dpb_mgr->as_top_field_pics[i].i4_long_term_frame_idx    = -1;
100         ps_dpb_mgr->as_bottom_field_pics[i].i4_long_term_frame_idx = -1;
101     }
102 
103     ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;
104     ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;
105     ps_dpb_mgr->ps_dpb_short_term_head = NULL;
106     ps_dpb_mgr->ps_dpb_long_term_head = NULL;
107 }
108 
109 /**
110  *******************************************************************************
111  *
112  * @brief
113  *  Function to sort sort term pics by frame_num.
114  *
115  * @par Description:
116  *  Sorts short term fields by frame_num. For 2 fields having same frame_num,
117  *  orders them based on requested first field type.
118  *
119  * @param[in] ps_dpb_mgr
120  *  Pointer to the DPB manager structure
121  *
122  * @param[in] curr_frame_num
123  *  frame_num of the current pic
124  *
125  * @param[in] first_field_type
126  *  For complementary fields, required first field
127  *
128  * @param[in] max_frame_num
129  *  Maximum frame_num allowed
130  *
131  * @returns
132  *
133  * @remarks
134  *
135  *
136  *******************************************************************************
137  */
ih264_dpb_mgr_sort_short_term_fields_by_frame_num(dpb_mgr_t * ps_dpb_mgr,WORD32 curr_frame_num,WORD32 first_field_type,WORD32 max_frame_num)138 WORD32 ih264_dpb_mgr_sort_short_term_fields_by_frame_num(dpb_mgr_t *ps_dpb_mgr,
139                                                          WORD32 curr_frame_num,
140                                                          WORD32 first_field_type,
141                                                          WORD32 max_frame_num)
142 {
143     dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
144     dpb_info_t *ps_dpb_node2;
145     WORD32 frame_num_node1;
146     WORD32 frame_num_node2;
147     pic_buf_t *ps_pic_buf;
148 
149     if(ps_dpb_node1 == NULL)
150         return -1;
151 
152     for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)
153     {
154         for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)
155         {
156             frame_num_node1 = ps_dpb_node1->ps_pic_buf->i4_frame_num;
157             frame_num_node2 = ps_dpb_node2->ps_pic_buf->i4_frame_num;
158 
159             if(frame_num_node1 > curr_frame_num)
160                 frame_num_node1 = frame_num_node1 - max_frame_num;
161             if(frame_num_node2 > curr_frame_num)
162                 frame_num_node2 = frame_num_node2 - max_frame_num;
163 
164             if(frame_num_node1 < frame_num_node2)
165             {
166                 ps_pic_buf = ps_dpb_node1->ps_pic_buf;
167                 ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;
168                 ps_dpb_node2->ps_pic_buf = ps_pic_buf;
169             }
170         }
171     }
172 
173     /**
174      * For frames and complementary field pairs,
175      * ensure first_field_type appears first in the list
176      */
177     ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
178     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
179     while(ps_dpb_node2 != NULL)
180     {
181         pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;
182         pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;
183         frame_num_node1 = ps_pic_node1->i4_frame_num;
184         frame_num_node2 = ps_pic_node2->i4_frame_num;
185         if(frame_num_node1 == frame_num_node2)
186         {
187             ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);
188             if(ps_pic_node1->i1_field_type != first_field_type)
189             {
190                 ps_dpb_node1->ps_pic_buf = ps_pic_node2;
191                 ps_dpb_node2->ps_pic_buf = ps_pic_node1;
192             }
193         }
194         ps_dpb_node1 = ps_dpb_node2;
195         ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;
196     }
197     return 0;
198 
199 }
200 
201 /**
202  *******************************************************************************
203  *
204  * @brief
205  *  Function to sort sort term pics by poc for list 0.
206  *
207  * @par Description:
208  *  Orders all the pocs less than current poc in the descending order.
209  *  Then orders all the pocs greater than current poc in the ascending order.
210  *
211  * @param[in] ps_dpb_mgr
212  *  Pointer to the DPB manager structure
213  *
214  * @param[in] curr_poc
215  *  Poc of the current pic
216  *
217  * @param[in] first_field_type
218  *  For complementary fields, required first field
219  *
220  * @returns
221  *
222  * @remarks
223  *
224  *
225  *******************************************************************************
226  */
ih264_dpb_mgr_sort_short_term_fields_by_poc_l0(dpb_mgr_t * ps_dpb_mgr,WORD32 curr_poc,WORD32 first_field_type)227 WORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l0(dpb_mgr_t *ps_dpb_mgr,
228                                                       WORD32 curr_poc,
229                                                       WORD32 first_field_type)
230 {
231     dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
232     dpb_info_t *ps_dpb_node2;
233     WORD32 poc_node1;
234     WORD32 poc_node2;
235     WORD32 frame_num_node1;
236     WORD32 frame_num_node2;
237     pic_buf_t *ps_pic_buf;
238 
239     if(ps_dpb_node1 == NULL)
240         return -1;
241 
242     /**
243      * Sort the fields by poc.
244      * All POCs less than current poc are first placed in the descending order.
245      * Then all POCs greater than current poc are placed in the ascending order.
246      */
247     for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)
248     {
249         for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)
250         {
251             poc_node1 = ps_dpb_node1->ps_pic_buf->i4_abs_poc;
252             poc_node2 = ps_dpb_node2->ps_pic_buf->i4_abs_poc;
253             ASSERT(poc_node1 != curr_poc);
254             ASSERT(poc_node2 != curr_poc);
255             if(((poc_node1 < curr_poc) && (poc_node2 > curr_poc)) ||
256                     ((poc_node1 < curr_poc) && (poc_node2 < curr_poc) && (poc_node1 > poc_node2)) ||
257                     ((poc_node1 > curr_poc) && (poc_node2 > curr_poc) && (poc_node1 < poc_node2)))
258                     continue;
259 
260             ps_pic_buf = ps_dpb_node1->ps_pic_buf;
261             ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;
262             ps_dpb_node2->ps_pic_buf = ps_pic_buf;
263         }
264     }
265 
266     ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
267     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
268     while(ps_dpb_node2 != NULL)
269     {
270         pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;
271         pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;
272         frame_num_node1 = ps_pic_node1->i4_frame_num;
273         frame_num_node2 = ps_pic_node2->i4_frame_num;
274         if(frame_num_node1 == frame_num_node2)
275         {
276             ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);
277             if(ps_pic_node1->i1_field_type != first_field_type)
278             {
279                 ps_dpb_node1->ps_pic_buf = ps_pic_node2;
280                 ps_dpb_node2->ps_pic_buf = ps_pic_node1;
281             }
282         }
283         ps_dpb_node1 = ps_dpb_node2;
284         ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;
285     }
286     return 0;
287 
288 }
289 
290 /**
291  *******************************************************************************
292  *
293  * @brief
294  *  Function to sort sort term pics by poc for list 1.
295  *
296  * @par Description:
297  *  Orders all the pocs greater than current poc in the ascending order.
298  *  Then rrders all the pocs less than current poc in the descending order.
299  *
300  * @param[in] ps_dpb_mgr
301  *  Pointer to the DPB manager structure
302  *
303  * @param[in] curr_poc
304  *  Poc of the current pic
305  *
306  * @param[in] first_field_type
307  *  For complementary fields, required first field
308  *
309  * @returns
310  *
311  * @remarks
312  *
313  *
314  *******************************************************************************
315  */
ih264_dpb_mgr_sort_short_term_fields_by_poc_l1(dpb_mgr_t * ps_dpb_mgr,WORD32 curr_poc,WORD32 first_field_type)316 WORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l1(dpb_mgr_t *ps_dpb_mgr,
317                                                       WORD32 curr_poc,
318                                                       WORD32 first_field_type)
319 {
320     dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
321     dpb_info_t *ps_dpb_node2;
322     WORD32 poc_node1;
323     WORD32 poc_node2;
324     WORD32 frame_num_node1;
325     WORD32 frame_num_node2;
326     pic_buf_t *ps_pic_buf;
327 
328     if(ps_dpb_node1 == NULL)
329         return -1;
330 
331     /**
332      * Sort the fields by poc.
333      * All POCs greater than current poc are first placed in the ascending order.
334      * Then all POCs less than current poc are placed in the decending order.
335      */
336     for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)
337     {
338         for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)
339         {
340             poc_node1 = ps_dpb_node1->ps_pic_buf->i4_abs_poc;
341             poc_node2 = ps_dpb_node2->ps_pic_buf->i4_abs_poc;
342             ASSERT(poc_node1 != curr_poc);
343             ASSERT(poc_node2 != curr_poc);
344             if(((poc_node1 > curr_poc) && (poc_node2 < curr_poc)) ||
345                     ((poc_node1 < curr_poc) && (poc_node2 < curr_poc) && (poc_node1 > poc_node2)) ||
346                     ((poc_node1 > curr_poc) && (poc_node2 > curr_poc) && (poc_node1 < poc_node2)))
347                     continue;
348 
349             ps_pic_buf = ps_dpb_node1->ps_pic_buf;
350             ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;
351             ps_dpb_node2->ps_pic_buf = ps_pic_buf;
352         }
353     }
354 
355     ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;
356     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
357     while(ps_dpb_node2 != NULL)
358     {
359         pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;
360         pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;
361         frame_num_node1 = ps_pic_node1->i4_frame_num;
362         frame_num_node2 = ps_pic_node2->i4_frame_num;
363         if(frame_num_node1 == frame_num_node2)
364         {
365             ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);
366             if(ps_pic_node1->i1_field_type != first_field_type)
367             {
368                 ps_dpb_node1->ps_pic_buf = ps_pic_node2;
369                 ps_dpb_node2->ps_pic_buf = ps_pic_node1;
370             }
371         }
372         ps_dpb_node1 = ps_dpb_node2;
373         ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;
374     }
375     return 0;
376 }
377 /**
378  *******************************************************************************
379  *
380  * @brief
381  *  Function to sort long term pics by long term frame idx.
382  *
383  * @par Description:
384  *  Sorts long term fields by long term frame idx. For 2 fields
385  *  having same frame_num, orders them based on requested first field type.
386  *
387  * @param[in] ps_dpb_mgr
388  *  Pointer to the DPB manager structure
389  *
390  * @param[in] first_field_type
391  *  For complementary fields, required first field
392  *
393  * @returns
394  *
395  * @remarks
396  *
397  *
398  *******************************************************************************
399  */
ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(dpb_mgr_t * ps_dpb_mgr,WORD32 first_field_type)400 WORD32 ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(dpb_mgr_t *ps_dpb_mgr,
401                                                         WORD32 first_field_type)
402 {
403     dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;
404     dpb_info_t *ps_dpb_node2;
405     WORD32 frame_idx_node1;
406     WORD32 frame_idx_node2;
407     pic_buf_t *ps_pic_buf;
408 
409     if(ps_dpb_node1 == NULL)
410         return -1;
411 
412     /* Sort the fields by frame idx */
413     for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)
414     {
415         for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)
416         {
417             frame_idx_node1 = ps_dpb_node1->ps_pic_buf->i4_long_term_frame_idx;
418             frame_idx_node2 = ps_dpb_node2->ps_pic_buf->i4_long_term_frame_idx;
419 
420             if(frame_idx_node1 > frame_idx_node2)
421             {
422                 ps_pic_buf = ps_dpb_node1->ps_pic_buf;
423                 ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;
424                 ps_dpb_node2->ps_pic_buf = ps_pic_buf;
425             }
426         }
427     }
428 
429     /**
430      * For frames and complementary field pairs,
431      * ensure first_field_type appears first in the list
432      */
433     ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;
434     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
435     while(ps_dpb_node2 != NULL)
436     {
437         pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;
438         pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;
439         frame_idx_node1 = ps_pic_node1->i4_long_term_frame_idx;
440         frame_idx_node2 = ps_pic_node2->i4_long_term_frame_idx;
441         if(frame_idx_node1 == frame_idx_node2)
442         {
443             ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);
444             if(ps_pic_node1->i1_field_type != first_field_type)
445             {
446                 ps_dpb_node1->ps_pic_buf = ps_pic_node2;
447                 ps_dpb_node2->ps_pic_buf = ps_pic_node1;
448             }
449         }
450         ps_dpb_node1 = ps_dpb_node2;
451         ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;
452     }
453     return 0;
454 }
455 
456 /**
457  *******************************************************************************
458  *
459  * @brief
460  *  Function to alternate fields.
461  *
462  * @par Description:
463  *  In the ordered list of fields, alternate fields starting with
464  *  first_field_type
465  *
466  * @param[in] ps_dpb_mgr
467  *  Pointer to the DPB manager structure
468  *
469  * @param[in] reference_type
470  *  This is used to select between short-term and long-term linked list.
471  *
472  * @param[in] first_field_type
473  *  For complementary fields, required first field
474  *
475  * @returns
476  *
477  * @remarks
478  *
479  *
480  *******************************************************************************
481  */
ih264_dpb_mgr_alternate_ref_fields(dpb_mgr_t * ps_dpb_mgr,WORD32 reference_type,WORD32 first_field_type)482 WORD32 ih264_dpb_mgr_alternate_ref_fields(dpb_mgr_t *ps_dpb_mgr,
483                                           WORD32 reference_type,
484                                           WORD32 first_field_type)
485 {
486     dpb_info_t s_dpb_head;
487     dpb_info_t *ps_dpb_head;
488     dpb_info_t *ps_dpb_node1;
489     dpb_info_t *ps_dpb_node2;
490     dpb_info_t *ps_dpb_node3;
491     dpb_info_t *ps_dpb_node4;
492     WORD32 expected_field;
493 
494     expected_field = first_field_type;
495 
496     ps_dpb_head = &s_dpb_head;
497 
498     ps_dpb_head->ps_prev_dpb = (reference_type == SHORT_TERM_REF) ?
499             ps_dpb_mgr->ps_dpb_short_term_head:
500             ps_dpb_mgr->ps_dpb_long_term_head;
501 
502     ps_dpb_node1 = ps_dpb_head;
503     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
504     while(ps_dpb_node2 != NULL)
505     {
506         pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;
507         if(ps_pic_node2->i1_field_type != expected_field)
508         {
509             /*
510              * If it is not expected field, loop over the node till
511              * the expected field.
512              */
513             ps_dpb_node3 = ps_dpb_node2;
514             ps_dpb_node4 = ps_dpb_node2->ps_prev_dpb;
515             while((ps_dpb_node4 != NULL) &&
516                     (ps_dpb_node4->ps_pic_buf->i1_field_type != expected_field))
517             {
518                 ps_dpb_node3 = ps_dpb_node4;
519                 ps_dpb_node4 = ps_dpb_node4->ps_prev_dpb;
520             }
521             if(ps_dpb_node4 != NULL)
522             {
523                 ps_dpb_node1->ps_prev_dpb = ps_dpb_node4;
524                 ps_dpb_node3->ps_prev_dpb = ps_dpb_node4->ps_prev_dpb;
525                 ps_dpb_node4->ps_prev_dpb = ps_dpb_node2;
526             }
527             else
528             {
529                 /* node4 null means we have reached the end */
530                 break;
531             }
532         }
533         ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb;
534         ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
535         expected_field = (ps_dpb_node1->ps_pic_buf->i1_field_type == TOP_FIELD)?
536                             BOTTOM_FIELD:TOP_FIELD;
537     }
538 
539     if(reference_type == SHORT_TERM_REF)
540     {
541         ps_dpb_mgr->ps_dpb_short_term_head = ps_dpb_head->ps_prev_dpb;
542     }
543     else
544     {
545         ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_head->ps_prev_dpb;
546     }
547 
548     return 0;
549 }
550 
551 /**
552  *******************************************************************************
553  *
554  * @brief
555  *  Add a ref field to short-term or long-term linked list.
556  *
557  * @par Description:
558  *  This function adds a ref field to either short-term or long-term linked
559  *  list. It picks up memory for the link from the array of dpb_info in
560  *  dpb_mgr. The field is added to the beginning of the linked list and the
561  *  head is set the the field.
562  *
563  * @param[in] ps_dpb_mgr
564  *  Pointer to the DPB manager structure
565  *
566  * @param[in] ps_pic_buf
567  *  Pic buf structure for the field being added.
568  *
569  * @param[in] reference_type
570  *  This is used to select between short-term and long-term linked list.
571  *
572  * @param[in] frame_num
573  *  frame_num for the field.
574  *
575  * @param[in] long_term_frame_idx
576  *  If the ref being added is long-term, long_term_frame_idx of the field.
577  *  Otherwise invalid.
578  *
579  * @returns
580  *
581  * @remarks
582  *
583  *
584  *******************************************************************************
585  */
ih264_dpb_mgr_insert_ref_field(dpb_mgr_t * ps_dpb_mgr,pic_buf_t * ps_pic_buf,WORD32 reference_type,UWORD32 frame_num,WORD32 long_term_frame_idx)586 WORD32 ih264_dpb_mgr_insert_ref_field(dpb_mgr_t *ps_dpb_mgr,
587                                     pic_buf_t *ps_pic_buf,
588                                     WORD32 reference_type,
589                                     UWORD32 frame_num,
590                                     WORD32 long_term_frame_idx)
591 {
592     WORD32 i;
593     dpb_info_t *ps_dpb_info;
594     dpb_info_t *ps_dpb_head;
595 
596     ps_dpb_info = ps_dpb_mgr->as_dpb_info;
597 
598     /* Return error if buffer is already present in the DPB */
599     for(i = 0; i < MAX_DPB_BUFS; i++)
600     {
601         if( (ps_dpb_info[i].ps_pic_buf == ps_pic_buf)
602                         && (ps_dpb_info[i].ps_pic_buf->i4_used_as_ref == reference_type) )
603         {
604             return (-1);
605         }
606     }
607 
608     /* Find an unused DPB location */
609     for(i = 0; i < MAX_DPB_BUFS; i++)
610     {
611         if(NULL == ps_dpb_info[i].ps_pic_buf)
612         {
613             break;
614         }
615     }
616     if(i == MAX_DPB_BUFS)
617     {
618         return (-1);
619     }
620 
621     ps_dpb_head = (reference_type == SHORT_TERM_REF)
622                     ?ps_dpb_mgr->ps_dpb_short_term_head
623                     :ps_dpb_mgr->ps_dpb_long_term_head;
624 
625     if(reference_type == SHORT_TERM_REF)
626         long_term_frame_idx = -1;
627 
628     /* Create DPB info */
629     ps_dpb_info[i].ps_pic_buf = ps_pic_buf;
630     ps_dpb_info[i].ps_prev_dpb = ps_dpb_head;
631     ps_dpb_info[i].ps_pic_buf->i4_used_as_ref = reference_type;
632     ps_dpb_info[i].ps_pic_buf->i4_frame_num = frame_num;
633     ps_dpb_info[i].ps_pic_buf->i4_long_term_frame_idx = long_term_frame_idx;
634 
635     /* update the head node of linked list to point to the current picture */
636     if(reference_type == SHORT_TERM_REF)
637     {
638         ps_dpb_mgr->ps_dpb_short_term_head = ps_dpb_info + i;
639 
640         /* Increment Short term buffer count */
641         ps_dpb_mgr->u1_num_short_term_ref_bufs++;
642 
643     }
644     else
645     {
646         ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_info + i;
647 
648         /* Increment Long term buffer count */
649         ps_dpb_mgr->u1_num_long_term_ref_bufs++;
650     }
651 
652     return 0;
653 }
654 
655 /**
656  *******************************************************************************
657  *
658  * @brief
659  *  Add a ref frame to short-term or long-term linked list.
660  *
661  * @par Description:
662  *  This function adds a ref frame to either short-term or long-term linked
663  *  list. Internally it calls add ref field twice to add top and bottom field.
664  *
665  * @param[in] ps_dpb_mgr
666  *  Pointer to the DPB manager structure
667  *
668  * @param[in] ps_pic_buf
669  *  Pic buf structure for the field being added.
670  *
671  * @param[in] reference_type
672  *  This is used to select between short-term and long-term linked list.
673  *
674  * @param[in] frame_num
675  *  frame_num for the field.
676  *
677  * @param[in] long_term_frame_idx
678  *  If the ref being added is long-term, long_term_frame_idx of the field.
679  *  Otherwise invalid.
680  *
681  * @returns
682  *
683  * @remarks
684  *
685  *
686  *******************************************************************************
687  */
ih264_dpb_mgr_insert_ref_frame(dpb_mgr_t * ps_dpb_mgr,pic_buf_t * ps_pic_buf,WORD32 reference_type,UWORD32 frame_num,WORD32 long_term_frame_idx)688 WORD32 ih264_dpb_mgr_insert_ref_frame(dpb_mgr_t *ps_dpb_mgr,
689                                       pic_buf_t *ps_pic_buf,
690                                       WORD32 reference_type,
691                                       UWORD32 frame_num,
692                                       WORD32 long_term_frame_idx)
693 {
694     WORD32 buf_id;
695     pic_buf_t *ps_pic_top;
696     pic_buf_t *ps_pic_bottom;
697     WORD32 ret;
698 
699     /*
700      * For a frame, since the ps_pic_buf passed to this function is that of top field
701      * obtain bottom field using buf_id.
702      */
703     ps_pic_top = ps_pic_buf;
704     buf_id = ps_pic_top->i4_buf_id;
705     ps_pic_bottom = &ps_dpb_mgr->as_bottom_field_pics[buf_id];
706 
707     /* Insert top field */
708     ret = ih264_dpb_mgr_insert_ref_field(ps_dpb_mgr,
709                                        ps_pic_top,
710                                        reference_type,
711                                        frame_num,
712                                        long_term_frame_idx);
713 
714     if(ret != 0)
715         return ret;
716 
717     /* Insert bottom field */
718     ret = ih264_dpb_mgr_insert_ref_field(ps_dpb_mgr,
719                                        ps_pic_bottom,
720                                        reference_type,
721                                        frame_num,
722                                        long_term_frame_idx);
723 
724     if(ret != 0)
725         return ret;
726 
727     return ret;
728 }
729 
730 /**
731  *******************************************************************************
732  *
733  * @brief
734  *  Returns the number of ref frames in both the linked list.
735  *
736  * @par Description:
737  *  Returns the count of number of frames, number of complementary field pairs
738  *  and number of unpaired fields.
739  *
740  * @param[in] ps_dpb_mgr
741  *  Pointer to the DPB manager structure
742  *
743  * @param[in] curr_frame_num
744  *  frame_num for the field.
745  *
746  * @param[in] max_frame_num
747  *  Maximum frame_num allowed
748  *
749  * @returns
750  *
751  * @remarks
752  *
753  *
754  *******************************************************************************
755  */
ih264_dpb_mgr_count_ref_frames(dpb_mgr_t * ps_dpb_mgr,WORD32 curr_frame_num,WORD32 max_frame_num)756 WORD32 ih264_dpb_mgr_count_ref_frames(dpb_mgr_t *ps_dpb_mgr,
757                                       WORD32 curr_frame_num,
758                                       WORD32 max_frame_num)
759 {
760     WORD32 numShortTerm = 0;
761     WORD32 numLongTerm = 0;
762     dpb_info_t *ps_dpb_node;
763     WORD32 frame_num;
764     WORD32 prev_frame_num;
765 
766     /*
767      * Compute the number of short-term frames/complementary field pairs/
768      * unpaired fields
769      */
770     if(ps_dpb_mgr->ps_dpb_short_term_head != NULL)
771     {
772         /* Sort the short-term list by frame_num */
773         ih264_dpb_mgr_sort_short_term_fields_by_frame_num(ps_dpb_mgr,
774                                                         curr_frame_num,
775                                                         TOP_FIELD,
776                                                         max_frame_num);
777 
778         ps_dpb_node = ps_dpb_mgr->ps_dpb_short_term_head;
779         if(ps_dpb_node != NULL)
780         {
781             numShortTerm++;
782             prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
783             ps_dpb_node = ps_dpb_node->ps_prev_dpb;
784         }
785 
786         while(ps_dpb_node != NULL)
787         {
788             frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
789             if(frame_num != prev_frame_num)
790                 numShortTerm++;
791             prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
792             ps_dpb_node = ps_dpb_node->ps_prev_dpb;
793         }
794     }
795 
796     /*
797      * Compute the number of long-term frames/complementary field pairs/
798      * unpaired fields
799      */
800     if(ps_dpb_mgr->ps_dpb_long_term_head != NULL)
801     {
802         ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(ps_dpb_mgr,
803                                                         TOP_FIELD);
804 
805         ps_dpb_node = ps_dpb_mgr->ps_dpb_long_term_head;
806         if(ps_dpb_node != NULL)
807         {
808             numLongTerm++;
809             prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
810             ps_dpb_node = ps_dpb_node->ps_prev_dpb;
811         }
812 
813         while(ps_dpb_node != NULL)
814         {
815             frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
816             if(frame_num != prev_frame_num)
817                 numLongTerm++;
818             prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;
819             ps_dpb_node = ps_dpb_node->ps_prev_dpb;
820         }
821     }
822     return (numShortTerm + numLongTerm);
823 }
824 
825 /**
826  *******************************************************************************
827  *
828  * @brief
829  *  Deletes the ref frame at the end of the linked list.
830  *
831  * @par Description:
832  *  Deletes the ref frame at the end of the linked list. For unpaired fields,
833  *  it deletes just the last node. For frame or complementary field pair, it
834  *  deletes the last two nodes.
835  *
836  * @param[in] ps_dpb_mgr
837  *  Pointer to the DPB manager structure
838  *
839  * @param[in] reference_type
840  *  This is used to select between short-term and long-term linked list.
841  *
842  * @returns
843  *
844  * @remarks
845  *
846  *
847  *******************************************************************************
848  */
ih264_dpb_mgr_delete_ref_frame(dpb_mgr_t * ps_dpb_mgr,WORD32 reference_type)849 WORD32 ih264_dpb_mgr_delete_ref_frame(dpb_mgr_t *ps_dpb_mgr,
850                                       WORD32 reference_type)
851 {
852     dpb_info_t *ps_dpb_node1;
853     dpb_info_t *ps_dpb_node2;
854     dpb_info_t *ps_dpb_node3;
855 
856     /*
857      * Assumption: The nodes sorted for frame num.
858      */
859 
860 
861     /* Select bw short-term and long-term list. */
862     ps_dpb_node1 = (reference_type == SHORT_TERM_REF)
863                     ?ps_dpb_mgr->ps_dpb_short_term_head
864                     :ps_dpb_mgr->ps_dpb_long_term_head;
865     /* If null, no entries in the list. Hence return. */
866     if(ps_dpb_node1 == NULL)
867         return 0;
868 
869     /* If only one node in the list, set as unsed for refer and return. */
870     if(ps_dpb_node1->ps_prev_dpb == NULL)
871     {
872         /* Set the picture as unused for reference */
873         ps_dpb_node1->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
874         ps_dpb_node1->ps_pic_buf = NULL;
875 
876         if(reference_type == SHORT_TERM_REF)
877         {
878             ps_dpb_mgr->ps_dpb_short_term_head = NULL;
879 
880             /* Increment Short term buffer count */
881             ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;
882 
883         }
884         else
885         {
886             ps_dpb_mgr->ps_dpb_long_term_head = NULL;
887 
888             /* Increment Long term buffer count */
889             ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;
890 
891         }
892         return 0;
893     }
894 
895     /**
896      * If there are only 2 nodes in the list, set second node as unused for reference.
897      * If the frame_num of second node and first node is same, set first node also as
898      * unused for reference and set the corresponding head to NULL.
899      */
900     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
901     if(ps_dpb_node2->ps_prev_dpb == NULL)
902     {
903         /* Set the picture as unused for reference */
904         if(ps_dpb_node2->ps_pic_buf->i4_frame_num == ps_dpb_node1->ps_pic_buf->i4_frame_num)
905         {
906             /* Set the picture as unused for reference */
907             ps_dpb_node1->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
908             ps_dpb_node1->ps_pic_buf = NULL;
909             if(reference_type == SHORT_TERM_REF)
910             {
911                 ps_dpb_mgr->ps_dpb_short_term_head = NULL;
912 
913                 /* Increment Short term buffer count */
914                 ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;
915 
916             }
917             else
918             {
919                 ps_dpb_mgr->ps_dpb_long_term_head = NULL;
920 
921                 /* Increment Long term buffer count */
922                 ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;
923 
924             }
925 
926         }
927         ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
928         ps_dpb_node2->ps_pic_buf = NULL;
929         ps_dpb_node1->ps_prev_dpb = NULL;
930         return 0;
931     }
932     /*
933      * If there are more than 2 nodes, run a loop to get the last 3 nodes.
934      */
935     ps_dpb_node3 = ps_dpb_node2->ps_prev_dpb;
936     while(ps_dpb_node3->ps_prev_dpb != NULL)
937     {
938         ps_dpb_node1 = ps_dpb_node2;
939         ps_dpb_node2 = ps_dpb_node3;
940         ps_dpb_node3 = ps_dpb_node3->ps_prev_dpb;
941     }
942     /*
943      * If node 2 and node 3 frame_nums are same, set node 2 also as unsed for
944      * reference and del reference from node1.
945      */
946     if(ps_dpb_node2->ps_pic_buf->i4_frame_num == ps_dpb_node3->ps_pic_buf->i4_frame_num)
947     {
948         ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
949         ps_dpb_node2->ps_pic_buf = NULL;
950         ps_dpb_node1->ps_prev_dpb = NULL;
951 
952     }
953     /* Set the third node as unused for reference */
954     ps_dpb_node3->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
955     ps_dpb_node3->ps_pic_buf = NULL;
956     ps_dpb_node2->ps_prev_dpb = NULL;
957 
958     return 0;
959 }
960 /**
961  *******************************************************************************
962  *
963  * @brief
964  *  Delete long-term ref fields above max frame idx.
965  *
966  * @par Description:
967  *  Deletes all the long-term ref fields having idx greater than max_frame_idx
968  *
969  * @param[in] ps_dpb_mgr
970  *  Pointer to the DPB manager structure
971  *
972  * @param[in] max_frame_idx
973  *  Max long-term frame idx allowed.
974  *
975  * @returns
976  *
977  * @remarks
978  *
979  *
980  *******************************************************************************
981  */
ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx(dpb_mgr_t * ps_dpb_mgr,WORD32 max_frame_idx)982 WORD32 ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx(dpb_mgr_t *ps_dpb_mgr,
983                                                           WORD32 max_frame_idx)
984 {
985     dpb_info_t *ps_dpb_node1;
986     dpb_info_t *ps_dpb_node2;
987     /*
988      * Loop until there is node which isn't to be deleted is encountered.
989      */
990     while(ps_dpb_mgr->ps_dpb_long_term_head != NULL)
991     {
992         if(ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf->i4_long_term_frame_idx
993                         <= max_frame_idx)
994         {
995             break;
996         }
997         ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
998         ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf = NULL;
999         ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_mgr->ps_dpb_long_term_head->ps_prev_dpb;
1000     }
1001 
1002     ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;
1003     if(ps_dpb_node1 == NULL)
1004         return 0;
1005     /*
1006      * With the node that isn't to be deleted as head, loop until the end.
1007      */
1008     ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
1009     while(ps_dpb_node2 != NULL)
1010     {
1011         if(ps_dpb_node2->ps_pic_buf->i4_long_term_frame_idx > max_frame_idx)
1012         {
1013             ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
1014             ps_dpb_node2->ps_pic_buf = NULL;
1015             ps_dpb_node1->ps_prev_dpb = ps_dpb_node2->ps_prev_dpb;
1016         }
1017         ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb;
1018         if(ps_dpb_node1 == NULL)
1019             break;
1020         ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;
1021     }
1022     return 0;
1023 }
1024 
1025 /**
1026  *******************************************************************************
1027  *
1028  * @brief
1029  *  Deletes the short-term with least frame_num
1030  *
1031  * @par Description:
1032  *  Deletes the short-term with least frame_num. It sorts the function the
1033  *  short-term linked list by frame-num and the function that deletes the last
1034  *  frame in the linked list.
1035  *
1036  * @param[in] ps_dpb_mgr
1037  *  Pointer to the DPB manager structure
1038  *
1039  * @param[in] curr_frame_num
1040  *  frame_num of the current pic
1041  *
1042  * @param[in] max_frame_num
1043  *  Maximum frame_num allowed
1044  *
1045  * @returns
1046  *
1047  * @remarks
1048  *
1049  *
1050  *******************************************************************************
1051  */
ih264_dpb_mgr_delete_short_ref_frame(dpb_mgr_t * ps_dpb_mgr,WORD32 curr_frame_num,WORD32 max_frame_num)1052 WORD32 ih264_dpb_mgr_delete_short_ref_frame(dpb_mgr_t *ps_dpb_mgr,
1053                                             WORD32 curr_frame_num,
1054                                             WORD32 max_frame_num)
1055 {
1056     WORD32 ret;
1057     /* Sort the short-term list by frame_num */
1058     ret = ih264_dpb_mgr_sort_short_term_fields_by_frame_num(ps_dpb_mgr,
1059                                                           curr_frame_num,
1060                                                           TOP_FIELD,
1061                                                           max_frame_num);
1062 
1063     /* Delete the last reference frame or field */
1064     ret = ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,SHORT_TERM_REF);
1065 
1066     if(ret != 0)
1067     {
1068         ASSERT(0);
1069     }
1070 
1071     return ret;
1072 }
1073 /**
1074  *******************************************************************************
1075  *
1076  * @brief
1077  *  Deletes all the ref frames.
1078  *
1079  * @par Description:
1080  *  Deletes all of the ref frames/fields in the short-term and long-term linked
1081  *  list.
1082  *
1083  * @param[in] ps_dpb_mgr
1084  *  Pointer to the DPB manager structure
1085  *
1086  * @returns
1087  *
1088  * @remarks
1089  *
1090  *
1091  *******************************************************************************
1092  */
ih264_dpb_mgr_delete_all_ref_frames(dpb_mgr_t * ps_dpb_mgr)1093 WORD32 ih264_dpb_mgr_delete_all_ref_frames(dpb_mgr_t *ps_dpb_mgr)
1094 {
1095     /* Loop over short-term linked list. */
1096     while(ps_dpb_mgr->ps_dpb_short_term_head != NULL)
1097     {
1098         ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,SHORT_TERM_REF);
1099     }
1100 
1101     /* Loop over long-term linked list. */
1102     while(ps_dpb_mgr->ps_dpb_long_term_head != NULL)
1103     {
1104         ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,LONG_TERM_REF);
1105     }
1106     return 0;
1107 }
1108 
1109 
ih264_dpb_mgr_reset(dpb_mgr_t * ps_dpb_mgr,buf_mgr_t * ps_buf_mgr)1110 void ih264_dpb_mgr_reset(dpb_mgr_t *ps_dpb_mgr, buf_mgr_t *ps_buf_mgr)
1111 {
1112     WORD32 i;
1113     dpb_info_t *ps_dpb_info;
1114     ASSERT(0);
1115 
1116 
1117     ps_dpb_info = ps_dpb_mgr->as_dpb_info;
1118 
1119     for(i = 0; i < MAX_DPB_BUFS; i++)
1120     {
1121         if(ps_dpb_info[i].ps_pic_buf->i4_used_as_ref)
1122         {
1123             ps_dpb_info[i].ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;
1124             ps_dpb_info[i].ps_prev_dpb = NULL;
1125             //Release physical buffer
1126             ih264_buf_mgr_release(ps_buf_mgr, ps_dpb_info[i].ps_pic_buf->i4_buf_id,
1127                                   BUF_MGR_REF);
1128 
1129             ps_dpb_info[i].ps_pic_buf = NULL;
1130         }
1131     }
1132     ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;
1133     ps_dpb_mgr->u1_num_long_term_ref_bufs  = 0;
1134     ps_dpb_mgr->ps_dpb_short_term_head = NULL;
1135     ps_dpb_mgr->ps_dpb_long_term_head  = NULL;
1136 
1137 }
1138 
1139 /**
1140  *******************************************************************************
1141  *
1142  * @brief
1143  *  deletes all pictures from DPB
1144  *
1145  * @par Description:
1146  *  Deletes all pictures present in the DPB manager
1147  *
1148  * @param[in] ps_buf_mgr
1149  *  Pointer to buffer manager structure
1150  *
1151  * @param[in] u1_disp_bufs
1152  *  Number of buffers to be deleted
1153  *
1154  * @returns
1155  *
1156  * @remarks
1157  *
1158  *
1159  *******************************************************************************
1160  */
1161 
ih264_dpb_mgr_release_pics(buf_mgr_t * ps_buf_mgr,UWORD8 u1_disp_bufs)1162 void ih264_dpb_mgr_release_pics(buf_mgr_t *ps_buf_mgr, UWORD8 u1_disp_bufs)
1163 {
1164     WORD8 i;
1165     UWORD32 buf_status;
1166     ASSERT(0);
1167 
1168     for(i = 0; i < u1_disp_bufs; i++)
1169     {
1170         buf_status = ih264_buf_mgr_get_status(ps_buf_mgr, i);
1171         if(0 != buf_status)
1172         {
1173             ih264_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, i, BUF_MGR_REF);
1174         }
1175     }
1176 }
1177