blob: 4ddc7ddf1c4fa231a8cb096b502f1e82dc251078 [file] [log] [blame]
/* ------------------------------------------------------------------
* 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 ;
}