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
75void 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
119WORD32 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
196void 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 */
275pic_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 */
342pic_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
395pic_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
445void 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
493void 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