1/* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18#include "avclib_common.h"
19
20#define DPB_MEM_ATTR 0
21
22AVCStatus InitDPB(AVCHandle *avcHandle, AVCCommonObj *video, int FrameHeightInMbs, int PicWidthInMbs, bool padding)
23{
24    AVCDecPicBuffer *dpb = video->decPicBuf;
25    int level, framesize, num_fs;
26    void *userData = avcHandle->userData;
27#ifndef PV_MEMORY_POOL
28    uint32 addr;
29#endif
30    uint16 refIdx = 0;
31    level = video->currSeqParams->level_idc;
32
33    for (num_fs = 0; num_fs < MAX_FS; num_fs++)
34    {
35        dpb->fs[num_fs] = NULL;
36    }
37
38    framesize = (int)(((FrameHeightInMbs * PicWidthInMbs) << 7) * 3);
39    if (padding)
40    {
41        video->padded_size = (int)((((FrameHeightInMbs + 2) * (PicWidthInMbs + 2)) << 7) * 3) - framesize;
42    }
43    else
44    {
45        video->padded_size = 0;
46    }
47
48#ifndef PV_MEMORY_POOL
49    if (dpb->decoded_picture_buffer)
50    {
51        avcHandle->CBAVC_Free(userData, (int)dpb->decoded_picture_buffer);
52        dpb->decoded_picture_buffer = NULL;
53    }
54#endif
55    /* need to allocate one extra frame for current frame, DPB only defines for reference frames */
56
57    dpb->num_fs = (uint32)(MaxDPBX2[mapLev2Idx[level]] << 2) / (3 * FrameHeightInMbs * PicWidthInMbs) + 1;
58    if (dpb->num_fs > MAX_FS)
59    {
60        dpb->num_fs = MAX_FS;
61    }
62
63    if (video->currSeqParams->num_ref_frames + 1 > (uint32)dpb->num_fs)
64    {
65        dpb->num_fs = video->currSeqParams->num_ref_frames + 1;
66    }
67
68    dpb->dpb_size = dpb->num_fs * (framesize + video->padded_size);
69//  dpb->dpb_size = (uint32)MaxDPBX2[mapLev2Idx[level]]*512 + framesize;
70
71#ifndef PV_MEMORY_POOL
72    dpb->decoded_picture_buffer = (uint8*) avcHandle->CBAVC_Malloc(userData, dpb->dpb_size, 100/*DPB_MEM_ATTR*/);
73
74    if (dpb->decoded_picture_buffer == NULL || dpb->decoded_picture_buffer&0x3) // not word aligned
75        return AVC_MEMORY_FAIL;
76#endif
77    dpb->used_size = 0;
78    num_fs = 0;
79
80    while (num_fs < dpb->num_fs)
81    {
82        /*  fs is an array pointers to AVCDecPicture */
83        dpb->fs[num_fs] = (AVCFrameStore*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCFrameStore), 101/*DEFAULT_ATTR*/);
84        if (dpb->fs[num_fs] == NULL)
85        {
86            return AVC_MEMORY_FAIL;
87        }
88#ifndef PV_MEMORY_POOL
89        /* assign the actual memory for Sl, Scb, Scr */
90        dpb->fs[num_fs]->base_dpb = dpb->decoded_picture_buffer + dpb->used_size;
91#endif
92        dpb->fs[num_fs]->IsReference = 0;
93        dpb->fs[num_fs]->IsLongTerm = 0;
94        dpb->fs[num_fs]->IsOutputted = 3;
95        dpb->fs[num_fs]->frame.RefIdx = refIdx++; /* this value will remain unchanged through out the encoding session */
96        dpb->fs[num_fs]->frame.picType = AVC_FRAME;
97        dpb->fs[num_fs]->frame.isLongTerm = 0;
98        dpb->fs[num_fs]->frame.isReference = 0;
99        video->RefPicList0[num_fs] = &(dpb->fs[num_fs]->frame);
100        dpb->fs[num_fs]->frame.padded = 0;
101        dpb->used_size += (framesize + video->padded_size);
102        num_fs++;
103    }
104
105    return AVC_SUCCESS;
106}
107
108OSCL_EXPORT_REF AVCStatus AVCConfigureSequence(AVCHandle *avcHandle, AVCCommonObj *video, bool padding)
109{
110    void *userData = avcHandle->userData;
111    AVCDecPicBuffer *dpb = video->decPicBuf;
112    int framesize, ii; /* size of one frame */
113    uint PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs, PicSizeInMapUnits;
114    uint num_fs;
115    /* derived variables from SPS */
116    PicWidthInMbs = video->currSeqParams->pic_width_in_mbs_minus1 + 1;
117    PicHeightInMapUnits = video->currSeqParams->pic_height_in_map_units_minus1 + 1 ;
118    FrameHeightInMbs = (2 - video->currSeqParams->frame_mbs_only_flag) * PicHeightInMapUnits ;
119    PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits ;
120
121    if (video->PicSizeInMapUnits != PicSizeInMapUnits || video->currSeqParams->level_idc != video->level_idc)
122    {
123        /* make sure you mark all the frames as unused for reference for flushing*/
124        for (ii = 0; ii < dpb->num_fs; ii++)
125        {
126            dpb->fs[ii]->IsReference = 0;
127            dpb->fs[ii]->IsOutputted |= 0x02;
128        }
129
130        num_fs = (uint32)(MaxDPBX2[(uint32)mapLev2Idx[video->currSeqParams->level_idc]] << 2) / (3 * PicSizeInMapUnits) + 1;
131        if (num_fs >= MAX_FS)
132        {
133            num_fs = MAX_FS;
134        }
135#ifdef PV_MEMORY_POOL
136        if (padding)
137        {
138            avcHandle->CBAVC_DPBAlloc(avcHandle->userData,
139                                      PicSizeInMapUnits + ((PicWidthInMbs + 2) << 1) + (PicHeightInMapUnits << 1), num_fs);
140        }
141        else
142        {
143            avcHandle->CBAVC_DPBAlloc(avcHandle->userData, PicSizeInMapUnits, num_fs);
144        }
145#endif
146        CleanUpDPB(avcHandle, video);
147        if (InitDPB(avcHandle, video, FrameHeightInMbs, PicWidthInMbs, padding) != AVC_SUCCESS)
148        {
149            return AVC_FAIL;
150        }
151        /*  Allocate video->mblock upto PicSizeInMbs and populate the structure  such as the neighboring MB pointers.   */
152        framesize = (FrameHeightInMbs * PicWidthInMbs);
153        if (video->mblock)
154        {
155            avcHandle->CBAVC_Free(userData, video->mblock);
156            video->mblock = NULL;
157        }
158        video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR);
159        if (video->mblock == NULL)
160        {
161            return AVC_FAIL;
162        }
163        for (ii = 0; ii < framesize; ii++)
164        {
165            video->mblock[ii].slice_id = -1;
166        }
167        /* Allocate memory for intra prediction */
168#ifdef MB_BASED_DEBLOCK
169        video->intra_pred_top = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 4, FAST_MEM_ATTR);
170        if (video->intra_pred_top == NULL)
171        {
172            return AVC_FAIL;
173        }
174        video->intra_pred_top_cb = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR);
175        if (video->intra_pred_top_cb == NULL)
176        {
177            return AVC_FAIL;
178        }
179        video->intra_pred_top_cr = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR);
180        if (video->intra_pred_top_cr == NULL)
181        {
182            return AVC_FAIL;
183        }
184
185#endif
186        /*  Allocate slice group MAP map */
187
188        if (video->MbToSliceGroupMap)
189        {
190            avcHandle->CBAVC_Free(userData, video->MbToSliceGroupMap);
191            video->MbToSliceGroupMap = NULL;
192        }
193        video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * PicSizeInMapUnits * 2, 7/*DEFAULT_ATTR*/);
194        if (video->MbToSliceGroupMap == NULL)
195        {
196            return AVC_FAIL;
197        }
198        video->PicSizeInMapUnits = PicSizeInMapUnits;
199        video->level_idc = video->currSeqParams->level_idc;
200
201    }
202    return AVC_SUCCESS;
203}
204
205OSCL_EXPORT_REF AVCStatus CleanUpDPB(AVCHandle *avcHandle, AVCCommonObj *video)
206{
207    AVCDecPicBuffer *dpb = video->decPicBuf;
208    int ii;
209    void *userData = avcHandle->userData;
210
211    for (ii = 0; ii < MAX_FS; ii++)
212    {
213        if (dpb->fs[ii] != NULL)
214        {
215            avcHandle->CBAVC_Free(userData, dpb->fs[ii]);
216            dpb->fs[ii] = NULL;
217        }
218    }
219#ifndef PV_MEMORY_POOL
220    if (dpb->decoded_picture_buffer)
221    {
222        avcHandle->CBAVC_Free(userData, dpb->decoded_picture_buffer);
223        dpb->decoded_picture_buffer = NULL;
224    }
225#endif
226    dpb->used_size = 0;
227    dpb->dpb_size = 0;
228
229    return AVC_SUCCESS;
230}
231
232OSCL_EXPORT_REF AVCStatus DPBInitBuffer(AVCHandle *avcHandle, AVCCommonObj *video)
233{
234    AVCDecPicBuffer *dpb = video->decPicBuf;
235    int ii, status;
236
237    /* Before doing any decoding, check if there's a frame memory available */
238    /* look for next unused dpb->fs, or complementary field pair */
239    /* video->currPic is assigned to this */
240
241    /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */
242
243    for (ii = 0; ii < dpb->num_fs; ii++)
244    {
245        /* looking for the one not used or not reference and has been outputted */
246        if (dpb->fs[ii]->IsReference == 0 && dpb->fs[ii]->IsOutputted == 3)
247        {
248            video->currFS = dpb->fs[ii];
249#ifdef PV_MEMORY_POOL
250            status = avcHandle->CBAVC_FrameBind(avcHandle->userData, ii, &(video->currFS->base_dpb));
251            if (status == AVC_FAIL)
252            {
253                return AVC_NO_BUFFER; /* this should not happen */
254            }
255#endif
256            break;
257        }
258    }
259    if (ii == dpb->num_fs)
260    {
261        return AVC_PICTURE_OUTPUT_READY; /* no empty frame available */
262    }
263    return AVC_SUCCESS;
264}
265
266OSCL_EXPORT_REF void DPBInitPic(AVCCommonObj *video, int CurrPicNum)
267{
268    int offset = 0;
269    int offsetc = 0;
270    int luma_framesize;
271    /* this part has to be set here, assuming that slice header and POC have been decoded. */
272    /* used in GetOutput API */
273    video->currFS->PicOrderCnt = video->PicOrderCnt;
274    video->currFS->FrameNum = video->sliceHdr->frame_num;
275    video->currFS->FrameNumWrap = CurrPicNum;    // MC_FIX
276    /* initialize everything to zero */
277    video->currFS->IsOutputted = 0;
278    video->currFS->IsReference = 0;
279    video->currFS->IsLongTerm = 0;
280    video->currFS->frame.isReference = FALSE;
281    video->currFS->frame.isLongTerm = FALSE;
282
283    /* initialize the pixel pointer to NULL */
284    video->currFS->frame.Sl = video->currFS->frame.Scb = video->currFS->frame.Scr = NULL;
285
286    /* determine video->currPic */
287    /* assign dbp->base_dpb to fs[i]->frame.Sl, Scb, Scr .*/
288    /* For PicSizeInMbs, see DecodeSliceHeader() */
289
290    video->currPic = &(video->currFS->frame);
291
292    video->currPic->padded = 0; // reset this flag to not-padded
293
294    if (video->padded_size)
295    {
296        offset = ((video->PicWidthInSamplesL + 32) << 4) + 16; // offset to the origin
297        offsetc = (offset >> 2) + 4;
298        luma_framesize = (int)((((video->FrameHeightInMbs + 2) * (video->PicWidthInMbs + 2)) << 8));
299    }
300    else
301        luma_framesize = video->PicSizeInMbs << 8;
302
303
304    video->currPic->Sl = video->currFS->base_dpb + offset;
305    video->currPic->Scb = video->currFS->base_dpb  + luma_framesize + offsetc;
306    video->currPic->Scr = video->currPic->Scb + (luma_framesize >> 2);
307    video->currPic->pitch = video->PicWidthInSamplesL + (video->padded_size == 0 ? 0 : 32);
308
309
310    video->currPic->height = video->PicHeightInSamplesL;
311    video->currPic->width = video->PicWidthInSamplesL;
312    video->currPic->PicNum = CurrPicNum;
313}
314
315/* to release skipped frame after encoding */
316OSCL_EXPORT_REF void DPBReleaseCurrentFrame(AVCHandle *avcHandle, AVCCommonObj *video)
317{
318    AVCDecPicBuffer *dpb = video->decPicBuf;
319    int ii;
320
321    video->currFS->IsOutputted = 3; // return this buffer.
322
323#ifdef PV_MEMORY_POOL /* for non-memory pool, no need to do anything */
324
325    /* search for current frame index */
326    ii = dpb->num_fs;
327    while (ii--)
328    {
329        if (dpb->fs[ii] == video->currFS)
330        {
331            avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii);
332            break;
333        }
334    }
335#endif
336
337    return ;
338}
339
340/* see subclause 8.2.5.1 */
341OSCL_EXPORT_REF AVCStatus StorePictureInDPB(AVCHandle *avcHandle, AVCCommonObj *video)
342{
343    AVCStatus status;
344    AVCDecPicBuffer *dpb = video->decPicBuf;
345    AVCSliceHeader *sliceHdr = video->sliceHdr;
346    int ii, num_ref;
347
348    /* number 1 of 8.2.5.1, we handle gaps in frame_num differently without using the memory */
349    /* to be done!!!! */
350
351    /* number 3 of 8.2.5.1 */
352    if (video->nal_unit_type == AVC_NALTYPE_IDR)
353    {
354        for (ii = 0; ii < dpb->num_fs; ii++)
355        {
356            if (dpb->fs[ii] != video->currFS) /* not current frame */
357            {
358                dpb->fs[ii]->IsReference = 0; /* mark as unused for reference */
359                dpb->fs[ii]->IsLongTerm = 0;  /* but still used until output */
360                dpb->fs[ii]->IsOutputted |= 0x02;
361#ifdef PV_MEMORY_POOL
362                if (dpb->fs[ii]->IsOutputted == 3)
363                {
364                    avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii);
365                }
366#endif
367            }
368        }
369
370        video->currPic->isReference = TRUE;
371        video->currFS->IsReference = 3;
372
373        if (sliceHdr->long_term_reference_flag == 0)
374        {
375            video->currPic->isLongTerm = FALSE;
376            video->currFS->IsLongTerm = 0;
377            video->MaxLongTermFrameIdx = -1;
378        }
379        else
380        {
381            video->currPic->isLongTerm = TRUE;
382            video->currFS->IsLongTerm = 3;
383            video->currFS->LongTermFrameIdx = 0;
384            video->MaxLongTermFrameIdx = 0;
385        }
386        if (sliceHdr->no_output_of_prior_pics_flag)
387        {
388            for (ii = 0; ii < dpb->num_fs; ii++)
389            {
390                if (dpb->fs[ii] != video->currFS) /* not current frame */
391                {
392                    dpb->fs[ii]->IsOutputted = 3;
393#ifdef PV_MEMORY_POOL
394                    avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii);
395#endif
396                }
397            }
398        }
399        video->mem_mgr_ctrl_eq_5 = TRUE;    /* flush reference frames MC_FIX */
400    }
401    else
402    {
403        if (video->currPic->isReference == TRUE)
404        {
405            if (sliceHdr->adaptive_ref_pic_marking_mode_flag == 0)
406            {
407                status = sliding_window_process(avcHandle, video, dpb); /* we may have to do this after adaptive_memory_marking */
408            }
409            else
410            {
411                status = adaptive_memory_marking(avcHandle, video, dpb, sliceHdr);
412            }
413            if (status != AVC_SUCCESS)
414            {
415                return status;
416            }
417        }
418    }
419    /* number 4 of 8.2.5.1 */
420    /* This basically says every frame must be at least used for short-term ref. */
421    /* Need to be revisited!!! */
422    /* look at insert_picture_in_dpb() */
423
424
425
426    if (video->nal_unit_type != AVC_NALTYPE_IDR && video->currPic->isLongTerm == FALSE)
427    {
428        if (video->currPic->isReference)
429        {
430            video->currFS->IsReference = 3;
431        }
432        else
433        {
434            video->currFS->IsReference = 0;
435        }
436        video->currFS->IsLongTerm = 0;
437    }
438
439    /* check if number of reference frames doesn't exceed num_ref_frames */
440    num_ref = 0;
441    for (ii = 0; ii < dpb->num_fs; ii++)
442    {
443        if (dpb->fs[ii]->IsReference)
444        {
445            num_ref++;
446        }
447    }
448
449    if (num_ref > (int)video->currSeqParams->num_ref_frames)
450    {
451        return AVC_FAIL; /* out of range */
452    }
453
454    return AVC_SUCCESS;
455}
456
457
458AVCStatus sliding_window_process(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb)
459{
460    int ii, numShortTerm, numLongTerm;
461    int32 MinFrameNumWrap;
462    int MinIdx;
463
464
465    numShortTerm = 0;
466    numLongTerm = 0;
467    for (ii = 0; ii < dpb->num_fs; ii++)
468    {
469        if (dpb->fs[ii] != video->currFS) /* do not count the current frame */
470        {
471            if (dpb->fs[ii]->IsLongTerm)
472            {
473                numLongTerm++;
474            }
475            else if (dpb->fs[ii]->IsReference)
476            {
477                numShortTerm++;
478            }
479        }
480    }
481
482    while (numShortTerm + numLongTerm >= (int)video->currSeqParams->num_ref_frames)
483    {
484        /* get short-term ref frame with smallest PicOrderCnt */
485        /* this doesn't work for all I-slice clip since PicOrderCnt will not be initialized */
486
487        MinFrameNumWrap = 0x7FFFFFFF;
488        MinIdx = -1;
489        for (ii = 0; ii < dpb->num_fs; ii++)
490        {
491            if (dpb->fs[ii]->IsReference && !dpb->fs[ii]->IsLongTerm)
492            {
493                if (dpb->fs[ii]->FrameNumWrap < MinFrameNumWrap)
494                {
495                    MinFrameNumWrap = dpb->fs[ii]->FrameNumWrap;
496                    MinIdx = ii;
497                }
498            }
499        }
500        if (MinIdx < 0) /* something wrong, impossible */
501        {
502            return AVC_FAIL;
503        }
504
505        /* mark the frame with smallest PicOrderCnt to be unused for reference */
506        dpb->fs[MinIdx]->IsReference = 0;
507        dpb->fs[MinIdx]->IsLongTerm = 0;
508        dpb->fs[MinIdx]->frame.isReference = FALSE;
509        dpb->fs[MinIdx]->frame.isLongTerm = FALSE;
510        dpb->fs[MinIdx]->IsOutputted |= 0x02;
511#ifdef PV_MEMORY_POOL
512        if (dpb->fs[MinIdx]->IsOutputted == 3)
513        {
514            avcHandle->CBAVC_FrameUnbind(avcHandle->userData, MinIdx);
515        }
516#endif
517        numShortTerm--;
518    }
519    return AVC_SUCCESS;
520}
521
522/* see subclause 8.2.5.4 */
523AVCStatus adaptive_memory_marking(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, AVCSliceHeader *sliceHdr)
524{
525    int ii;
526
527    ii = 0;
528    while (ii < MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[ii] != 0)
529    {
530        switch (sliceHdr->memory_management_control_operation[ii])
531        {
532            case 1:
533                MemMgrCtrlOp1(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii]);
534                //      update_ref_list(dpb);
535                break;
536            case 2:
537                MemMgrCtrlOp2(avcHandle, dpb, sliceHdr->long_term_pic_num[ii]);
538                break;
539            case 3:
540                MemMgrCtrlOp3(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii], sliceHdr->long_term_frame_idx[ii]);
541                break;
542            case 4:
543                MemMgrCtrlOp4(avcHandle, video, dpb, sliceHdr->max_long_term_frame_idx_plus1[ii]);
544                break;
545            case 5:
546                MemMgrCtrlOp5(avcHandle, video, dpb);
547                video->currFS->FrameNum = 0;    //
548                video->currFS->PicOrderCnt = 0;
549                break;
550            case 6:
551                MemMgrCtrlOp6(avcHandle, video, dpb, sliceHdr->long_term_frame_idx[ii]);
552                break;
553        }
554        ii++;
555    }
556
557    if (ii == MAX_DEC_REF_PIC_MARKING)
558    {
559        return AVC_FAIL; /* exceed the limit */
560    }
561
562    return AVC_SUCCESS;
563}
564
565
566/* see subclause 8.2.5.4.1, mark short-term picture as "unused for reference" */
567void MemMgrCtrlOp1(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, int difference_of_pic_nums_minus1)
568{
569    int picNumX, ii;
570
571    picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1);
572
573    for (ii = 0; ii < dpb->num_fs; ii++)
574    {
575        if (dpb->fs[ii]->IsReference == 3 && dpb->fs[ii]->IsLongTerm == 0)
576        {
577            if (dpb->fs[ii]->frame.PicNum == picNumX)
578            {
579                unmark_for_reference(avcHandle, dpb, ii);
580                return ;
581            }
582        }
583    }
584
585    return ;
586}
587
588/* see subclause 8.2.5.4.2 mark long-term picture as "unused for reference" */
589void MemMgrCtrlOp2(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, int long_term_pic_num)
590{
591    int ii;
592
593    for (ii = 0; ii < dpb->num_fs; ii++)
594    {
595        if (dpb->fs[ii]->IsLongTerm == 3)
596        {
597            if (dpb->fs[ii]->frame.LongTermPicNum == long_term_pic_num)
598            {
599                unmark_for_reference(avcHandle, dpb, ii);
600            }
601        }
602    }
603}
604
605/* see subclause 8.2.5.4.3 assign LongTermFrameIdx to a short-term ref picture */
606void MemMgrCtrlOp3(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint difference_of_pic_nums_minus1,
607                   uint long_term_frame_idx)
608{
609    int picNumX, ii;
610
611    picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1);
612
613    /* look for fs[i] with long_term_frame_idx */
614
615    unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx);
616
617
618    /* now mark the picture with picNumX to long term frame idx */
619
620    for (ii = 0; ii < dpb->num_fs; ii++)
621    {
622        if (dpb->fs[ii]->IsReference == 3)
623        {
624            if ((dpb->fs[ii]->frame.isLongTerm == FALSE) && (dpb->fs[ii]->frame.PicNum == picNumX))
625            {
626                dpb->fs[ii]->LongTermFrameIdx = long_term_frame_idx;
627                dpb->fs[ii]->frame.LongTermPicNum = long_term_frame_idx;
628
629                dpb->fs[ii]->frame.isLongTerm = TRUE;
630
631                dpb->fs[ii]->IsLongTerm = 3;
632                return;
633            }
634        }
635    }
636
637}
638
639/* see subclause 8.2.5.4.4, MaxLongTermFrameIdx */
640void MemMgrCtrlOp4(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint max_long_term_frame_idx_plus1)
641{
642    int ii;
643
644    video->MaxLongTermFrameIdx = max_long_term_frame_idx_plus1 - 1;
645
646    /* then mark long term frame with exceeding LongTermFrameIdx to unused for reference. */
647    for (ii = 0; ii < dpb->num_fs; ii++)
648    {
649        if (dpb->fs[ii]->IsLongTerm && dpb->fs[ii] != video->currFS)
650        {
651            if (dpb->fs[ii]->LongTermFrameIdx > video->MaxLongTermFrameIdx)
652            {
653                unmark_for_reference(avcHandle, dpb, ii);
654            }
655        }
656    }
657}
658
659/* see subclause 8.2.5.4.5 mark all reference picture as "unused for reference" and setting
660MaxLongTermFrameIdx to "no long-term frame indices" */
661void MemMgrCtrlOp5(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb)
662{
663    int ii;
664
665    video->MaxLongTermFrameIdx = -1;
666    for (ii = 0; ii < dpb->num_fs; ii++) /* including the current frame ??????*/
667    {
668        if (dpb->fs[ii] != video->currFS) // MC_FIX
669        {
670            unmark_for_reference(avcHandle, dpb, ii);
671        }
672    }
673
674    video->mem_mgr_ctrl_eq_5 = TRUE;
675}
676
677/* see subclause 8.2.5.4.6 assing long-term frame index to the current picture */
678void MemMgrCtrlOp6(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint long_term_frame_idx)
679{
680
681    unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx);
682    video->currFS->IsLongTerm = 3;
683    video->currFS->IsReference = 3;
684
685    video->currPic->isLongTerm = TRUE;
686    video->currPic->isReference = TRUE;
687    video->currFS->LongTermFrameIdx = long_term_frame_idx;
688}
689
690
691void unmark_for_reference(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint idx)
692{
693
694    AVCFrameStore *fs = dpb->fs[idx];
695    fs->frame.isReference = FALSE;
696    fs->frame.isLongTerm = FALSE;
697
698    fs->IsLongTerm = 0;
699    fs->IsReference = 0;
700    fs->IsOutputted |= 0x02;
701#ifdef PV_MEMORY_POOL
702    if (fs->IsOutputted == 3)
703    {
704        avcHandle->CBAVC_FrameUnbind(avcHandle->userData, idx);
705    }
706#endif
707    return ;
708}
709
710void unmark_long_term_frame_for_reference_by_frame_idx(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint long_term_frame_idx)
711{
712    int ii;
713    for (ii = 0; ii < dpb->num_fs; ii++)
714    {
715
716        if (dpb->fs[ii]->IsLongTerm && (dpb->fs[ii]->LongTermFrameIdx == (int)long_term_frame_idx))
717        {
718            unmark_for_reference(avcHandle, dpb, ii);
719        }
720
721    }
722}
723
724
725