| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| #include "avclib_common.h" |
| |
| #define DPB_MEM_ATTR 0 |
| |
| AVCStatus InitDPB(AVCHandle *avcHandle, AVCCommonObj *video, int FrameHeightInMbs, int PicWidthInMbs, bool padding) |
| { |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| int level, framesize, num_fs; |
| void *userData = avcHandle->userData; |
| #ifndef PV_MEMORY_POOL |
| uint32 addr; |
| #endif |
| uint16 refIdx = 0; |
| level = video->currSeqParams->level_idc; |
| |
| for (num_fs = 0; num_fs < MAX_FS; num_fs++) |
| { |
| dpb->fs[num_fs] = NULL; |
| } |
| |
| framesize = (int)(((FrameHeightInMbs * PicWidthInMbs) << 7) * 3); |
| if (padding) |
| { |
| video->padded_size = (int)((((FrameHeightInMbs + 2) * (PicWidthInMbs + 2)) << 7) * 3) - framesize; |
| } |
| else |
| { |
| video->padded_size = 0; |
| } |
| |
| #ifndef PV_MEMORY_POOL |
| if (dpb->decoded_picture_buffer) |
| { |
| avcHandle->CBAVC_Free(userData, (int)dpb->decoded_picture_buffer); |
| dpb->decoded_picture_buffer = NULL; |
| } |
| #endif |
| /* need to allocate one extra frame for current frame, DPB only defines for reference frames */ |
| |
| dpb->num_fs = (uint32)(MaxDPBX2[mapLev2Idx[level]] << 2) / (3 * FrameHeightInMbs * PicWidthInMbs) + 1; |
| if (dpb->num_fs > MAX_FS) |
| { |
| dpb->num_fs = MAX_FS; |
| } |
| |
| if (video->currSeqParams->num_ref_frames + 1 > (uint32)dpb->num_fs) |
| { |
| dpb->num_fs = video->currSeqParams->num_ref_frames + 1; |
| } |
| |
| dpb->dpb_size = dpb->num_fs * (framesize + video->padded_size); |
| // dpb->dpb_size = (uint32)MaxDPBX2[mapLev2Idx[level]]*512 + framesize; |
| |
| #ifndef PV_MEMORY_POOL |
| dpb->decoded_picture_buffer = (uint8*) avcHandle->CBAVC_Malloc(userData, dpb->dpb_size, 100/*DPB_MEM_ATTR*/); |
| |
| if (dpb->decoded_picture_buffer == NULL || dpb->decoded_picture_buffer&0x3) // not word aligned |
| return AVC_MEMORY_FAIL; |
| #endif |
| dpb->used_size = 0; |
| num_fs = 0; |
| |
| while (num_fs < dpb->num_fs) |
| { |
| /* fs is an array pointers to AVCDecPicture */ |
| dpb->fs[num_fs] = (AVCFrameStore*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCFrameStore), 101/*DEFAULT_ATTR*/); |
| if (dpb->fs[num_fs] == NULL) |
| { |
| return AVC_MEMORY_FAIL; |
| } |
| #ifndef PV_MEMORY_POOL |
| /* assign the actual memory for Sl, Scb, Scr */ |
| dpb->fs[num_fs]->base_dpb = dpb->decoded_picture_buffer + dpb->used_size; |
| #endif |
| dpb->fs[num_fs]->IsReference = 0; |
| dpb->fs[num_fs]->IsLongTerm = 0; |
| dpb->fs[num_fs]->IsOutputted = 3; |
| dpb->fs[num_fs]->frame.RefIdx = refIdx++; /* this value will remain unchanged through out the encoding session */ |
| dpb->fs[num_fs]->frame.picType = AVC_FRAME; |
| dpb->fs[num_fs]->frame.isLongTerm = 0; |
| dpb->fs[num_fs]->frame.isReference = 0; |
| video->RefPicList0[num_fs] = &(dpb->fs[num_fs]->frame); |
| dpb->fs[num_fs]->frame.padded = 0; |
| dpb->used_size += (framesize + video->padded_size); |
| num_fs++; |
| } |
| |
| return AVC_SUCCESS; |
| } |
| |
| OSCL_EXPORT_REF AVCStatus AVCConfigureSequence(AVCHandle *avcHandle, AVCCommonObj *video, bool padding) |
| { |
| void *userData = avcHandle->userData; |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| int framesize, ii; /* size of one frame */ |
| uint PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs, PicSizeInMapUnits; |
| uint num_fs; |
| /* derived variables from SPS */ |
| PicWidthInMbs = video->currSeqParams->pic_width_in_mbs_minus1 + 1; |
| PicHeightInMapUnits = video->currSeqParams->pic_height_in_map_units_minus1 + 1 ; |
| FrameHeightInMbs = (2 - video->currSeqParams->frame_mbs_only_flag) * PicHeightInMapUnits ; |
| PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits ; |
| |
| if (video->PicSizeInMapUnits != PicSizeInMapUnits || video->currSeqParams->level_idc != video->level_idc) |
| { |
| /* make sure you mark all the frames as unused for reference for flushing*/ |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| dpb->fs[ii]->IsReference = 0; |
| dpb->fs[ii]->IsOutputted |= 0x02; |
| } |
| |
| num_fs = (uint32)(MaxDPBX2[(uint32)mapLev2Idx[video->currSeqParams->level_idc]] << 2) / (3 * PicSizeInMapUnits) + 1; |
| if (num_fs >= MAX_FS) |
| { |
| num_fs = MAX_FS; |
| } |
| #ifdef PV_MEMORY_POOL |
| if (padding) |
| { |
| avcHandle->CBAVC_DPBAlloc(avcHandle->userData, |
| PicSizeInMapUnits + ((PicWidthInMbs + 2) << 1) + (PicHeightInMapUnits << 1), num_fs); |
| } |
| else |
| { |
| avcHandle->CBAVC_DPBAlloc(avcHandle->userData, PicSizeInMapUnits, num_fs); |
| } |
| #endif |
| CleanUpDPB(avcHandle, video); |
| if (InitDPB(avcHandle, video, FrameHeightInMbs, PicWidthInMbs, padding) != AVC_SUCCESS) |
| { |
| return AVC_FAIL; |
| } |
| /* Allocate video->mblock upto PicSizeInMbs and populate the structure such as the neighboring MB pointers. */ |
| framesize = (FrameHeightInMbs * PicWidthInMbs); |
| if (video->mblock) |
| { |
| avcHandle->CBAVC_Free(userData, video->mblock); |
| video->mblock = NULL; |
| } |
| video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR); |
| if (video->mblock == NULL) |
| { |
| return AVC_FAIL; |
| } |
| for (ii = 0; ii < framesize; ii++) |
| { |
| video->mblock[ii].slice_id = -1; |
| } |
| /* Allocate memory for intra prediction */ |
| #ifdef MB_BASED_DEBLOCK |
| video->intra_pred_top = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 4, FAST_MEM_ATTR); |
| if (video->intra_pred_top == NULL) |
| { |
| return AVC_FAIL; |
| } |
| video->intra_pred_top_cb = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR); |
| if (video->intra_pred_top_cb == NULL) |
| { |
| return AVC_FAIL; |
| } |
| video->intra_pred_top_cr = (uint8*) avcHandle->CBAVC_Malloc(userData, PicWidthInMbs << 3, FAST_MEM_ATTR); |
| if (video->intra_pred_top_cr == NULL) |
| { |
| return AVC_FAIL; |
| } |
| |
| #endif |
| /* Allocate slice group MAP map */ |
| |
| if (video->MbToSliceGroupMap) |
| { |
| avcHandle->CBAVC_Free(userData, video->MbToSliceGroupMap); |
| video->MbToSliceGroupMap = NULL; |
| } |
| video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * PicSizeInMapUnits * 2, 7/*DEFAULT_ATTR*/); |
| if (video->MbToSliceGroupMap == NULL) |
| { |
| return AVC_FAIL; |
| } |
| video->PicSizeInMapUnits = PicSizeInMapUnits; |
| video->level_idc = video->currSeqParams->level_idc; |
| |
| } |
| return AVC_SUCCESS; |
| } |
| |
| OSCL_EXPORT_REF AVCStatus CleanUpDPB(AVCHandle *avcHandle, AVCCommonObj *video) |
| { |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| int ii; |
| void *userData = avcHandle->userData; |
| |
| for (ii = 0; ii < MAX_FS; ii++) |
| { |
| if (dpb->fs[ii] != NULL) |
| { |
| avcHandle->CBAVC_Free(userData, dpb->fs[ii]); |
| dpb->fs[ii] = NULL; |
| } |
| } |
| #ifndef PV_MEMORY_POOL |
| if (dpb->decoded_picture_buffer) |
| { |
| avcHandle->CBAVC_Free(userData, dpb->decoded_picture_buffer); |
| dpb->decoded_picture_buffer = NULL; |
| } |
| #endif |
| dpb->used_size = 0; |
| dpb->dpb_size = 0; |
| |
| return AVC_SUCCESS; |
| } |
| |
| OSCL_EXPORT_REF AVCStatus DPBInitBuffer(AVCHandle *avcHandle, AVCCommonObj *video) |
| { |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| int ii, status; |
| |
| /* Before doing any decoding, check if there's a frame memory available */ |
| /* look for next unused dpb->fs, or complementary field pair */ |
| /* video->currPic is assigned to this */ |
| |
| /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */ |
| |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| /* looking for the one not used or not reference and has been outputted */ |
| if (dpb->fs[ii]->IsReference == 0 && dpb->fs[ii]->IsOutputted == 3) |
| { |
| video->currFS = dpb->fs[ii]; |
| #ifdef PV_MEMORY_POOL |
| status = avcHandle->CBAVC_FrameBind(avcHandle->userData, ii, &(video->currFS->base_dpb)); |
| if (status == AVC_FAIL) |
| { |
| return AVC_NO_BUFFER; /* this should not happen */ |
| } |
| #endif |
| break; |
| } |
| } |
| if (ii == dpb->num_fs) |
| { |
| return AVC_PICTURE_OUTPUT_READY; /* no empty frame available */ |
| } |
| return AVC_SUCCESS; |
| } |
| |
| OSCL_EXPORT_REF void DPBInitPic(AVCCommonObj *video, int CurrPicNum) |
| { |
| int offset = 0; |
| int offsetc = 0; |
| int luma_framesize; |
| /* this part has to be set here, assuming that slice header and POC have been decoded. */ |
| /* used in GetOutput API */ |
| video->currFS->PicOrderCnt = video->PicOrderCnt; |
| video->currFS->FrameNum = video->sliceHdr->frame_num; |
| video->currFS->FrameNumWrap = CurrPicNum; // MC_FIX |
| /* initialize everything to zero */ |
| video->currFS->IsOutputted = 0; |
| video->currFS->IsReference = 0; |
| video->currFS->IsLongTerm = 0; |
| video->currFS->frame.isReference = FALSE; |
| video->currFS->frame.isLongTerm = FALSE; |
| |
| /* initialize the pixel pointer to NULL */ |
| video->currFS->frame.Sl = video->currFS->frame.Scb = video->currFS->frame.Scr = NULL; |
| |
| /* determine video->currPic */ |
| /* assign dbp->base_dpb to fs[i]->frame.Sl, Scb, Scr .*/ |
| /* For PicSizeInMbs, see DecodeSliceHeader() */ |
| |
| video->currPic = &(video->currFS->frame); |
| |
| video->currPic->padded = 0; // reset this flag to not-padded |
| |
| if (video->padded_size) |
| { |
| offset = ((video->PicWidthInSamplesL + 32) << 4) + 16; // offset to the origin |
| offsetc = (offset >> 2) + 4; |
| luma_framesize = (int)((((video->FrameHeightInMbs + 2) * (video->PicWidthInMbs + 2)) << 8)); |
| } |
| else |
| luma_framesize = video->PicSizeInMbs << 8; |
| |
| |
| video->currPic->Sl = video->currFS->base_dpb + offset; |
| video->currPic->Scb = video->currFS->base_dpb + luma_framesize + offsetc; |
| video->currPic->Scr = video->currPic->Scb + (luma_framesize >> 2); |
| video->currPic->pitch = video->PicWidthInSamplesL + (video->padded_size == 0 ? 0 : 32); |
| |
| |
| video->currPic->height = video->PicHeightInSamplesL; |
| video->currPic->width = video->PicWidthInSamplesL; |
| video->currPic->PicNum = CurrPicNum; |
| } |
| |
| /* to release skipped frame after encoding */ |
| OSCL_EXPORT_REF void DPBReleaseCurrentFrame(AVCHandle *avcHandle, AVCCommonObj *video) |
| { |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| int ii; |
| |
| video->currFS->IsOutputted = 3; // return this buffer. |
| |
| #ifdef PV_MEMORY_POOL /* for non-memory pool, no need to do anything */ |
| |
| /* search for current frame index */ |
| ii = dpb->num_fs; |
| while (ii--) |
| { |
| if (dpb->fs[ii] == video->currFS) |
| { |
| avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); |
| break; |
| } |
| } |
| #endif |
| |
| return ; |
| } |
| |
| /* see subclause 8.2.5.1 */ |
| OSCL_EXPORT_REF AVCStatus StorePictureInDPB(AVCHandle *avcHandle, AVCCommonObj *video) |
| { |
| AVCStatus status; |
| AVCDecPicBuffer *dpb = video->decPicBuf; |
| AVCSliceHeader *sliceHdr = video->sliceHdr; |
| int ii, num_ref; |
| |
| /* number 1 of 8.2.5.1, we handle gaps in frame_num differently without using the memory */ |
| /* to be done!!!! */ |
| |
| /* number 3 of 8.2.5.1 */ |
| if (video->nal_unit_type == AVC_NALTYPE_IDR) |
| { |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii] != video->currFS) /* not current frame */ |
| { |
| dpb->fs[ii]->IsReference = 0; /* mark as unused for reference */ |
| dpb->fs[ii]->IsLongTerm = 0; /* but still used until output */ |
| dpb->fs[ii]->IsOutputted |= 0x02; |
| #ifdef PV_MEMORY_POOL |
| if (dpb->fs[ii]->IsOutputted == 3) |
| { |
| avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); |
| } |
| #endif |
| } |
| } |
| |
| video->currPic->isReference = TRUE; |
| video->currFS->IsReference = 3; |
| |
| if (sliceHdr->long_term_reference_flag == 0) |
| { |
| video->currPic->isLongTerm = FALSE; |
| video->currFS->IsLongTerm = 0; |
| video->MaxLongTermFrameIdx = -1; |
| } |
| else |
| { |
| video->currPic->isLongTerm = TRUE; |
| video->currFS->IsLongTerm = 3; |
| video->currFS->LongTermFrameIdx = 0; |
| video->MaxLongTermFrameIdx = 0; |
| } |
| if (sliceHdr->no_output_of_prior_pics_flag) |
| { |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii] != video->currFS) /* not current frame */ |
| { |
| dpb->fs[ii]->IsOutputted = 3; |
| #ifdef PV_MEMORY_POOL |
| avcHandle->CBAVC_FrameUnbind(avcHandle->userData, ii); |
| #endif |
| } |
| } |
| } |
| video->mem_mgr_ctrl_eq_5 = TRUE; /* flush reference frames MC_FIX */ |
| } |
| else |
| { |
| if (video->currPic->isReference == TRUE) |
| { |
| if (sliceHdr->adaptive_ref_pic_marking_mode_flag == 0) |
| { |
| status = sliding_window_process(avcHandle, video, dpb); /* we may have to do this after adaptive_memory_marking */ |
| } |
| else |
| { |
| status = adaptive_memory_marking(avcHandle, video, dpb, sliceHdr); |
| } |
| if (status != AVC_SUCCESS) |
| { |
| return status; |
| } |
| } |
| } |
| /* number 4 of 8.2.5.1 */ |
| /* This basically says every frame must be at least used for short-term ref. */ |
| /* Need to be revisited!!! */ |
| /* look at insert_picture_in_dpb() */ |
| |
| |
| |
| if (video->nal_unit_type != AVC_NALTYPE_IDR && video->currPic->isLongTerm == FALSE) |
| { |
| if (video->currPic->isReference) |
| { |
| video->currFS->IsReference = 3; |
| } |
| else |
| { |
| video->currFS->IsReference = 0; |
| } |
| video->currFS->IsLongTerm = 0; |
| } |
| |
| /* check if number of reference frames doesn't exceed num_ref_frames */ |
| num_ref = 0; |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsReference) |
| { |
| num_ref++; |
| } |
| } |
| |
| if (num_ref > (int)video->currSeqParams->num_ref_frames) |
| { |
| return AVC_FAIL; /* out of range */ |
| } |
| |
| return AVC_SUCCESS; |
| } |
| |
| |
| AVCStatus sliding_window_process(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb) |
| { |
| int ii, numShortTerm, numLongTerm; |
| int32 MinFrameNumWrap; |
| int MinIdx; |
| |
| |
| numShortTerm = 0; |
| numLongTerm = 0; |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii] != video->currFS) /* do not count the current frame */ |
| { |
| if (dpb->fs[ii]->IsLongTerm) |
| { |
| numLongTerm++; |
| } |
| else if (dpb->fs[ii]->IsReference) |
| { |
| numShortTerm++; |
| } |
| } |
| } |
| |
| while (numShortTerm + numLongTerm >= (int)video->currSeqParams->num_ref_frames) |
| { |
| /* get short-term ref frame with smallest PicOrderCnt */ |
| /* this doesn't work for all I-slice clip since PicOrderCnt will not be initialized */ |
| |
| MinFrameNumWrap = 0x7FFFFFFF; |
| MinIdx = -1; |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsReference && !dpb->fs[ii]->IsLongTerm) |
| { |
| if (dpb->fs[ii]->FrameNumWrap < MinFrameNumWrap) |
| { |
| MinFrameNumWrap = dpb->fs[ii]->FrameNumWrap; |
| MinIdx = ii; |
| } |
| } |
| } |
| if (MinIdx < 0) /* something wrong, impossible */ |
| { |
| return AVC_FAIL; |
| } |
| |
| /* mark the frame with smallest PicOrderCnt to be unused for reference */ |
| dpb->fs[MinIdx]->IsReference = 0; |
| dpb->fs[MinIdx]->IsLongTerm = 0; |
| dpb->fs[MinIdx]->frame.isReference = FALSE; |
| dpb->fs[MinIdx]->frame.isLongTerm = FALSE; |
| dpb->fs[MinIdx]->IsOutputted |= 0x02; |
| #ifdef PV_MEMORY_POOL |
| if (dpb->fs[MinIdx]->IsOutputted == 3) |
| { |
| avcHandle->CBAVC_FrameUnbind(avcHandle->userData, MinIdx); |
| } |
| #endif |
| numShortTerm--; |
| } |
| return AVC_SUCCESS; |
| } |
| |
| /* see subclause 8.2.5.4 */ |
| AVCStatus adaptive_memory_marking(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, AVCSliceHeader *sliceHdr) |
| { |
| int ii; |
| |
| ii = 0; |
| while (ii < MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[ii] != 0) |
| { |
| switch (sliceHdr->memory_management_control_operation[ii]) |
| { |
| case 1: |
| MemMgrCtrlOp1(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii]); |
| // update_ref_list(dpb); |
| break; |
| case 2: |
| MemMgrCtrlOp2(avcHandle, dpb, sliceHdr->long_term_pic_num[ii]); |
| break; |
| case 3: |
| MemMgrCtrlOp3(avcHandle, video, dpb, sliceHdr->difference_of_pic_nums_minus1[ii], sliceHdr->long_term_frame_idx[ii]); |
| break; |
| case 4: |
| MemMgrCtrlOp4(avcHandle, video, dpb, sliceHdr->max_long_term_frame_idx_plus1[ii]); |
| break; |
| case 5: |
| MemMgrCtrlOp5(avcHandle, video, dpb); |
| video->currFS->FrameNum = 0; // |
| video->currFS->PicOrderCnt = 0; |
| break; |
| case 6: |
| MemMgrCtrlOp6(avcHandle, video, dpb, sliceHdr->long_term_frame_idx[ii]); |
| break; |
| } |
| ii++; |
| } |
| |
| if (ii == MAX_DEC_REF_PIC_MARKING) |
| { |
| return AVC_FAIL; /* exceed the limit */ |
| } |
| |
| return AVC_SUCCESS; |
| } |
| |
| |
| /* see subclause 8.2.5.4.1, mark short-term picture as "unused for reference" */ |
| void MemMgrCtrlOp1(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, int difference_of_pic_nums_minus1) |
| { |
| int picNumX, ii; |
| |
| picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1); |
| |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsReference == 3 && dpb->fs[ii]->IsLongTerm == 0) |
| { |
| if (dpb->fs[ii]->frame.PicNum == picNumX) |
| { |
| unmark_for_reference(avcHandle, dpb, ii); |
| return ; |
| } |
| } |
| } |
| |
| return ; |
| } |
| |
| /* see subclause 8.2.5.4.2 mark long-term picture as "unused for reference" */ |
| void MemMgrCtrlOp2(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, int long_term_pic_num) |
| { |
| int ii; |
| |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsLongTerm == 3) |
| { |
| if (dpb->fs[ii]->frame.LongTermPicNum == long_term_pic_num) |
| { |
| unmark_for_reference(avcHandle, dpb, ii); |
| } |
| } |
| } |
| } |
| |
| /* see subclause 8.2.5.4.3 assign LongTermFrameIdx to a short-term ref picture */ |
| void MemMgrCtrlOp3(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint difference_of_pic_nums_minus1, |
| uint long_term_frame_idx) |
| { |
| int picNumX, ii; |
| |
| picNumX = video->CurrPicNum - (difference_of_pic_nums_minus1 + 1); |
| |
| /* look for fs[i] with long_term_frame_idx */ |
| |
| unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx); |
| |
| |
| /* now mark the picture with picNumX to long term frame idx */ |
| |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsReference == 3) |
| { |
| if ((dpb->fs[ii]->frame.isLongTerm == FALSE) && (dpb->fs[ii]->frame.PicNum == picNumX)) |
| { |
| dpb->fs[ii]->LongTermFrameIdx = long_term_frame_idx; |
| dpb->fs[ii]->frame.LongTermPicNum = long_term_frame_idx; |
| |
| dpb->fs[ii]->frame.isLongTerm = TRUE; |
| |
| dpb->fs[ii]->IsLongTerm = 3; |
| return; |
| } |
| } |
| } |
| |
| } |
| |
| /* see subclause 8.2.5.4.4, MaxLongTermFrameIdx */ |
| void MemMgrCtrlOp4(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint max_long_term_frame_idx_plus1) |
| { |
| int ii; |
| |
| video->MaxLongTermFrameIdx = max_long_term_frame_idx_plus1 - 1; |
| |
| /* then mark long term frame with exceeding LongTermFrameIdx to unused for reference. */ |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| if (dpb->fs[ii]->IsLongTerm && dpb->fs[ii] != video->currFS) |
| { |
| if (dpb->fs[ii]->LongTermFrameIdx > video->MaxLongTermFrameIdx) |
| { |
| unmark_for_reference(avcHandle, dpb, ii); |
| } |
| } |
| } |
| } |
| |
| /* see subclause 8.2.5.4.5 mark all reference picture as "unused for reference" and setting |
| MaxLongTermFrameIdx to "no long-term frame indices" */ |
| void MemMgrCtrlOp5(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb) |
| { |
| int ii; |
| |
| video->MaxLongTermFrameIdx = -1; |
| for (ii = 0; ii < dpb->num_fs; ii++) /* including the current frame ??????*/ |
| { |
| if (dpb->fs[ii] != video->currFS) // MC_FIX |
| { |
| unmark_for_reference(avcHandle, dpb, ii); |
| } |
| } |
| |
| video->mem_mgr_ctrl_eq_5 = TRUE; |
| } |
| |
| /* see subclause 8.2.5.4.6 assing long-term frame index to the current picture */ |
| void MemMgrCtrlOp6(AVCHandle *avcHandle, AVCCommonObj *video, AVCDecPicBuffer *dpb, uint long_term_frame_idx) |
| { |
| |
| unmark_long_term_frame_for_reference_by_frame_idx(avcHandle, dpb, long_term_frame_idx); |
| video->currFS->IsLongTerm = 3; |
| video->currFS->IsReference = 3; |
| |
| video->currPic->isLongTerm = TRUE; |
| video->currPic->isReference = TRUE; |
| video->currFS->LongTermFrameIdx = long_term_frame_idx; |
| } |
| |
| |
| void unmark_for_reference(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint idx) |
| { |
| |
| AVCFrameStore *fs = dpb->fs[idx]; |
| fs->frame.isReference = FALSE; |
| fs->frame.isLongTerm = FALSE; |
| |
| fs->IsLongTerm = 0; |
| fs->IsReference = 0; |
| fs->IsOutputted |= 0x02; |
| #ifdef PV_MEMORY_POOL |
| if (fs->IsOutputted == 3) |
| { |
| avcHandle->CBAVC_FrameUnbind(avcHandle->userData, idx); |
| } |
| #endif |
| return ; |
| } |
| |
| void unmark_long_term_frame_for_reference_by_frame_idx(AVCHandle *avcHandle, AVCDecPicBuffer *dpb, uint long_term_frame_idx) |
| { |
| int ii; |
| for (ii = 0; ii < dpb->num_fs; ii++) |
| { |
| |
| if (dpb->fs[ii]->IsLongTerm && (dpb->fs[ii]->LongTermFrameIdx == (int)long_term_frame_idx)) |
| { |
| unmark_for_reference(avcHandle, dpb, ii); |
| } |
| |
| } |
| } |
| |
| |