1 /******************************************************************************
2 *
3 * Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
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 /**
19  *******************************************************************************
20  * @file
21  *  ihevc_dpb_mgr.c
22  *
23  * @brief
24  *  Function definitions used for decoded picture buffer management
25  *
26  * @author
27  *  Srinivas T
28  *
29  * @par List of Functions:
30  *   - ihevc_dpb_mgr_init()
31  *   - ihevc_dpb_mgr_del_lt()
32  *   - ihevc_dpb_mgr_insert_lt()
33  *   - ihevc_dpb_mgr_del_st_or_make_lt()
34  *   - ihevc_dpb_mgr_insert_st()
35  *   - ihevc_dpb_mgr_reset()
36  *   - ihevc_dpb_mgr_release_pics()
37  *
38  * @remarks
39  *  None
40  *
41  *******************************************************************************
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 
47 #include "ihevc_typedefs.h"
48 #include "ihevc_defs.h"
49 #include "ihevc_macros.h"
50 #include "ihevc_func_selector.h"
51 #include "ihevc_structs.h"
52 #include "ihevc_buf_mgr.h"
53 #include "ihevc_dpb_mgr.h"
54 
55 /**
56  *******************************************************************************
57  *
58  * @brief
59  *  DPB manager initializer
60  *
61  * @par Description:
62  *  Initialises the DPB manager structure
63  *
64  * @param[in] ps_dpb_mgr
65  *  Pointer to the DPB manager structure
66  *
67  * @returns
68  *
69  * @remarks
70  *
71  *
72  *******************************************************************************
73  */
74 
ihevc_dpb_mgr_init(dpb_mgr_t * ps_dpb_mgr)75 void ihevc_dpb_mgr_init(dpb_mgr_t *ps_dpb_mgr)
76 {
77     UWORD32 i;
78     dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;
79     for(i = 0; i < MAX_DPB_BUFS; i++)
80     {
81         ps_dpb_info[i].ps_prev_dpb = NULL;
82         ps_dpb_info[i].ps_pic_buf = NULL;
83 
84     }
85 
86     ps_dpb_mgr->u1_num_ref_bufs = 0;
87     ps_dpb_mgr->ps_dpb_head = NULL;
88 
89 }
90 
91 
92 /**
93  *******************************************************************************
94  *
95  * @brief
96  *  Adds a reference picture into the linked  list
97  *
98  * @par Description:
99  *  Adds the reference buffer with the given buffer id into the DPB manager
100  *
101  *
102  * @param[in] ps_dpb_mgr
103  *  Pointer to the DPB manager structure
104  *
105  * @param[in] ps_picBuf
106  *  Pointer to the picture buffer
107  *
108  * @param[in] buf_id
109  *  buffer id of the picture buffer
110  *
111  * @returns  0 if successful, -1 otherwise
112  *
113  * @remarks
114  *
115  *
116  *******************************************************************************
117  */
118 
ihevc_dpb_mgr_insert_ref(dpb_mgr_t * ps_dpb_mgr,pic_buf_t * ps_pic_buf,WORD32 buf_id)119 WORD32 ihevc_dpb_mgr_insert_ref(dpb_mgr_t *ps_dpb_mgr,
120                                 pic_buf_t *ps_pic_buf,
121                                 WORD32 buf_id)
122 {
123     int i;
124     dpb_info_t *ps_dpb_info;
125 
126     ps_dpb_info = ps_dpb_mgr->as_dpb_info;
127 
128     /* Return error if buffer is already present in the DPB */
129     for(i = 0; i < MAX_DPB_BUFS; i++)
130     {
131         if((ps_dpb_info[i].ps_pic_buf == ps_pic_buf)
132                         && (ps_dpb_info[i].ps_pic_buf->u1_used_as_ref))
133         {
134             return (-1);
135         }
136 
137 
138     }
139 
140     /* Find an unused DPB location */
141     for(i = 0; i < MAX_DPB_BUFS; i++)
142     {
143         if(NULL == ps_dpb_info[i].ps_pic_buf)
144         {
145             break;
146         }
147     }
148     if(i == MAX_DPB_BUFS)
149     {
150         return (-1);
151     }
152 
153     /* Create DPB info */
154     ps_dpb_info[i].ps_pic_buf = ps_pic_buf;
155     ps_dpb_info[i].ps_prev_dpb = ps_dpb_mgr->ps_dpb_head;
156     ps_dpb_info[i].ps_pic_buf->u1_buf_id = buf_id;
157     ps_dpb_info[i].ps_pic_buf->u1_used_as_ref = SHORT_TERM_REF;
158 
159     /* update the head node of linked list to point to the current picture */
160     ps_dpb_mgr->ps_dpb_head = ps_dpb_info + i;
161 
162     /* Increment Short term buffer count */
163     ps_dpb_mgr->u1_num_ref_bufs++;
164 
165     return 0;
166 }
167 
168 /**
169  *******************************************************************************
170  *
171  * @brief
172  *  Deletes a reference buffer from the dpb manager
173  *
174  * @par Description:
175  *  Delete short term reference with a given POC from the linked
176  *  list
177  *
178  * @param[in] ps_dpb_mgr
179  *  Pointer to DPB Manager structure
180  *
181  * @param[in] ps_buf_mgr
182  *  Pointer to buffer manager structure
183  *
184  * @param[in] u4_abs_poc
185  *  Node's absolute poc
186  *
187  *
188  * @returns  0 if successful, -1 otherwise
189  *
190  * @remarks
191  *
192  *
193  *******************************************************************************
194  */
195 
ihevc_dpb_mgr_del_ref(dpb_mgr_t * ps_dpb_mgr,buf_mgr_t * ps_buf_mgr,WORD32 i4_abs_poc)196 void ihevc_dpb_mgr_del_ref(dpb_mgr_t *ps_dpb_mgr,
197                            buf_mgr_t *ps_buf_mgr,
198                            WORD32 i4_abs_poc)
199 {
200     int i;
201     dpb_info_t *ps_next_dpb;
202 
203     dpb_info_t *ps_unmark_node;
204     UWORD8 u1_del_node;
205     UNUSED(u1_del_node);
206     u1_del_node = 0;
207 
208     /* Find the node with matching absolute POC */
209     ps_next_dpb = ps_dpb_mgr->ps_dpb_head;
210     if(ps_next_dpb->ps_pic_buf->i4_abs_poc == i4_abs_poc)
211     {
212         ps_unmark_node = ps_next_dpb;
213     }
214     else
215     {
216         for(i = 1; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
217         {
218             if(ps_next_dpb->ps_prev_dpb->ps_pic_buf->i4_abs_poc == i4_abs_poc)
219                 break;
220             ps_next_dpb = ps_next_dpb->ps_prev_dpb;
221         }
222 
223         if(i == ps_dpb_mgr->u1_num_ref_bufs)
224         {
225             return;
226         }
227         else
228             ps_unmark_node = ps_next_dpb->ps_prev_dpb;
229     }
230 
231     if(ps_unmark_node == ps_dpb_mgr->ps_dpb_head)
232     {
233         ps_dpb_mgr->ps_dpb_head = ps_unmark_node->ps_prev_dpb;
234     }
235     else
236     {
237         ps_next_dpb->ps_prev_dpb = ps_unmark_node->ps_prev_dpb; //update link
238         ps_unmark_node->ps_prev_dpb = NULL;
239     }
240     ps_dpb_mgr->u1_num_ref_bufs--; //decrement buffer count
241 
242     /* Release the physical buffer */
243     ihevc_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, ps_unmark_node->ps_pic_buf->u1_buf_id,
244                           BUF_MGR_REF);
245     ps_unmark_node->ps_prev_dpb = NULL;
246     ps_unmark_node->ps_pic_buf = NULL;
247 }
248 
249 
250 /**
251  *******************************************************************************
252  *
253  * @brief
254  *  Gets a buffer with abs_poc closest to the current poc
255  *
256  * @par Description:
257  *  Returns the pointer to the picture buffer whose poc is equal to abs_poc
258  *
259  * @param[in] ps_dpb_mgr
260  *  Pointer to DPB Manager structure
261  *
262  * @param[out] ps_pic_buf
263  *  Pointer to picture buffer
264 
265  * @param[in] abs_poc
266  *  poc of the buffer to be returned
267  *
268  * @returns
269  *  0 if successful, pic_buf otherwise
270  * @remarks
271  *
272  *
273  *******************************************************************************
274  */
ihevc_dpb_mgr_get_ref_by_nearest_poc(dpb_mgr_t * ps_dpb_mgr,WORD32 cur_abs_poc)275 pic_buf_t* ihevc_dpb_mgr_get_ref_by_nearest_poc(dpb_mgr_t *ps_dpb_mgr, WORD32 cur_abs_poc)
276 {
277     WORD32 i;
278     WORD32 min_diff = 0x7FFFFFFF;
279     pic_buf_t *ps_pic_buf = NULL;
280 
281     for(i = 0; i < MAX_DPB_BUFS; i++)
282     {
283         if((ps_dpb_mgr->as_dpb_info[i].ps_pic_buf) &&
284                         (ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->u1_used_as_ref != UNUSED_FOR_REF))
285         {
286             WORD32 poc_diff = cur_abs_poc - ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->i4_abs_poc;
287             if((poc_diff > 0) && (poc_diff < min_diff))
288             {
289                 min_diff = poc_diff;
290                 ps_pic_buf = ps_dpb_mgr->as_dpb_info[i].ps_pic_buf;
291             }
292         }
293     }
294 
295     if(NULL == ps_pic_buf)
296     {
297         min_diff = 0x7FFFFFFF;
298         for(i = 0; i < MAX_DPB_BUFS; i++)
299         {
300             if((ps_dpb_mgr->as_dpb_info[i].ps_pic_buf) &&
301                             (ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->u1_used_as_ref != UNUSED_FOR_REF))
302             {
303                 WORD32 poc_diff = cur_abs_poc - ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->i4_abs_poc;
304                 if(ABS(poc_diff) < min_diff)
305                 {
306                     min_diff = ABS(poc_diff);
307                     ps_pic_buf = ps_dpb_mgr->as_dpb_info[i].ps_pic_buf;
308                 }
309             }
310         }
311     }
312 
313     return ps_pic_buf;
314 }
315 
316 
317 /**
318  *******************************************************************************
319  *
320  * @brief
321  *  Gets a buffer with abs_poc
322  *
323  * @par Description:
324  *  Returns the pointer to the picture buffer whose poc is equal to abs_poc
325  *
326  * @param[in] ps_dpb_mgr
327  *  Pointer to DPB Manager structure
328  *
329  * @param[out] ps_pic_buf
330  *  Pointer to picture buffer
331 
332  * @param[in] abs_poc
333  *  poc of the buffer to be returned
334  *
335  * @returns
336  *  0 if successful, pic_buf otherwise
337  * @remarks
338  *
339  *
340  *******************************************************************************
341  */
ihevc_dpb_mgr_get_ref_by_poc(dpb_mgr_t * ps_dpb_mgr,WORD32 abs_poc)342 pic_buf_t* ihevc_dpb_mgr_get_ref_by_poc(dpb_mgr_t *ps_dpb_mgr, WORD32 abs_poc)
343 {
344     UWORD32 i;
345     dpb_info_t *ps_next_ref;
346     pic_buf_t *ps_pic_buf = NULL;
347 
348 
349     ps_next_ref = ps_dpb_mgr->ps_dpb_head;
350     for(i = 0; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
351     {
352         if(ps_next_ref->ps_pic_buf->i4_abs_poc == abs_poc)
353         {
354             ps_pic_buf = ps_next_ref->ps_pic_buf;
355             break;
356         }
357 
358         ps_next_ref = ps_next_ref->ps_prev_dpb;
359     }
360 
361     if(i == ps_dpb_mgr->u1_num_ref_bufs)
362     {
363         ps_pic_buf = NULL;
364     }
365 
366     return ps_pic_buf;
367 }
368 
369 /**
370  *******************************************************************************
371  *
372  * @brief
373  *  Gets a buffer with poc_lsb
374  *
375  * @par Description:
376  *  Returns the pointer to the picture buffer whose poc is equal to poc_lsb
377  *
378  * @param[in] ps_dpb_mgr
379  *  Pointer to DPB Manager structure
380  *
381  * @param[out] ps_pic_buf
382  *  Pointer to picture buffer
383 
384  * @param[in] poc_lsb
385  *  poc_lsb of the buffer to be returned
386  *
387  * @returns
388  *  0 if successful, pic_buf otherwise
389  * @remarks
390  *
391  *
392  *******************************************************************************
393  */
394 
ihevc_dpb_mgr_get_ref_by_poc_lsb(dpb_mgr_t * ps_dpb_mgr,WORD32 poc_lsb)395 pic_buf_t* ihevc_dpb_mgr_get_ref_by_poc_lsb(dpb_mgr_t *ps_dpb_mgr, WORD32 poc_lsb)
396 {
397     pic_buf_t *ps_pic_buf = NULL;
398     UWORD32 i;
399     dpb_info_t *ps_next_ref;
400 
401     ps_next_ref = ps_dpb_mgr->ps_dpb_head;
402     for(i = 0; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
403     {
404         if(ps_next_ref->ps_pic_buf->i4_poc_lsb == poc_lsb)
405         {
406             ps_pic_buf = ps_next_ref->ps_pic_buf;
407             break;
408         }
409 
410         ps_next_ref = ps_next_ref->ps_prev_dpb;
411     }
412 
413     if(i == ps_dpb_mgr->u1_num_ref_bufs)
414     {
415         ps_pic_buf = NULL;
416     }
417 
418     return ps_pic_buf;
419 }
420 
421 
422 /**
423  *******************************************************************************
424  *
425  * @brief
426  *  Resets the DPB manager
427  *
428  * @par Description:
429  *  Re-initialises the DPB manager structure
430  *
431  * @param[in] ps_dpb_mgr
432  *  Pointer to DPB Manager structure
433  *
434  * @param[in] ps_buf_mgr
435  *  Pointer to buffer manager structure
436  *
437  * @returns
438  *
439  * @remarks
440  *
441  *
442  *******************************************************************************
443  */
444 
ihevc_dpb_mgr_reset(dpb_mgr_t * ps_dpb_mgr,buf_mgr_t * ps_buf_mgr)445 void ihevc_dpb_mgr_reset(dpb_mgr_t *ps_dpb_mgr, buf_mgr_t *ps_buf_mgr)
446 {
447     int i;
448     dpb_info_t *ps_dpb_info;
449 
450     ps_dpb_info = ps_dpb_mgr->as_dpb_info;
451 
452     for(i = 0; i < MAX_DPB_BUFS; i++)
453     {
454         if(ps_dpb_info[i].ps_pic_buf->u1_used_as_ref)
455         {
456             ps_dpb_info[i].ps_pic_buf->u1_used_as_ref = UNUSED_FOR_REF;
457             ps_dpb_info[i].ps_prev_dpb = NULL;
458             //Release physical buffer
459             ihevc_buf_mgr_release(ps_buf_mgr, ps_dpb_info[i].ps_pic_buf->u1_buf_id,
460                                   BUF_MGR_REF);
461 
462             ps_dpb_info[i].ps_pic_buf = NULL;
463         }
464     }
465     ps_dpb_mgr->u1_num_ref_bufs = 0;
466     ps_dpb_mgr->ps_dpb_head = NULL;
467 
468 }
469 
470 /**
471  *******************************************************************************
472  *
473  * @brief
474  *  deletes all pictures from DPB
475  *
476  * @par Description:
477  *  Deletes all pictures present in the DPB manager
478  *
479  * @param[in] ps_buf_mgr
480  *  Pointer to buffer manager structure
481  *
482  * @param[in] u1_disp_bufs
483  *  Number of buffers to be deleted
484  *
485  * @returns
486  *
487  * @remarks
488  *
489  *
490  *******************************************************************************
491  */
492 
ihevc_dpb_mgr_release_pics(buf_mgr_t * ps_buf_mgr,UWORD8 u1_disp_bufs)493 void ihevc_dpb_mgr_release_pics(buf_mgr_t *ps_buf_mgr, UWORD8 u1_disp_bufs)
494 {
495     WORD8 i;
496     UWORD32 buf_status;
497 
498     for(i = 0; i < u1_disp_bufs; i++)
499     {
500         buf_status = ihevc_buf_mgr_get_status(ps_buf_mgr, i);
501         if(0 != buf_status)
502         {
503             ihevc_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, i, BUF_MGR_REF);
504         }
505     }
506 }
507