/* ------------------------------------------------------------------ * 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" /** see subclause 8.2.4 Decoding process for reference picture lists construction. */ OSCL_EXPORT_REF void RefListInit(AVCCommonObj *video) { AVCSliceHeader *sliceHdr = video->sliceHdr; AVCDecPicBuffer *dpb = video->decPicBuf; int slice_type = video->slice_type; int i, list0idx; AVCPictureData *tmp_s; list0idx = 0; if (slice_type == AVC_I_SLICE) { video->refList0Size = 0; video->refList1Size = 0; /* we still have to calculate FrameNumWrap to make sure that all I-slice clip can perform sliding_window_operation properly. */ for (i = 0; i < dpb->num_fs; i++) { if ((dpb->fs[i]->IsReference == 3) && (!dpb->fs[i]->IsLongTerm)) { /* subclause 8.2.4.1 Decoding process for picture numbers. */ if (dpb->fs[i]->FrameNum > (int)sliceHdr->frame_num) { dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum - video->MaxFrameNum; } else { dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum; } dpb->fs[i]->frame.PicNum = dpb->fs[i]->FrameNumWrap; } } return ; } if (slice_type == AVC_P_SLICE) { /* Calculate FrameNumWrap and PicNum */ for (i = 0; i < dpb->num_fs; i++) { if ((dpb->fs[i]->IsReference == 3) && (!dpb->fs[i]->IsLongTerm)) { /* subclause 8.2.4.1 Decoding process for picture numbers. */ if (dpb->fs[i]->FrameNum > (int)sliceHdr->frame_num) { dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum - video->MaxFrameNum; } else { dpb->fs[i]->FrameNumWrap = dpb->fs[i]->FrameNum; } dpb->fs[i]->frame.PicNum = dpb->fs[i]->FrameNumWrap; video->RefPicList0[list0idx++] = &(dpb->fs[i]->frame); } } if (list0idx == 0) { dpb->fs[0]->IsReference = 3; video->RefPicList0[0] = &(dpb->fs[0]->frame); list0idx = 1; } /* order list 0 by PicNum from max to min, see subclause 8.2.4.2.1 */ SortPicByPicNum(video->RefPicList0, list0idx); video->refList0Size = list0idx; /* long term handling */ for (i = 0; i < dpb->num_fs; i++) { if (dpb->fs[i]->IsLongTerm == 3) { /* subclause 8.2.4.1 Decoding process for picture numbers. */ dpb->fs[i]->frame.LongTermPicNum = dpb->fs[i]->LongTermFrameIdx; video->RefPicList0[list0idx++] = &(dpb->fs[i]->frame); } } /* order PicNum from min to max, see subclause 8.2.4.2.1 */ SortPicByPicNumLongTerm(&(video->RefPicList0[video->refList0Size]), list0idx - video->refList0Size); video->refList0Size = list0idx; video->refList1Size = 0; } if ((video->refList0Size == video->refList1Size) && (video->refList0Size > 1)) { /* check if lists are identical, if yes swap first two elements of listX[1] */ /* last paragraph of subclause 8.2.4.2.4 */ for (i = 0; i < video->refList0Size; i++) { if (video->RefPicList0[i] != video->RefPicList1[i]) { break; } } if (i == video->refList0Size) { tmp_s = video->RefPicList1[0]; video->RefPicList1[0] = video->RefPicList1[1]; video->RefPicList1[1] = tmp_s; } } /* set max size */ video->refList0Size = AVC_MIN(video->refList0Size, (int)video->sliceHdr->num_ref_idx_l0_active_minus1 + 1); video->refList1Size = AVC_MIN(video->refList1Size, (int)video->sliceHdr->num_ref_idx_l1_active_minus1 + 1); return ; } /* see subclause 8.2.4.3 */ OSCL_EXPORT_REF AVCStatus ReOrderList(AVCCommonObj *video) { AVCSliceHeader *sliceHdr = video->sliceHdr; AVCStatus status = AVC_SUCCESS; int slice_type = video->slice_type; if (slice_type != AVC_I_SLICE) { if (sliceHdr->ref_pic_list_reordering_flag_l0) { status = ReorderRefPicList(video, 0); if (status != AVC_SUCCESS) return status; } if (video->refList0Size == 0) { return AVC_FAIL; } } return status; } AVCStatus ReorderRefPicList(AVCCommonObj *video, int isL1) { AVCSliceHeader *sliceHdr = video->sliceHdr; AVCStatus status; int *list_size; int num_ref_idx_lX_active_minus1; uint *remapping_of_pic_nums_idc; int *abs_diff_pic_num_minus1; int *long_term_pic_idx; int i; int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; int refIdxLX = 0; void* tmp; if (!isL1) /* list 0 */ { list_size = &(video->refList0Size); num_ref_idx_lX_active_minus1 = sliceHdr->num_ref_idx_l0_active_minus1; remapping_of_pic_nums_idc = sliceHdr->reordering_of_pic_nums_idc_l0; tmp = (void*)sliceHdr->abs_diff_pic_num_minus1_l0; abs_diff_pic_num_minus1 = (int*) tmp; tmp = (void*)sliceHdr->long_term_pic_num_l0; long_term_pic_idx = (int*) tmp; } else { list_size = &(video->refList1Size); num_ref_idx_lX_active_minus1 = sliceHdr->num_ref_idx_l1_active_minus1; remapping_of_pic_nums_idc = sliceHdr->reordering_of_pic_nums_idc_l1; tmp = (void*) sliceHdr->abs_diff_pic_num_minus1_l1; abs_diff_pic_num_minus1 = (int*) tmp; tmp = (void*) sliceHdr->long_term_pic_num_l1; long_term_pic_idx = (int*)tmp; } maxPicNum = video->MaxPicNum; currPicNum = video->CurrPicNum; picNumLXPred = currPicNum; /* initial value */ for (i = 0; remapping_of_pic_nums_idc[i] != 3; i++) { if ((remapping_of_pic_nums_idc[i] > 3) || (i >= MAX_REF_PIC_LIST_REORDERING)) { return AVC_FAIL; /* out of range */ } /* see subclause 8.2.4.3.1 */ if (remapping_of_pic_nums_idc[i] < 2) { if (remapping_of_pic_nums_idc[i] == 0) { if (picNumLXPred - (abs_diff_pic_num_minus1[i] + 1) < 0) picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1[i] + 1) + maxPicNum; else picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1[i] + 1); } else /* (remapping_of_pic_nums_idc[i] == 1) */ { if (picNumLXPred + (abs_diff_pic_num_minus1[i] + 1) >= maxPicNum) picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1[i] + 1) - maxPicNum; else picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1[i] + 1); } picNumLXPred = picNumLXNoWrap; /* prediction for the next one */ if (picNumLXNoWrap > currPicNum) picNumLX = picNumLXNoWrap - maxPicNum; else picNumLX = picNumLXNoWrap; status = ReorderShortTerm(video, picNumLX, &refIdxLX, isL1); if (status != AVC_SUCCESS) { return status; } } else /* (remapping_of_pic_nums_idc[i] == 2), subclause 8.2.4.3.2 */ { status = ReorderLongTerm(video, long_term_pic_idx[i], &refIdxLX, isL1); if (status != AVC_SUCCESS) { return status; } } } /* that's a definition */ *list_size = num_ref_idx_lX_active_minus1 + 1; return AVC_SUCCESS; } /* see subclause 8.2.4.3.1 */ AVCStatus ReorderShortTerm(AVCCommonObj *video, int picNumLX, int *refIdxLX, int isL1) { int cIdx, nIdx; int num_ref_idx_lX_active_minus1; AVCPictureData *picLX, **RefPicListX; if (!isL1) /* list 0 */ { RefPicListX = video->RefPicList0; num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l0_active_minus1; } else { RefPicListX = video->RefPicList1; num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l1_active_minus1; } picLX = GetShortTermPic(video, picNumLX); if (picLX == NULL) { return AVC_FAIL; } /* Note RefPicListX has to access element number num_ref_idx_lX_active */ /* There could be access violation here. */ if (num_ref_idx_lX_active_minus1 + 1 >= MAX_REF_PIC_LIST) { return AVC_FAIL; } for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; cIdx--) { RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; } RefPicListX[(*refIdxLX)++ ] = picLX; nIdx = *refIdxLX; for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++) { if (RefPicListX[ cIdx ]) { if ((RefPicListX[ cIdx ]->isLongTerm) || ((int)RefPicListX[ cIdx ]->PicNum != picNumLX)) { RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; } } } return AVC_SUCCESS; } /* see subclause 8.2.4.3.2 */ AVCStatus ReorderLongTerm(AVCCommonObj *video, int LongTermPicNum, int *refIdxLX, int isL1) { AVCPictureData **RefPicListX; int num_ref_idx_lX_active_minus1; int cIdx, nIdx; AVCPictureData *picLX; if (!isL1) /* list 0 */ { RefPicListX = video->RefPicList0; num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l0_active_minus1; } else { RefPicListX = video->RefPicList1; num_ref_idx_lX_active_minus1 = video->sliceHdr->num_ref_idx_l1_active_minus1; } picLX = GetLongTermPic(video, LongTermPicNum); if (picLX == NULL) { return AVC_FAIL; } /* Note RefPicListX has to access element number num_ref_idx_lX_active */ /* There could be access violation here. */ if (num_ref_idx_lX_active_minus1 + 1 >= MAX_REF_PIC_LIST) { return AVC_FAIL; } for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > *refIdxLX; cIdx--) RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; RefPicListX[(*refIdxLX)++ ] = picLX; nIdx = *refIdxLX; for (cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++) { if ((!RefPicListX[ cIdx ]->isLongTerm) || ((int)RefPicListX[ cIdx ]->LongTermPicNum != LongTermPicNum)) { RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; } } return AVC_SUCCESS; } AVCPictureData* GetShortTermPic(AVCCommonObj *video, int picNum) { int i; AVCDecPicBuffer *dpb = video->decPicBuf; for (i = 0; i < dpb->num_fs; i++) { if (dpb->fs[i]->IsReference == 3) { if ((dpb->fs[i]->frame.isLongTerm == FALSE) && (dpb->fs[i]->frame.PicNum == picNum)) { return &(dpb->fs[i]->frame); } } } return NULL; } AVCPictureData* GetLongTermPic(AVCCommonObj *video, int LongtermPicNum) { AVCDecPicBuffer *dpb = video->decPicBuf; int i; for (i = 0; i < dpb->num_fs; i++) { if (dpb->fs[i]->IsReference == 3) { if ((dpb->fs[i]->frame.isLongTerm == TRUE) && (dpb->fs[i]->frame.LongTermPicNum == LongtermPicNum)) { return &(dpb->fs[i]->frame); } } } return NULL; } int is_short_ref(AVCPictureData *s) { return ((s->isReference) && !(s->isLongTerm)); } int is_long_ref(AVCPictureData *s) { return ((s->isReference) && (s->isLongTerm)); } /* sort by PicNum, descending order */ void SortPicByPicNum(AVCPictureData *data[], int num) { int i, j; AVCPictureData *temp; for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->PicNum > data[i]->PicNum) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } return ; } /* sort by PicNum, ascending order */ void SortPicByPicNumLongTerm(AVCPictureData *data[], int num) { int i, j; AVCPictureData *temp; for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->LongTermPicNum < data[i]->LongTermPicNum) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } return ; } /* sort by FrameNumWrap, descending order */ void SortFrameByFrameNumWrap(AVCFrameStore *data[], int num) { int i, j; AVCFrameStore *temp; for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->FrameNumWrap > data[i]->FrameNumWrap) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } return ; } /* sort frames by LongTermFrameIdx, ascending order */ void SortFrameByLTFrameIdx(AVCFrameStore *data[], int num) { int i, j; AVCFrameStore *temp; for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->LongTermFrameIdx < data[i]->LongTermFrameIdx) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } return ; } /* sort PictureData by POC in descending order */ void SortPicByPOC(AVCPictureData *data[], int num, int descending) { int i, j; AVCPictureData *temp; if (descending) { for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->PicOrderCnt > data[i]->PicOrderCnt) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } } else { for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->PicOrderCnt < data[i]->PicOrderCnt) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } } return ; } /* sort PictureData by LongTermPicNum in ascending order */ void SortPicByLTPicNum(AVCPictureData *data[], int num) { int i, j; AVCPictureData *temp; for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->LongTermPicNum < data[i]->LongTermPicNum) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } return ; } /* sort by PicOrderCnt, descending order */ void SortFrameByPOC(AVCFrameStore *data[], int num, int descending) { int i, j; AVCFrameStore *temp; if (descending) { for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->PicOrderCnt > data[i]->PicOrderCnt) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } } else { for (i = 0; i < num - 1; i++) { for (j = i + 1; j < num; j++) { if (data[j]->PicOrderCnt < data[i]->PicOrderCnt) { temp = data[j]; data[j] = data[i]; data[i] = temp; } } } } return ; }