blob: 5f660de47ff6f2212af90eb753bf66029d2cf5ec [file] [log] [blame]
/*!
***********************************************************************
* \file: h264_dpb_ctl.c
*
***********************************************************************
*/
#include "viddec_parser_ops.h"
#include "viddec_pm.h"
//#include <limits.h>
#include "h264parse.h"
#include "h264parse_dpb.h"
//#include "h264_debug.h"
#ifndef NULL
#define NULL 0
#endif
//#ifndef USER_MODE
//#define NULL 0
//#endif
///////////////////////// DPB init //////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Init DPB
// Description: init dpb, which should be called while open
//
//////////////////////////////////////////////////////////////////////////////
void h264_init_dpb(h264_DecodedPictureBuffer * p_dpb)
{
int32_t i;
//// Init DPB to zero
//h264_memset(p_dpb, 0x0, sizeof(h264_DecodedPictureBuffer) );
for (i=0; i<NUM_DPB_FRAME_STORES; i++)
{
p_dpb->fs[i].fs_idc = MPD_DPB_FS_NULL_IDC;
p_dpb->fs_dpb_idc[i] = MPD_DPB_FS_NULL_IDC;
}
p_dpb->used_size = 0;
p_dpb->fs_dec_idc = MPD_DPB_FS_NULL_IDC;
p_dpb->fs_non_exist_idc = MPD_DPB_FS_NULL_IDC;
return;
}
///////////////////////// Reference list management //////////////////////////
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_add_ref_list ()
//
// Adds an idc to the long term reference list
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_add_ref_list(h264_DecodedPictureBuffer * p_dpb, int32_t ref_idc)
{
p_dpb->fs_ref_idc[p_dpb->ref_frames_in_buffer] = ref_idc;
p_dpb->ref_frames_in_buffer++;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_add_ltref_list ()
//
// Adds an idc to the long term reference list
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_add_ltref_list(h264_DecodedPictureBuffer * p_dpb, int32_t ref_idc)
{
p_dpb->fs_ltref_idc[p_dpb->ltref_frames_in_buffer] = ref_idc;
p_dpb->ltref_frames_in_buffer++;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_update_all_ref_lists (h264_DecodedPictureBuffer * p_dpb,int32_t NonExisting)
//
// Decide whether the current picture needs to be added to the reference lists
// active_fs should be set-up prior to calling this function
//
// Check if we need to search the lists here
// or can we go straight to adding to ref lists..
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_insert_ref_lists(h264_DecodedPictureBuffer * p_dpb, int32_t NonExisting)
{
if (NonExisting)
h264_dpb_set_active_fs(p_dpb,p_dpb->fs_non_exist_idc);
else
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
//if(active_fs->is_reference)
if (p_dpb->active_fs->frame.used_for_reference)
{
if (viddec_h264_get_is_long_term(p_dpb->active_fs))
{
if (viddec_h264_get_dec_structure(p_dpb->active_fs) == FRAME)
h264_dpb_add_ltref_list(p_dpb, p_dpb->active_fs->fs_idc);
else
{
uint32_t found_in_list = 0, i = 0;
for (i = 0; (i < p_dpb->ltref_frames_in_buffer) && (found_in_list == 0); i++) {
if (p_dpb->fs_ltref_idc[i] == p_dpb->active_fs->fs_idc) found_in_list = 1;
}
if (found_in_list == 0) h264_dpb_add_ltref_list(p_dpb, p_dpb->active_fs->fs_idc);
}
}
else
{
if (viddec_h264_get_dec_structure(p_dpb->active_fs) == FRAME) {
h264_dpb_add_ref_list(p_dpb, p_dpb->active_fs->fs_idc);
} else
{
uint32_t found_in_list = 0, i = 0;
for (i = 0; (i < p_dpb->ref_frames_in_buffer) && (found_in_list == 0); i++)
{
if (p_dpb->fs_ref_idc[i] == p_dpb->active_fs->fs_idc) found_in_list = 1;
}
if (found_in_list == 0) h264_dpb_add_ref_list(p_dpb, p_dpb->active_fs->fs_idc);
}
}
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// Set active fs
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_set_active_fs(h264_DecodedPictureBuffer * p_dpb, int32_t index)
{
p_dpb->active_fs = &p_dpb->fs[index];
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// Sort reference list
//////////////////////////////////////////////////////////////////////////////
void h264_list_sort(uint8_t *list, int32_t *sort_indices, int32_t size, int32_t desc)
{
int32_t j, k, temp, idc;
// Dodgy looking for embedded code here...
if (size > 1)
{
for (j = 0; j < size-1; j = j + 1) {
for (k = j + 1; k < size; k = k + 1) {
if ((desc & (sort_indices[j] < sort_indices[k]))|
(~desc & (sort_indices[j] > sort_indices[k])) )
{
temp = sort_indices[k];
sort_indices[k] = sort_indices[j];
sort_indices[j] = temp;
idc = list[k];
list[k] = list[j];
list[j] = idc;
}
}
}
}
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_pic_is_bottom_field_ref ()
//
// Used to sort a list based on a corresponding sort indices
//////////////////////////////////////////////////////////////////////////////
int32_t h264_dpb_pic_is_bottom_field_ref(h264_DecodedPictureBuffer * p_dpb, int32_t long_term)
{
int32_t temp;
if (long_term) temp = ((p_dpb->active_fs->bottom_field.used_for_reference) && (p_dpb->active_fs->bottom_field.is_long_term)) ? 1 : 0;
else temp = ((p_dpb->active_fs->bottom_field.used_for_reference) && !(p_dpb->active_fs->bottom_field.is_long_term)) ? 1 : 0;
return temp;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_pic_is_top_field_ref ()
//
// Used to sort a list based on a corresponding sort indices
//////////////////////////////////////////////////////////////////////////////
int32_t h264_dpb_pic_is_top_field_ref(h264_DecodedPictureBuffer * p_dpb, int32_t long_term)
{
int32_t temp;
if (long_term)
temp = ((p_dpb->active_fs->top_field.used_for_reference) && (p_dpb->active_fs->top_field.is_long_term)) ? 1 : 0;
else
temp = ((p_dpb->active_fs->top_field.used_for_reference) && !(p_dpb->active_fs->top_field.is_long_term)) ? 1 : 0;
return temp;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_gen_pic_list_from_frame_list ()
//
// Used to sort a list based on a corresponding sort indices
//////////////////////////////////////////////////////////////////////////////
int32_t h264_dpb_gen_pic_list_from_frame_list(h264_DecodedPictureBuffer *p_dpb, uint8_t *pic_list, uint8_t *frame_list, int32_t currPicStructure, int32_t list_size, int32_t long_term)
{
int32_t top_idx, bot_idx, got_pic, list_idx;
int32_t lterm;
list_idx = 0;
lterm = (long_term)? 1:0;
if (list_size) {
top_idx = 0;
bot_idx = 0;
if (currPicStructure == TOP_FIELD) {
while ((top_idx < list_size)||(bot_idx < list_size))
{
/////////////////////////////////////////// ref Top Field
got_pic = 0;
while ((top_idx < list_size) & ~got_pic)
{
h264_dpb_set_active_fs(p_dpb, frame_list[top_idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs))&0x1)
{
if (h264_dpb_pic_is_top_field_ref(p_dpb, long_term))
{
pic_list[list_idx] = PUT_LIST_LONG_TERM_BITS(lterm) + frame_list[top_idx] + PUT_LIST_INDEX_FIELD_BIT(0); // top_field
list_idx++;
got_pic = 1;
}
}
top_idx++;
}
/////////////////////////////////////////// ref Bottom Field
got_pic = 0;
while ((bot_idx < list_size) & ~got_pic)
{
h264_dpb_set_active_fs(p_dpb, frame_list[bot_idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs))&0x2)
{
if (h264_dpb_pic_is_bottom_field_ref(p_dpb, long_term))
{
pic_list[list_idx] = PUT_LIST_LONG_TERM_BITS(lterm) + frame_list[bot_idx] + PUT_LIST_INDEX_FIELD_BIT(1); // bottom_field
list_idx++;
got_pic = 1;
}
}
bot_idx++;
}
}
}
/////////////////////////////////////////////// current Bottom Field
if (currPicStructure == BOTTOM_FIELD) {
while ((top_idx < list_size)||(bot_idx < list_size))
{
/////////////////////////////////////////// ref Top Field
got_pic = 0;
while ((bot_idx < list_size) && (!(got_pic)))
{
h264_dpb_set_active_fs(p_dpb, frame_list[bot_idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs))&0x2) {
if (h264_dpb_pic_is_bottom_field_ref(p_dpb, long_term)) {
// short term ref pic
pic_list[list_idx] = PUT_LIST_LONG_TERM_BITS(lterm) + frame_list[bot_idx] + PUT_LIST_INDEX_FIELD_BIT(1); // bottom_field
list_idx++;
got_pic = 1;
}
}
bot_idx++;
}
/////////////////////////////////////////// ref Bottom Field
got_pic = 0;
while ((top_idx < list_size) && (!(got_pic)))
{
h264_dpb_set_active_fs(p_dpb, frame_list[top_idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs))&0x1) {
if (h264_dpb_pic_is_top_field_ref(p_dpb, long_term)) {
// short term ref pic
pic_list[list_idx] = PUT_LIST_LONG_TERM_BITS(lterm) + frame_list[top_idx] + PUT_LIST_INDEX_FIELD_BIT(0); // top_field
list_idx++;
got_pic = 1;
}
}
top_idx++;
}
}
}
}
return list_idx;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_remove_ref_list ()
//
// Removes an idc from the refernce list and updates list after
//
void h264_dpb_remove_ref_list(h264_DecodedPictureBuffer * p_dpb, int32_t ref_idc)
{
uint8_t idx = 0;
int32_t Found = 0;
while ((idx < p_dpb->ref_frames_in_buffer) && (!(Found)))
{
if (p_dpb->fs_ref_idc[idx] == ref_idc)
Found = 1;
else
idx++;
}
if (Found)
{
// Move the remainder of the list up one
while (idx < p_dpb->ref_frames_in_buffer - 1) {
p_dpb->fs_ref_idc[idx] = p_dpb->fs_ref_idc[idx + 1];
idx ++;
}
p_dpb->fs_ref_idc[idx] = MPD_DPB_FS_NULL_IDC; // Clear the last one
p_dpb->ref_frames_in_buffer--;
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_remove_ltref_list ()
//
// Removes an idc from the long term reference list and updates list after
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_remove_ltref_list(h264_DecodedPictureBuffer * p_dpb,int32_t ref_idc)
{
uint8_t idx = 0;
int32_t Found = 0;
while ((idx < p_dpb->ltref_frames_in_buffer) && (!(Found)))
{
if (p_dpb->fs_ltref_idc[idx] == ref_idc) Found = 1;
else idx++;
}
if (Found)
{
// Move the remainder of the list up one
while (idx <(uint8_t)(p_dpb->ltref_frames_in_buffer - 1))
{
p_dpb->fs_ltref_idc[idx] = p_dpb->fs_ltref_idc[idx + 1];
idx ++;
}
p_dpb->fs_ltref_idc[idx] = MPD_DPB_FS_NULL_IDC; // Clear the last one
p_dpb->ltref_frames_in_buffer--;
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_init_lists ()
//
// Used to initialise the reference lists
// Also assigns picture numbers and long term picture numbers if P OR B slice
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_update_ref_lists(h264_Info * pInfo)
{
h264_DecodedPictureBuffer * p_dpb = &pInfo->dpb;
int32_t MaxFrameNum = 1 << (pInfo->active_SPS.log2_max_frame_num_minus4 + 4);
uint8_t list0idx, list0idx_1, listltidx;
uint8_t idx;
uint8_t add_top, add_bottom, diff;
uint8_t list_idc;
uint8_t check_non_existing, skip_picture;
uint8_t gen_pic_fs_list0[16];
uint8_t gen_pic_fs_list1[16];
uint8_t gen_pic_fs_listlt[16];
uint8_t gen_pic_pic_list[32]; // check out these sizes...
uint8_t sort_fs_idc[16];
int32_t list_sort_number[16];
#ifdef DUMP_HEADER_INFO
static int cc1 = 0;
//OS_INFO("-------------cc1= %d\n",cc1); /////// DEBUG info
if (cc1 == 255)
idx = 0;
#endif
list0idx = list0idx_1 = listltidx = 0;
if (pInfo->SliceHeader.structure == FRAME)
{
////////////////////////////////////////////////// short term handling
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs) == 3)&&(p_dpb->active_fs->frame.used_for_reference == 3))
{
if (p_dpb->active_fs->frame_num > pInfo->img.frame_num)
p_dpb->active_fs->frame_num_wrap = p_dpb->active_fs->frame_num - MaxFrameNum;
else
p_dpb->active_fs->frame_num_wrap = p_dpb->active_fs->frame_num;
p_dpb->active_fs->frame.pic_num = p_dpb->active_fs->frame_num_wrap;
// Use this opportunity to sort list for a p-frame
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
sort_fs_idc[list0idx] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx] = p_dpb->active_fs->frame.pic_num;
list0idx++;
}
}
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
h264_list_sort(sort_fs_idc, list_sort_number, list0idx, 1);
for (idx = 0; idx < list0idx; idx++)
p_dpb->listX_0[idx] = (sort_fs_idc[idx]); // frame
p_dpb->listXsize[0] = list0idx;
}
////////////////////////////////////////////////// long term handling
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs) == 3) && (viddec_h264_get_is_long_term(p_dpb->active_fs) == 3) && (p_dpb->active_fs->frame.used_for_reference == 3))
{
p_dpb->active_fs->frame.long_term_pic_num = p_dpb->active_fs->frame.long_term_frame_idx;
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
sort_fs_idc[list0idx-p_dpb->listXsize[0]] = p_dpb->fs_ltref_idc[idx];
list_sort_number[list0idx-p_dpb->listXsize[0]] = p_dpb->active_fs->frame.long_term_pic_num;
list0idx++;
}
}
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
h264_list_sort(sort_fs_idc, list_sort_number, list0idx-p_dpb->listXsize[0], 0);
for (idx = p_dpb->listXsize[0]; idx < list0idx; idx++) {
p_dpb->listX_0[idx] = (1<<6) + sort_fs_idc[idx-p_dpb->listXsize[0]];
}
p_dpb->listXsize[0] = list0idx;
}
}
else /// Field base
{
if (pInfo->SliceHeader.structure == TOP_FIELD)
{
add_top = 1;
add_bottom = 0;
}
else
{
add_top = 0;
add_bottom = 1;
}
////////////////////////////////////////////P0: Short term handling
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (p_dpb->active_fs->frame.used_for_reference)
{
if (p_dpb->active_fs->frame_num > pInfo->SliceHeader.frame_num) {
p_dpb->active_fs->frame_num_wrap = p_dpb->active_fs->frame_num - MaxFrameNum;
} else {
p_dpb->active_fs->frame_num_wrap = p_dpb->active_fs->frame_num;
}
if ((p_dpb->active_fs->frame.used_for_reference)&0x1) {
p_dpb->active_fs->top_field.pic_num = (p_dpb->active_fs->frame_num_wrap << 1) + add_top;
}
if ((p_dpb->active_fs->frame.used_for_reference)&0x2) {
p_dpb->active_fs->bottom_field.pic_num = (p_dpb->active_fs->frame_num_wrap << 1) + add_bottom;
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP) {
sort_fs_idc[list0idx] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx] = p_dpb->active_fs->frame_num_wrap;
list0idx++;
}
}
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
h264_list_sort(sort_fs_idc, list_sort_number, list0idx, 1);
for (idx = 0; idx < list0idx; idx++) {
gen_pic_fs_list0[idx] = sort_fs_idc[idx];
}
p_dpb->listXsize[0] = 0;
p_dpb->listXsize[0] = h264_dpb_gen_pic_list_from_frame_list(p_dpb, gen_pic_pic_list, gen_pic_fs_list0, pInfo->img.structure, list0idx, 0);
for (idx = 0; idx < p_dpb->listXsize[0]; idx++)
{
p_dpb->listX_0[idx] = gen_pic_pic_list[idx];
}
}
////////////////////////////////////////////P0: long term handling
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if (viddec_h264_get_is_long_term(p_dpb->active_fs)&0x1) {
p_dpb->active_fs->top_field.long_term_pic_num = (p_dpb->active_fs->top_field.long_term_frame_idx << 1) + add_top;
}
if (viddec_h264_get_is_long_term(p_dpb->active_fs)&0x2) {
p_dpb->active_fs->bottom_field.long_term_pic_num = (p_dpb->active_fs->bottom_field.long_term_frame_idx << 1) + add_bottom;
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
sort_fs_idc[listltidx] = p_dpb->fs_ltref_idc[idx];
list_sort_number[listltidx] = p_dpb->active_fs->long_term_frame_idx;
listltidx++;
}
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
h264_list_sort(sort_fs_idc, list_sort_number, listltidx, 0);
for (idx = 0; idx < listltidx; idx++) {
gen_pic_fs_listlt[idx] = sort_fs_idc[idx];
}
list0idx_1 = h264_dpb_gen_pic_list_from_frame_list(p_dpb, gen_pic_pic_list, gen_pic_fs_listlt, pInfo->img.structure, listltidx, 1);
for (idx = 0; idx < list0idx_1; idx++) {
p_dpb->listX_0[p_dpb->listXsize[0]+idx] = gen_pic_pic_list[idx];
}
p_dpb->listXsize[0] += list0idx_1;
}
}
if (pInfo->SliceHeader.slice_type == h264_PtypeI)
{
p_dpb->listXsize[0] = 0;
p_dpb->listXsize[1] = 0;
return;
}
if (pInfo->SliceHeader.slice_type == h264_PtypeP)
{
//// Forward done above
p_dpb->listXsize[1] = 0;
}
// B-Slice
// Do not include non-existing frames for B-pictures when cnt_type is zero
if (pInfo->SliceHeader.slice_type == h264_PtypeB)
{
list0idx = list0idx_1 = listltidx = 0;
skip_picture = 0;
if (pInfo->active_SPS.pic_order_cnt_type == 0)
check_non_existing = 1;
else
check_non_existing = 0;
if (pInfo->SliceHeader.structure == FRAME)
{
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3)
{
if (check_non_existing)
{
if (viddec_h264_get_is_non_existent(p_dpb->active_fs)) skip_picture = 1;
else skip_picture = 0;
}
if (skip_picture == 0)
{
if ((p_dpb->active_fs->frame.used_for_reference==3) && (!(p_dpb->active_fs->frame.is_long_term)))
{
if (pInfo->img.framepoc >= p_dpb->active_fs->frame.poc)
{
sort_fs_idc[list0idx] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx] = p_dpb->active_fs->frame.poc;
list0idx++;
}
}
}
}
}
h264_list_sort(sort_fs_idc, list_sort_number, list0idx, 1);
for (idx = 0; idx < list0idx; idx++) {
p_dpb->listX_0[idx] = sort_fs_idc[idx];
}
list0idx_1 = list0idx;
/////////////////////////////////////////B0: Short term handling
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3)
{
if (check_non_existing)
{
if (viddec_h264_get_is_non_existent(p_dpb->active_fs)) skip_picture = 1;
else skip_picture = 0;
}
if (skip_picture == 0)
{
if ((p_dpb->active_fs->frame.used_for_reference) && (!(p_dpb->active_fs->frame.is_long_term)))
{
if (pInfo->img.framepoc < p_dpb->active_fs->frame.poc)
{
sort_fs_idc[list0idx-list0idx_1] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx-list0idx_1] = p_dpb->active_fs->frame.poc;
list0idx++;
}
}
}
}
}
h264_list_sort(sort_fs_idc, list_sort_number, list0idx-list0idx_1, 0);
for (idx = list0idx_1; idx < list0idx; idx++) {
p_dpb->listX_0[idx] = sort_fs_idc[idx-list0idx_1];
}
for (idx = 0; idx < list0idx_1; idx++) {
p_dpb->listX_1[list0idx-list0idx_1+idx] = p_dpb->listX_0[idx];
}
for (idx = list0idx_1; idx < list0idx; idx++) {
p_dpb->listX_1[idx-list0idx_1] = p_dpb->listX_0[idx];
}
p_dpb->listXsize[0] = list0idx;
p_dpb->listXsize[1] = list0idx;
/////////////////////////////////////////B0: long term handling
list0idx = 0;
// Can non-existent pics be set as long term??
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if ((viddec_h264_get_is_used(p_dpb->active_fs) == 3) && (viddec_h264_get_is_long_term(p_dpb->active_fs) == 3))
{
// if we have two fields, both must be long-term
sort_fs_idc[list0idx] = p_dpb->fs_ltref_idc[idx];
list_sort_number[list0idx] = p_dpb->active_fs->frame.long_term_pic_num;
list0idx++;
}
}
h264_list_sort(sort_fs_idc, list_sort_number, list0idx, 0);
for (idx = p_dpb->listXsize[0]; idx < (p_dpb->listXsize[0]+list0idx); idx = idx + 1)
{
p_dpb->listX_0[idx] = (1<<6) + sort_fs_idc[idx-p_dpb->listXsize[0]];
p_dpb->listX_1[idx] = (1<<6) + sort_fs_idc[idx-p_dpb->listXsize[0]];
}
p_dpb->listXsize[0] += list0idx;
p_dpb->listXsize[1] += list0idx;
}
else // Field
{
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (viddec_h264_get_is_used(p_dpb->active_fs)) {
if (check_non_existing) {
if (viddec_h264_get_is_non_existent(p_dpb->active_fs))
skip_picture = 1;
else
skip_picture = 0;
}
if (skip_picture == 0) {
if (pInfo->img.ThisPOC >= p_dpb->active_fs->frame.poc) {
sort_fs_idc[list0idx] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx] = p_dpb->active_fs->frame.poc;
list0idx++;
}
}
}
}
h264_list_sort(sort_fs_idc, list_sort_number, list0idx, 1);
for (idx = 0; idx < list0idx; idx = idx + 1) {
gen_pic_fs_list0[idx] = sort_fs_idc[idx];
}
list0idx_1 = list0idx;
///////////////////////////////////////////// B1: Short term handling
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (viddec_h264_get_is_used(p_dpb->active_fs))
{
if (check_non_existing) {
if (viddec_h264_get_is_non_existent(p_dpb->active_fs))
skip_picture = 1;
else
skip_picture = 0;
}
if (skip_picture == 0) {
if (pInfo->img.ThisPOC < p_dpb->active_fs->frame.poc) {
sort_fs_idc[list0idx-list0idx_1] = p_dpb->fs_ref_idc[idx];
list_sort_number[list0idx-list0idx_1] = p_dpb->active_fs->frame.poc;
list0idx++;
}
}
}
}
///// Generate frame list from sorted fs
/////
h264_list_sort(sort_fs_idc, list_sort_number, list0idx-list0idx_1, 0);
for (idx = list0idx_1; idx < list0idx; idx++)
gen_pic_fs_list0[idx] = sort_fs_idc[idx-list0idx_1];
for (idx = 0; idx < list0idx_1; idx++)
gen_pic_fs_list1[list0idx-list0idx_1+idx] = gen_pic_fs_list0[idx];
for (idx = list0idx_1; idx < list0idx; idx++)
gen_pic_fs_list1[idx-list0idx_1] = gen_pic_fs_list0[idx];
///// Generate List_X0
/////
p_dpb->listXsize[0] = h264_dpb_gen_pic_list_from_frame_list(p_dpb, gen_pic_pic_list, gen_pic_fs_list0, pInfo->img.structure, list0idx, 0);
for (idx = 0; idx < p_dpb->listXsize[0]; idx++)
p_dpb->listX_0[idx] = gen_pic_pic_list[idx];
//// Generate List X1
////
p_dpb->listXsize[1] = h264_dpb_gen_pic_list_from_frame_list(p_dpb, gen_pic_pic_list, gen_pic_fs_list1, pInfo->img.structure, list0idx, 0);
for (idx = 0; idx < p_dpb->listXsize[1]; idx++)
p_dpb->listX_1[idx] = gen_pic_pic_list[idx];
///////////////////////////////////////////// B1: long term handling
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
sort_fs_idc[listltidx] = p_dpb->fs_ltref_idc[idx];
list_sort_number[listltidx] = p_dpb->active_fs->long_term_frame_idx;
listltidx++;
}
h264_list_sort(sort_fs_idc, list_sort_number, listltidx, 0);
for (idx = 0; idx < listltidx; idx++)
gen_pic_fs_listlt[idx] = sort_fs_idc[idx];
list0idx_1 = h264_dpb_gen_pic_list_from_frame_list(p_dpb, gen_pic_pic_list, gen_pic_fs_listlt, pInfo->img.structure, listltidx, 1);
for (idx = 0; idx < list0idx_1; idx++)
{
p_dpb->listX_0[p_dpb->listXsize[0]+idx] = gen_pic_pic_list[idx];
p_dpb->listX_1[p_dpb->listXsize[1]+idx] = gen_pic_pic_list[idx];
}
p_dpb->listXsize[0] += list0idx_1;
p_dpb->listXsize[1] += list0idx_1;
}
}
// Setup initial list sizes at this point
p_dpb->nInitListSize[0] = p_dpb->listXsize[0];
p_dpb->nInitListSize[1] = p_dpb->listXsize[1];
if (pInfo->SliceHeader.slice_type != h264_PtypeI)
{
if ((p_dpb->listXsize[0]==p_dpb->listXsize[1]) && (p_dpb->listXsize[0] > 1))
{
// check if lists are identical, if yes swap first two elements of listX[1]
diff = 0;
for (idx = 0; idx < p_dpb->listXsize[0]; idx = idx + 1)
{
if (p_dpb->listX_0[idx] != p_dpb->listX_1[idx]) diff = 1;
}
if (!(diff))
{
list_idc = p_dpb->listX_1[0];
p_dpb->listX_1[0] = p_dpb->listX_1[1];
p_dpb->listX_1[1] = list_idc;
}
}
// set max size
if (p_dpb->listXsize[0] > pInfo->SliceHeader.num_ref_idx_l0_active)
{
p_dpb->listXsize[0] = pInfo->SliceHeader.num_ref_idx_l0_active;
}
if (p_dpb->listXsize[1] > pInfo->SliceHeader.num_ref_idx_l1_active)
{
p_dpb->listXsize[1] = pInfo->SliceHeader.num_ref_idx_l1_active;
}
}
/// DPB reorder list
h264_dpb_reorder_lists(pInfo);
return;
} //// End of init_dpb_list
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_get_short_term_pic ()
//
// Sets active_fs to point to frame store containing picture with given picNum
// Sets field_flag, bottom_field and err_flag based on the picture and whether
// it is available or not...
//
static frame_param_ptr h264_dpb_get_short_term_pic(h264_Info * pInfo,int32_t pic_num, int32_t *bottom_field_bit)
{
register uint32_t idx;
register frame_param_ptr temp_fs;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
*bottom_field_bit = 0;
for (idx = 0; idx < p_dpb->ref_frames_in_buffer; idx++)
{
temp_fs = &p_dpb->fs[p_dpb->fs_ref_idc[idx]];
if (pInfo->SliceHeader.structure == FRAME)
{
if (temp_fs->frame.used_for_reference == 3)
if (!(temp_fs->frame.is_long_term))
if (temp_fs->frame.pic_num == pic_num) return temp_fs;
}
else // current picture is a field
{
if (temp_fs->frame.used_for_reference&0x1)
if (!(temp_fs->top_field.is_long_term))
if (temp_fs->top_field.pic_num == pic_num)
{
return temp_fs;
}
if (temp_fs->frame.used_for_reference&0x2)
if (!(temp_fs->bottom_field.is_long_term))
if (temp_fs->bottom_field.pic_num == pic_num)
{
*bottom_field_bit = PUT_LIST_INDEX_FIELD_BIT(1);
return temp_fs;
}
}
}
return NULL;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_get_long_term_pic ()
//
// Sets active_fs to point to frame store containing picture with given picNum
//
static frame_param_ptr h264_dpb_get_long_term_pic(h264_Info * pInfo,int32_t long_term_pic_num, int32_t *bottom_field_bit)
{
register uint32_t idx;
register frame_param_ptr temp_fs;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
*bottom_field_bit = 0;
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
temp_fs = &p_dpb->fs[p_dpb->fs_ltref_idc[idx]];
if (pInfo->SliceHeader.structure == FRAME)
{
if (temp_fs->frame.used_for_reference == 3)
if (temp_fs->frame.is_long_term)
if (temp_fs->frame.long_term_pic_num == long_term_pic_num)
return temp_fs;
}
else
{
if (temp_fs->frame.used_for_reference&0x1)
if (temp_fs->top_field.is_long_term)
if (temp_fs->top_field.long_term_pic_num == long_term_pic_num)
return temp_fs;
if (temp_fs->frame.used_for_reference&0x2)
if (temp_fs->bottom_field.is_long_term)
if (temp_fs->bottom_field.long_term_pic_num == long_term_pic_num)
{
*bottom_field_bit = PUT_LIST_INDEX_FIELD_BIT(1);
return temp_fs;
}
}
}
return NULL;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_reorder_ref_pic_list ()
//
// Used to sort a list based on a corresponding sort indices
//
struct list_value_t
{
int32_t value;
struct list_value_t *next;
};
struct linked_list_t
{
struct list_value_t *begin;
struct list_value_t *end;
struct list_value_t *entry;
struct list_value_t *prev_entry;
struct list_value_t list[32];
};
static void linked_list_initialize (struct linked_list_t *lp, uint8_t *vp, int32_t size)
{
struct list_value_t *lvp;
lvp = lp->list;
lp->begin = lvp;
lp->entry = lvp;
lp->end = lvp + (size-1);
lp->prev_entry = NULL;
while (lvp <= lp->end)
{
lvp->value = *(vp++);
lvp->next = lvp + 1;
lvp++;
}
lp->end->next = NULL;
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
static void linked_list_reorder (struct linked_list_t *lp, int32_t list_value)
{
register struct list_value_t *lvp = lp->entry;
register struct list_value_t *lvp_prev;
if (lvp == NULL) {
lp->end->value = list_value; // replace the end entry
} else if ((lp->begin==lp->end)||(lvp==lp->end)) // replece the begin/end entry and set the entry to NULL
{
lp->entry->value = list_value;
lp->prev_entry = lp->entry;
lp->entry = NULL;
}
else if (lvp->value==list_value) // the entry point matches
{
lp->prev_entry = lvp;
lp->entry = lvp->next;
}
else if (lvp->next == lp->end) // the entry is just before the end
{
// replace the end and swap the end and entry points
// lvp
// prev_entry => entry => old_end
// old_end & new_prev_entry => new_end & entry
lp->end->value = list_value;
if (lp->prev_entry)
lp->prev_entry->next = lp->end;
else
lp->begin = lp->end;
lp->prev_entry = lp->end;
lp->end->next = lvp;
lp->end = lvp;
lvp->next = NULL;
}
else
{
lvp_prev = NULL;
while (lvp->next) // do not check the end but we'll be in the loop at least once
{
if (lvp->value == list_value) break;
lvp_prev = lvp;
lvp = lvp->next;
}
lvp->value = list_value; // force end matches
if (lvp_prev != NULL)
{
// remove lvp from the list
lvp_prev->next = lvp->next;
}
if (lvp==lp->end) lp->end = lvp_prev;
// insert lvp in front of lp->entry
if (lp->entry==lp->begin)
{
lvp->next = lp->begin;
lp->begin = lvp;
}
else
{
lvp->next = lp->entry;
lp->prev_entry->next = lvp;
}
lp->prev_entry = lvp;
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
static void linked_list_output (struct linked_list_t *lp, int32_t *vp)
{
register int32_t *ip1;
register struct list_value_t *lvp;
lvp = lp->begin;
ip1 = vp;
while (lvp)
{
*(ip1++) = lvp->value;
lvp = lvp->next;
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
int32_t h264_dpb_reorder_ref_pic_list(h264_Info * pInfo,int32_t list_num, int32_t num_ref_idx_active)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
uint8_t *remapping_of_pic_nums_idc;
list_reordering_num_t *list_reordering_num;
int32_t bottom_field_bit;
int32_t maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, pic_num;
int32_t refIdxLX;
int32_t i;
int32_t PicList[32] = {0};
struct linked_list_t ll;
struct linked_list_t *lp = &ll; // should consider use the scratch space
// declare these below as registers gave me 23 cy/MB for the worst frames in Allegro_Combined_CABAC_07_HD, YHu
register frame_param_ptr temp_fs;
register int32_t temp;
register uint8_t *ip1;
maxPicNum = 1 << (pInfo->active_SPS.log2_max_frame_num_minus4 + 4);
if (list_num == 0) // i.e list 0
{
ip1 = p_dpb->listX_0;
remapping_of_pic_nums_idc = pInfo->SliceHeader.sh_refpic_l0.reordering_of_pic_nums_idc;
list_reordering_num = pInfo->SliceHeader.sh_refpic_l0.list_reordering_num;
}
else
{
ip1 = p_dpb->listX_1;
remapping_of_pic_nums_idc = pInfo->SliceHeader.sh_refpic_l1.reordering_of_pic_nums_idc;
list_reordering_num = pInfo->SliceHeader.sh_refpic_l1.list_reordering_num;
}
linked_list_initialize (lp, ip1, num_ref_idx_active);
currPicNum = pInfo->SliceHeader.frame_num;
if (pInfo->SliceHeader.structure != FRAME)
{
/* The reason it is + 1 I think, is because the list is based on polarity
expand later...
*/
maxPicNum <<= 1;
currPicNum <<= 1;
currPicNum++;
}
picNumLXPred = currPicNum;
refIdxLX = 0;
for (i = 0; remapping_of_pic_nums_idc[i] != 3; i++)
{
if (i > MAX_NUM_REF_FRAMES)
{
break;
}
if (remapping_of_pic_nums_idc[i] < 2) // - short-term re-ordering
{
temp = (list_reordering_num[i].abs_diff_pic_num_minus1 + 1);
if (remapping_of_pic_nums_idc[i] == 0)
{
temp = picNumLXPred - temp;
if (temp < 0 ) picNumLXNoWrap = temp + maxPicNum;
else picNumLXNoWrap = temp;
}
else // (remapping_of_pic_nums_idc[i] == 1)
{
temp += picNumLXPred;
if (temp >= maxPicNum) picNumLXNoWrap = temp - maxPicNum;
else picNumLXNoWrap = temp;
}
// Updates for next iteration of the loop
picNumLXPred = picNumLXNoWrap;
if (picNumLXNoWrap > currPicNum ) pic_num = picNumLXNoWrap - maxPicNum;
else pic_num = picNumLXNoWrap;
temp_fs = h264_dpb_get_short_term_pic(pInfo, pic_num, &bottom_field_bit);
if (temp_fs)
{
temp = bottom_field_bit + PUT_FS_IDC_BITS(temp_fs->fs_idc);
linked_list_reorder (lp, temp);
}
}
else //(remapping_of_pic_nums_idc[i] == 2) long-term re-ordering
{
pic_num = list_reordering_num[i].long_term_pic_num;
temp_fs = h264_dpb_get_long_term_pic(pInfo, pic_num, &bottom_field_bit);
if (temp_fs)
{
temp = PUT_LIST_LONG_TERM_BITS(1) + bottom_field_bit + PUT_FS_IDC_BITS(temp_fs->fs_idc);
linked_list_reorder (lp, temp);
}
}
}
linked_list_output (lp, PicList);
if (0 == list_num )
{
for (i=0; i<num_ref_idx_active; i++)
{
pInfo->slice_ref_list0[i]=(uint8_t)PicList[i];
}
}
else
{
for (i=0; i<num_ref_idx_active; i++)
{
pInfo->slice_ref_list1[i]=(uint8_t)PicList[i];
}
}
// Instead of updating the now reordered list here, just write it down...
// This way, we can continue to hold the initialised list in p_dpb->listX_0
// and therefore not need to update it every slice
//h264_dpb_write_list(list_num, PicList, num_ref_idx_active);
return num_ref_idx_active;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
void h264_dpb_RP_check_list (h264_Info * pInfo)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
uint8_t *p_list = pInfo->slice_ref_list0;
//
// If the decoding start from RP and without exact point, all B frames belong to previous GOP should be throw away!
//
if ((pInfo->SliceHeader.slice_type == h264_PtypeB)&&(pInfo->sei_b_state_ready ==0) && pInfo->sei_rp_received) {
pInfo->wl_err_curr |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
pInfo->wl_err_curr |= (FRAME << FIELD_ERR_OFFSET);
}
//
// Repare Ref list if it damaged with RP recovery only
//
if ((pInfo->SliceHeader.slice_type == h264_PtypeP) && pInfo->sei_rp_received)
{
int32_t idx, rp_found = 0;
if ( ((pInfo->SliceHeader.num_ref_idx_l0_active == 1)&&(pInfo->SliceHeader.structure == FRAME)) ||
((pInfo->SliceHeader.num_ref_idx_l0_active == 2)&&(pInfo->SliceHeader.structure != FRAME)) )
{
if (pInfo->SliceHeader.sh_refpic_l0.ref_pic_list_reordering_flag)
{
p_list = pInfo->slice_ref_list0;
}
else
{
p_list = pInfo->dpb.listX_0;
//pInfo->sei_rp_received = 0;
//return;
}
for (idx = 0; idx < p_dpb->used_size; idx++) {
if (p_dpb->fs_dpb_idc[idx] == pInfo->last_I_frame_idc) {
rp_found = 1;
break;
}
}
if (rp_found) {
#if 0
int32_t poc;
///// Clear long-term ref list
for (idx = 0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_unmark_for_reference(p_dpb, p_dpb->fs_ltref_idc[0]);
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[0]);
}
///// Clear short-term ref list
//while(p_dpb->used_size>1)
for (idx = 0; idx < p_dpb->used_size; idx++)
{
int32_t idx_pos;
//// find smallest non-output POC
h264_dpb_get_smallest_poc(p_dpb, &poc, &idx_pos);
//// Remove all frames in previous GOP
if ((idx_pos != MPD_DPB_FS_NULL_IDC) && (p_dpb->fs_dpb_idc[idx_pos] != pInfo->last_I_frame_idc))
{
// Remove from ref-list
h264_dpb_unmark_for_reference(p_dpb, p_dpb->fs_dpb_idc[idx_pos]);
h264_dpb_remove_ref_list(p_dpb, p_dpb->fs_dpb_idc[idx_pos]);
// Output from DPB
//h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dpb_idc[idx]);
//if((active_fs->is_output == 0) && (active_fs->is_non_existent == 0))
{
//int32_t existing;
//h264_dpb_frame_output(pInfo, p_dpb->fs_dpb_idc[idx], 0, &existing);
//p_dpb->last_output_poc = poc;
}
//h264_dpb_remove_frame_from_dpb(p_dpb, idx); // Remove dpb.fs_dpb_idc[pos]
}
}
#endif
///// Set the reference to last I frame
if ( (pInfo->last_I_frame_idc!=255)&&(pInfo->last_I_frame_idc!=p_list[0]))
{
/// Repaire the reference list now
h264_dpb_unmark_for_reference(p_dpb, p_list[0]);
h264_dpb_remove_ref_list(p_dpb, p_list[0]);
p_list[0] = pInfo->last_I_frame_idc;
if (pInfo->SliceHeader.structure != FRAME)
p_list[1] = (pInfo->last_I_frame_idc ^ 0x20);
}
}
}
pInfo->sei_rp_received = 0;
pInfo->sei_b_state_ready = 1;
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_reorder_lists ()
//
// Used to sort a list based on a corresponding sort indices
//
void h264_dpb_reorder_lists(h264_Info * pInfo)
{
int32_t currSliceType = pInfo->SliceHeader.slice_type;
if (currSliceType == h264_PtypeP )
{
/////////////////////////////////////////////// Reordering reference list for P slice
/// Forward reordering
if (pInfo->SliceHeader.sh_refpic_l0.ref_pic_list_reordering_flag)
h264_dpb_reorder_ref_pic_list(pInfo, 0, pInfo->SliceHeader.num_ref_idx_l0_active);
else
{
}
pInfo->dpb.listXsize[0]=pInfo->SliceHeader.num_ref_idx_l0_active;
} else if (currSliceType == h264_PtypeB)
{
/////////////////////////////////////////////// Reordering reference list for B slice
/// Forward reordering
if (pInfo->SliceHeader.sh_refpic_l0.ref_pic_list_reordering_flag)
h264_dpb_reorder_ref_pic_list(pInfo, 0, pInfo->SliceHeader.num_ref_idx_l0_active);
else
{
}
pInfo->dpb.listXsize[0]=pInfo->SliceHeader.num_ref_idx_l0_active;
/// Backward reordering
if (pInfo->SliceHeader.sh_refpic_l1.ref_pic_list_reordering_flag)
h264_dpb_reorder_ref_pic_list(pInfo, 1, pInfo->SliceHeader.num_ref_idx_l1_active);
else
{
}
pInfo->dpb.listXsize[1]=pInfo->SliceHeader.num_ref_idx_l1_active;
}
//// Check if need recover reference list with previous recovery point
if (!pInfo->img.second_field)
{
h264_dpb_RP_check_list(pInfo);
}
return;
}
////////////////////////////////////////// DPB management //////////////////////
//////////////////////////////////////////////////////////////////////////////
// avc_dpb_get_non_output_frame_number ()
//
// get total non output frame number in the DPB.
//
static int32_t avc_dpb_get_non_output_frame_number(h264_Info * pInfo)
{
int32_t idx;
int32_t number=0;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
for (idx = 0; idx < p_dpb->used_size; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dpb_idc[idx]);
if (viddec_h264_get_is_output(p_dpb->active_fs) == 0)
{
(number)++;
}
}
return number;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//// Store previous picture in DPB, and then update DPB queue, remove unused frames from DPB
void h264_dpb_store_previous_picture_in_dpb(h264_Info * pInfo,int32_t NonExisting, int32_t use_old)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
int32_t used_for_reference;
int32_t is_direct_output;
int32_t second_field_stored = 0;
int32_t poc;
int32_t pos;
int32_t flag;
int32_t first_field_non_ref = 0;
int32_t idr_flag;
if (NonExisting) {
if (p_dpb->fs_non_exist_idc == MPD_DPB_FS_NULL_IDC)
return;
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_non_exist_idc);
} else {
if (p_dpb->fs_dec_idc == MPD_DPB_FS_NULL_IDC)
return;
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
}
if (NonExisting == 0)
{
//active_fs->sps_disp_index = (next_sps_disp_entry == 0)? 7 : next_sps_disp_entry - 1;
pInfo->img.last_has_mmco_5 = 0;
pInfo->img.last_pic_bottom_field = pInfo->img.bottom_field_flag;
//used_for_reference = (use_old) ? !(old_pInfo->img.old_disposable_flag) : !(pInfo->img.disposable_flag);
used_for_reference = (use_old) ? !(pInfo->old_slice.nal_ref_idc==0) : !(pInfo->SliceHeader.nal_ref_idc==0);
switch (viddec_h264_get_dec_structure(p_dpb->active_fs))
{
case(TOP_FIELD) : {
p_dpb->active_fs->top_field.used_for_reference = used_for_reference;
viddec_h264_set_is_top_used(p_dpb->active_fs, 1);
//p_dpb->active_fs->crc_field_coded = 1;
}
break;
case(BOTTOM_FIELD): {
p_dpb->active_fs->bottom_field.used_for_reference = used_for_reference << 1;
viddec_h264_set_is_bottom_used(p_dpb->active_fs, 1);
//p_dpb->active_fs->crc_field_coded = 1;
}
break;
default: {
p_dpb->active_fs->frame.used_for_reference = used_for_reference?3:0;
viddec_h264_set_is_frame_used(p_dpb->active_fs, 3);
//if(pInfo->img.MbaffFrameFlag) p_dpb->active_fs->crc_field_coded = 1;
}
break;
}
//freeze_assert = use_old ? old_pInfo->img.sei_freeze_this_image : pInfo->img.sei_freeze_this_image;
//if (freeze_assert) sei_information.disp_frozen = 1;
idr_flag = use_old ? pInfo->old_slice.idr_flag : pInfo->SliceHeader.idr_flag;
if (idr_flag) {
h264_dpb_idr_memory_management (pInfo, &pInfo->active_SPS, pInfo->img.no_output_of_prior_pics_flag);
} else {
// adaptive memory management
if (used_for_reference & pInfo->SliceHeader.sh_dec_refpic.adaptive_ref_pic_marking_mode_flag) {
h264_dpb_adaptive_memory_management(pInfo);
}
}
// Reset the active frame store - could have changed in mem management ftns
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if ((viddec_h264_get_dec_structure(p_dpb->active_fs) == TOP_FIELD)||(viddec_h264_get_dec_structure(p_dpb->active_fs) == BOTTOM_FIELD))
{
// check for frame store with same pic_number -- always true in my case, YH
// when we allocate frame store for the second field, we make sure the frame store for the second
// field is the one that contains the first field of the frame- see h264_dpb_init_frame_store()
// This is different from JM model.
// In this way we don't need to move image data around and can reduce memory bandwidth.
// simply check if the check if the other field has been decoded or not
if (viddec_h264_get_is_used(p_dpb->active_fs) != 0)
{
if (pInfo->img.second_field)
{
h264_dpb_insert_picture_in_dpb(pInfo, used_for_reference, 0, NonExisting, use_old);
second_field_stored = 1;
}
}
}
}
else
{ // Set up locals for non-existing frames
used_for_reference = 1;
p_dpb->active_fs->frame.used_for_reference = used_for_reference?3:0;
viddec_h264_set_is_frame_used(p_dpb->active_fs, 3);
viddec_h264_set_dec_structure(p_dpb->active_fs, FRAME);
pInfo->img.structure = FRAME;
}
is_direct_output = 0;
if (NonExisting == 0)
{
if (p_dpb->used_size >= p_dpb->BumpLevel)
{
// non-reference frames may be output directly
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if ((used_for_reference == 0) && (viddec_h264_get_is_used(p_dpb->active_fs) == 3))
{
h264_dpb_get_smallest_poc (p_dpb, &poc, &pos);
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if ((pos == MPD_DPB_FS_NULL_IDC) || (pInfo->img.ThisPOC < poc))
{
is_direct_output = 1;
}
}
}
}
if (NonExisting) {
h264_dpb_sliding_window_memory_management(p_dpb, NonExisting, pInfo->active_SPS.num_ref_frames);
} else if (pInfo->SliceHeader.idr_flag == 0) {
if (used_for_reference) {
if (pInfo->img.second_field == 0) {
if (pInfo->SliceHeader.sh_dec_refpic.adaptive_ref_pic_marking_mode_flag == 0) {
h264_dpb_sliding_window_memory_management(p_dpb, NonExisting, pInfo->active_SPS.num_ref_frames);
}
}
}
}
h264_dpb_remove_unused_frame_from_dpb(p_dpb, &flag);
//if (is_direct_output == 0)
{
if ((pInfo->img.second_field == 0) || (NonExisting))
{
h264_dpb_insert_picture_in_dpb(pInfo, used_for_reference, 1, NonExisting, use_old);
}
// In an errored stream we saw a condition where
// p_dpb->ref_frames_in_buffer + p_dpb->ltref_frames_in_buffer > p_dpb->BumpLevel,
// which in itself is an error, but this means first_field_non_ref will
// not get set and causes problems for h264_dpb_queue_update()
if ((pInfo->img.structure != FRAME) && (pInfo->img.second_field == 0)) {
if (used_for_reference == 0)
if (p_dpb->ref_frames_in_buffer + p_dpb->ltref_frames_in_buffer == p_dpb->BumpLevel)
first_field_non_ref = 1;
}
}
if (NonExisting)
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_non_exist_idc);
else
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if (NonExisting == 0)
{
if ((pInfo->img.second_field == 1) || (pInfo->img.structure == FRAME))
{
//h264_send_new_decoded_frame();
if ((p_dpb->OutputCtrl) && (is_direct_output == 0))
h264_dpb_output_one_frame_from_dpb(pInfo, 0, 0,pInfo->active_SPS.num_ref_frames);
// Pictures inserted by this point - check if we have reached the specified output
// level (if one has been specified) so we can begin on next call
/*
Fixed HSD 212625---------------should compare OutputLevel with non-output frame number in dpb, not the used number in dpb
if((p_dpb->OutputLevelValid)&&(p_dpb->OutputCtrl == 0))
{
if(p_dpb->used_size == p_dpb->OutputLevel)
p_dpb->OutputCtrl = 1;
}
*/
if (p_dpb->OutputLevelValid)
{
int32_t non_output_frame_number=0;
non_output_frame_number = avc_dpb_get_non_output_frame_number(pInfo);
if (non_output_frame_number == p_dpb->OutputLevel)
p_dpb->OutputCtrl = 1;
else
p_dpb->OutputCtrl = 0;
}
else {
p_dpb->OutputCtrl = 0;
}
}
}
while (p_dpb->used_size > (p_dpb->BumpLevel + first_field_non_ref))
//while(p_dpb->used_size > p_dpb->BumpLevel)
{
h264_dpb_queue_update(pInfo, 1, 0, 0,pInfo->active_SPS.num_ref_frames); // flush a frame
//h264_dpb_remove_unused_frame_from_dpb(p_dpb, &flag);
}
//
// Do not output "direct output" pictures until the sempahore has been set that the pic is
// decoded!!
//
if (is_direct_output) {
h264_dpb_queue_update(pInfo, 1, 1, 0,pInfo->active_SPS.num_ref_frames);
//h264_dpb_remove_unused_frame_from_dpb(p_dpb, &flag);
}
//
// Add reference pictures into Reference list
//
if (used_for_reference) {
h264_dpb_insert_ref_lists(&pInfo->dpb, NonExisting);
}
h264_dpb_remove_unused_frame_from_dpb(p_dpb, &flag);
return;
} ////////////// End of DPB store pic
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_insert_picture_in_dpb ()
//
// Insert the decoded picture into the DPB. A free DPB position is necessary
// for frames, .
// This ftn tends to fill out the framestore's top level parameters from the
// storable picture's parameters within it. It is called from h264_dpb_store_picture_in_dpb()
//
// This function finishes by updating the reference lists - this means it must be called after
// h264_dpb_sliding_window_memory_management()
//
// In the case of a frame it will call h264_dpb_split_field()
// In the case of the second field of a complementary field pair it calls h264_dpb_combine_field()
//
void h264_dpb_insert_picture_in_dpb(h264_Info * pInfo,int32_t used_for_reference, int32_t add2dpb, int32_t NonExisting, int32_t use_old)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
if (NonExisting == 0) {
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
p_dpb->active_fs->frame_num = (use_old) ? pInfo->old_slice.frame_num : pInfo->SliceHeader.frame_num;
}
else {
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_non_exist_idc);
p_dpb->active_fs->frame_num = p_dpb->active_fs->frame.pic_num;
}
if (add2dpb) {
p_dpb->fs_dpb_idc[p_dpb->used_size] = p_dpb->active_fs->fs_idc;
p_dpb->used_size++;
}
switch (viddec_h264_get_dec_structure(p_dpb->active_fs))
{
case FRAME : {
viddec_h264_set_is_frame_used(p_dpb->active_fs, 3);
p_dpb->active_fs->frame.used_for_reference = used_for_reference?3:0;
if (used_for_reference)
{
p_dpb->active_fs->frame.used_for_reference = 3;
if (p_dpb->active_fs->frame.is_long_term)
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 3);
}
// Split frame to 2 fields for prediction
h264_dpb_split_field(p_dpb, pInfo);
}
break;
case TOP_FIELD : {
viddec_h264_set_is_top_used(p_dpb->active_fs, 1);
p_dpb->active_fs->top_field.used_for_reference = used_for_reference;
if (used_for_reference)
{
p_dpb->active_fs->frame.used_for_reference |= 0x1;
if (p_dpb->active_fs->top_field.is_long_term)
{
viddec_h264_set_is_top_long_term(p_dpb->active_fs, 1);
p_dpb->active_fs->long_term_frame_idx = p_dpb->active_fs->top_field.long_term_frame_idx;
}
}
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3) {
h264_dpb_combine_field(p_dpb, use_old); // generate frame view
}
else
{
p_dpb->active_fs->frame.poc = p_dpb->active_fs->top_field.poc;
}
}
break;
case BOTTOM_FIELD : {
viddec_h264_set_is_bottom_used(p_dpb->active_fs, 1);
p_dpb->active_fs->bottom_field.used_for_reference = (used_for_reference<<1);
if (used_for_reference)
{
p_dpb->active_fs->frame.used_for_reference |= 0x2;
if (p_dpb->active_fs->bottom_field.is_long_term)
{
viddec_h264_set_is_bottom_long_term(p_dpb->active_fs, 1);
p_dpb->active_fs->long_term_frame_idx = p_dpb->active_fs->bottom_field.long_term_frame_idx;
}
}
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3) {
h264_dpb_combine_field(p_dpb, use_old); // generate frame view
}
else
{
p_dpb->active_fs->frame.poc = p_dpb->active_fs->bottom_field.poc;
}
}
break;
}
/*
if ( gRestartMode.LastRestartType == RESTART_SEI )
{
if ( p_dpb->active_fs->open_gop_entry ) dpb.WaitSeiRecovery = 1;
}
gRestartMode.LastRestartType = 0xFFFF;
*/
return;
} ////// End of insert picture in DPB
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_unmark_short_term_for_reference ()
//
// Adaptive Memory Management: Mark short term picture unused
//
void h264_dpb_mm_unmark_short_term_for_reference(h264_Info * pInfo, int32_t difference_of_pic_nums_minus1)
{
int32_t picNumX;
int32_t currPicNum;
uint32_t idx;
int32_t unmark_done;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
if (pInfo->img.structure == FRAME)
currPicNum = pInfo->img.frame_num;
else
currPicNum = (pInfo->img.frame_num << 1) + 1;
picNumX = currPicNum - (difference_of_pic_nums_minus1 + 1);
unmark_done = 0;
for (idx =0; (idx < p_dpb->ref_frames_in_buffer) && (!(unmark_done)); idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (pInfo->img.structure == FRAME)
{
/* If all pic numbers in the list are different (and they should be)
we should terminate the for loop the moment we match pic numbers,
no need to continue to check - hence set unmark_done
*/
if ((p_dpb->active_fs->frame.used_for_reference == 3) && (viddec_h264_get_is_long_term(p_dpb->active_fs) == 0) &&
(p_dpb->active_fs->frame.pic_num == picNumX))
{
h264_dpb_unmark_for_reference(p_dpb, p_dpb->active_fs->fs_idc);
h264_dpb_remove_ref_list(p_dpb, p_dpb->active_fs->fs_idc);
unmark_done = 1;
}
}
else
{
/*
If we wish to unmark a short-term picture by picture number when the current picture
is a field, we have to unmark the corresponding field as unused for reference,
and also if it was part of a frame or complementary reference field pair, the
frame is to be marked as unused. However the opposite field may still be used as a
reference for future fields
How will this affect the reference list update ftn coming after??
*/
if ((p_dpb->active_fs->frame.used_for_reference&0x1) && (!(viddec_h264_get_is_long_term(p_dpb->active_fs)&0x01))&&
(p_dpb->active_fs->top_field.pic_num == picNumX) )
{
p_dpb->active_fs->top_field.used_for_reference = 0;
p_dpb->active_fs->frame.used_for_reference &= 2;
unmark_done = 1;
//Check if other field is used for short-term reference, if not remove from list...
if (p_dpb->active_fs->bottom_field.used_for_reference == 0)
h264_dpb_remove_ref_list(p_dpb, p_dpb->fs_ref_idc[idx]);
}
if ((p_dpb->active_fs->frame.used_for_reference&0x2) && (!(viddec_h264_get_is_long_term(p_dpb->active_fs)&0x2)) &&
(p_dpb->active_fs->bottom_field.pic_num == picNumX) )
{
p_dpb->active_fs->bottom_field.used_for_reference = 0;
p_dpb->active_fs->frame.used_for_reference &= 1;
unmark_done = 1;
//Check if other field is used for reference, if not remove from list...
if (p_dpb->active_fs->top_field.used_for_reference == 0)
h264_dpb_remove_ref_list(p_dpb, p_dpb->fs_ref_idc[idx]);
}
}
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
////////////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_unmark_long_term_for_reference ()
//
// Adaptive Memory Management: Mark long term picture unused
//
// In a frame situation the long_term_pic_num will refer to another frame.
// Thus we can call h264_dpb_unmark_for_long_term_reference() and then remove the picture
// from the list
//
// If the current picture is a field, long_term_pic_num will refer to another field
// It is also the case that each individual field should have a unique picture number
// 8.2.5.4.2 suggests that when curr pic is a field, an mmco == 2 operation
// should be accompanied by a second op to unmark the other field as being unused
///////////////////////////////////////////////////////////////////////////////////
void h264_dpb_mm_unmark_long_term_for_reference (h264_Info * pInfo, int32_t long_term_pic_num)
{
uint32_t idx;
int32_t unmark_done;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
unmark_done = 0;
for (idx = 0; (idx < p_dpb->ltref_frames_in_buffer) && (!(unmark_done)); idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if (pInfo->img.structure == FRAME)
{
if ((p_dpb->active_fs->frame.used_for_reference==3) && (viddec_h264_get_is_long_term(p_dpb->active_fs)==3) &&
(p_dpb->active_fs->frame.long_term_pic_num == long_term_pic_num))
{
h264_dpb_unmark_for_long_term_reference(p_dpb, p_dpb->fs_ltref_idc[idx]);
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx]);
unmark_done = 1;
}
}
else
{
/// Check top field
if ((p_dpb->active_fs->frame.used_for_reference&0x1) && (viddec_h264_get_is_long_term(p_dpb->active_fs)&0x1) &&
(p_dpb->active_fs->top_field.long_term_pic_num == long_term_pic_num) )
{
p_dpb->active_fs->top_field.used_for_reference = 0;
p_dpb->active_fs->top_field.is_long_term = 0;
p_dpb->active_fs->frame.used_for_reference &= 2;
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 2);
unmark_done = 1;
//Check if other field is used for long term reference, if not remove from list...
if ((p_dpb->active_fs->bottom_field.used_for_reference == 0) || (p_dpb->active_fs->bottom_field.is_long_term == 0))
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx]);
}
/// Check Bottom field
if ((p_dpb->active_fs->frame.used_for_reference&0x2) && (viddec_h264_get_is_long_term(p_dpb->active_fs)&0x2) &&
(p_dpb->active_fs->bottom_field.long_term_pic_num == long_term_pic_num) )
{
p_dpb->active_fs->bottom_field.used_for_reference = 0;
p_dpb->active_fs->bottom_field.is_long_term = 0;
p_dpb->active_fs->frame.used_for_reference &= 1;
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 1);
unmark_done = 1;
//Check if other field is used for long term reference, if not remove from list...
if ((p_dpb->active_fs->top_field.used_for_reference == 0) || (p_dpb->active_fs->top_field.is_long_term == 0))
{
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx]);
}
}
} // field structure
} //for(idx)
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_get_pic_struct_by_pic_num
//
// Searches the fields appearing in short term reference list
// Returns the polarity of the field with pic_num = picNumX
//////////////////////////////////////////////////////////////////////////////
int32_t h264_dpb_get_pic_struct_by_pic_num(h264_DecodedPictureBuffer *p_dpb, int32_t picNumX)
{
uint32_t idx;
int32_t pic_struct = INVALID;
int32_t found = 0;
for (idx =0; (idx < p_dpb->ref_frames_in_buffer) && (!(found)); idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if ((p_dpb->active_fs->frame.used_for_reference&0x1) && (!(viddec_h264_get_is_long_term(p_dpb->active_fs)&0x01))&&
(p_dpb->active_fs->top_field.pic_num == picNumX) )
{
found = 1;
pic_struct = TOP_FIELD;
}
if ((p_dpb->active_fs->frame.used_for_reference&0x2) && (!(viddec_h264_get_is_long_term(p_dpb->active_fs)&0x2)) &&
(p_dpb->active_fs->bottom_field.pic_num == picNumX) )
{
found = 1;
pic_struct = BOTTOM_FIELD;
}
}
return pic_struct;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_assign_long_term_frame_idx ()
//
// Assign a long term frame index to a short term picture
// Both lists must be updated as part of this process...
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_mm_assign_long_term_frame_idx(h264_Info * pInfo, int32_t difference_of_pic_nums_minus1, int32_t long_term_frame_idx)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
int32_t picNumX;
int32_t currPicNum;
int32_t polarity = 0;
if (pInfo->img.structure == FRAME) {
currPicNum = pInfo->img.frame_num;
} else {
currPicNum = (pInfo->img.frame_num << 1) + 1;
}
picNumX = currPicNum - (difference_of_pic_nums_minus1 + 1);
// remove frames / fields with same long_term_frame_idx
if (pInfo->img.structure == FRAME) {
h264_dpb_unmark_long_term_frame_for_reference_by_frame_idx(p_dpb, long_term_frame_idx);
} else {
polarity = h264_dpb_get_pic_struct_by_pic_num(p_dpb, picNumX);
if (polarity != INVALID)
h264_dpb_unmark_long_term_field_for_reference_by_frame_idx(p_dpb, long_term_frame_idx, p_dpb->active_fs->fs_idc, polarity);
}
h264_dpb_mark_pic_long_term(pInfo, long_term_frame_idx, picNumX);
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_update_max_long_term_frame_idx ()
//
// Set new max long_term_frame_idx
//
void h264_dpb_mm_update_max_long_term_frame_idx(h264_DecodedPictureBuffer *p_dpb,int32_t max_long_term_frame_idx_plus1)
{
//h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
int32_t idx;
int32_t temp;
int32_t removed_count;
int32_t idx2 = 0;
p_dpb->max_long_term_pic_idx = max_long_term_frame_idx_plus1 - 1;
temp = p_dpb->ltref_frames_in_buffer;
removed_count = 0;
// check for invalid frames
for (idx = 0; idx < temp; idx++)
{
idx2 = idx - removed_count;
if (idx2 < 16 && idx2 > 0)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx2]);
if (p_dpb->active_fs->long_term_frame_idx > p_dpb->max_long_term_pic_idx)
{
removed_count++;
h264_dpb_unmark_for_long_term_reference(p_dpb, p_dpb->fs_ltref_idc[idx2]);
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx2]);
}
}
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_unmark_all_short_term_for_reference ()
//
// Unmark all short term refernce pictures
//
void h264_dpb_mm_unmark_all_short_term_for_reference (h264_DecodedPictureBuffer *p_dpb)
{
int32_t idx;
int32_t temp = p_dpb->ref_frames_in_buffer;
for (idx = 0; idx < temp; idx++)
{
h264_dpb_unmark_for_reference(p_dpb, p_dpb->fs_ref_idc[0]);
h264_dpb_remove_ref_list(p_dpb, p_dpb->fs_ref_idc[0]);
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mm_mark_current_picture_long_term ()
//
// Marks the current picture as long term after unmarking any long term picture
// already assigned with the same long term frame index
//
void h264_dpb_mm_mark_current_picture_long_term(h264_DecodedPictureBuffer *p_dpb, int32_t long_term_frame_idx)
{
int32_t picNumX;
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if (viddec_h264_get_dec_structure(p_dpb->active_fs) == FRAME)
{
h264_dpb_unmark_long_term_frame_for_reference_by_frame_idx(p_dpb, long_term_frame_idx);
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
p_dpb->active_fs->frame.is_long_term = 1;
p_dpb->active_fs->frame.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->frame.long_term_pic_num = long_term_frame_idx;
}
else
{
if (viddec_h264_get_dec_structure(p_dpb->active_fs) == TOP_FIELD)
{
picNumX = (p_dpb->active_fs->top_field.pic_num << 1) + 1;
p_dpb->active_fs->top_field.is_long_term = 1;
p_dpb->active_fs->top_field.long_term_frame_idx = long_term_frame_idx;
// Assign long-term pic num
p_dpb->active_fs->top_field.long_term_pic_num = (long_term_frame_idx << 1) + 1;
}
else
{
picNumX = (p_dpb->active_fs->bottom_field.pic_num << 1) + 1;
p_dpb->active_fs->bottom_field.is_long_term = 1;
p_dpb->active_fs->bottom_field.long_term_frame_idx = long_term_frame_idx;
// Assign long-term pic num
p_dpb->active_fs->bottom_field.long_term_pic_num = (long_term_frame_idx << 1) + 1;
}
h264_dpb_unmark_long_term_field_for_reference_by_frame_idx(p_dpb, long_term_frame_idx, p_dpb->fs_dec_idc, viddec_h264_get_dec_structure(p_dpb->active_fs));
}
// Add to long term list
//h264_dpb_add_ltref_list(p_dpb->fs_dec_idc);
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_unmark_long_term_frame_for_reference_by_frame_idx ()
//
// Mark a long-term reference frame or complementary field pair unused for referemce
// NOTE: Obviously this ftn cannot be used to unmark individual fields...
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_unmark_long_term_frame_for_reference_by_frame_idx(h264_DecodedPictureBuffer *p_dpb, int32_t long_term_frame_idx)
{
uint32_t idx;
for (idx =0; idx < p_dpb->ltref_frames_in_buffer; idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if (p_dpb->active_fs->long_term_frame_idx == long_term_frame_idx)
{
h264_dpb_unmark_for_long_term_reference(p_dpb, p_dpb->fs_ltref_idc[idx]);
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx]);
}
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_unmark_long_term_field_for_reference_by_frame_idx ()
//
// Mark a long-term reference field unused for reference. However if it is the
// complementary field (opposite polarity) of the picture stored in fs_idc,
// we do not unmark it
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_unmark_long_term_field_for_reference_by_frame_idx(h264_DecodedPictureBuffer *p_dpb, int32_t long_term_frame_idx, int32_t fs_idc, int32_t polarity)
{
uint32_t idx;
int32_t found = 0;
int32_t is_complement = 0;
for (idx = 0; (idx < p_dpb->ltref_frames_in_buffer) && (found == 0); idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ltref_idc[idx]);
if (p_dpb->active_fs->long_term_frame_idx == long_term_frame_idx)
{
if (p_dpb->active_fs->fs_idc == fs_idc)
{
// Again these seem like redundant checks but for safety while until JM is updated
if (polarity == TOP_FIELD)
is_complement = (p_dpb->active_fs->bottom_field.is_long_term)? 1:0;
else if (polarity == BOTTOM_FIELD)
is_complement = (p_dpb->active_fs->top_field.is_long_term) ? 1:0;
}
found = 1;
}
}
if (found) {
if (is_complement == 0)
{
h264_dpb_unmark_for_long_term_reference(p_dpb, p_dpb->fs_ltref_idc[idx-1]);
h264_dpb_remove_ltref_list(p_dpb, p_dpb->fs_ltref_idc[idx-1]);
}
}
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mark_pic_long_term ()
//
// This is used on a picture already in the dpb - i.e. not for the current picture
// dpb_split / dpb_combine field will perform ftnality in that case
//
// Marks a picture as used for long-term reference. Adds it to the long-term
// reference list. Also removes it from the short term reference list if required
//
// Note: if the current picture is a frame, the picture to be marked will be a
// short-term reference frame or short-term complemenetary reference field pair
// We use the pic_num assigned to the frame part of the structure to locate it
// Both its fields will have their long_term_frame_idx and long_term_pic_num
// assigned to be equal to long_term_frame_idx
//
// If the current picture is a field, the picture to be marked will be a
// short-term reference field. We use the pic_nums assigned to the field parts of
// the structure to identify the appropriate field. We assign the long_term_frame_idx
// of the field equal to long_term_frame_idx.
//
// We also check to see if this marking has resulted in both fields of the frame
// becoming long_term. If it has, we update the frame part of the structure by
// setting its long_term_frame_idx
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_mark_pic_long_term(h264_Info * pInfo, int32_t long_term_frame_idx, int32_t picNumX)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
uint32_t idx;
int32_t mark_done;
int32_t polarity = 0;
mark_done = 0;
if (pInfo->img.structure == FRAME)
{
for (idx = 0; (idx < p_dpb->ref_frames_in_buffer) && (!(mark_done)); idx++)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_ref_idc[idx]);
if (p_dpb->active_fs->frame.used_for_reference == 3)
{
if ((!(p_dpb->active_fs->frame.is_long_term))&&(p_dpb->active_fs->frame.pic_num == picNumX))
{
p_dpb->active_fs->long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->frame.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->top_field.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->bottom_field.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->frame.is_long_term = 1;
p_dpb->active_fs->top_field.is_long_term = 1;
p_dpb->active_fs->bottom_field.is_long_term = 1;
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 3);
mark_done = 1;
// Assign long-term pic num
p_dpb->active_fs->frame.long_term_pic_num = long_term_frame_idx;
p_dpb->active_fs->top_field.long_term_pic_num = long_term_frame_idx;
p_dpb->active_fs->bottom_field.long_term_pic_num = long_term_frame_idx;
// Add to long term list
h264_dpb_add_ltref_list(p_dpb, p_dpb->fs_ref_idc[idx]);
// Remove from short-term list
h264_dpb_remove_ref_list(p_dpb, p_dpb->fs_ref_idc[idx]);
}
}
}
}
else
{
polarity = h264_dpb_get_pic_struct_by_pic_num(p_dpb, picNumX);
p_dpb->active_fs->long_term_frame_idx = long_term_frame_idx; /////BUG
if (polarity == TOP_FIELD)
{
p_dpb->active_fs->top_field.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->top_field.is_long_term = 1;
viddec_h264_set_is_top_long_term(p_dpb->active_fs, 1);
// Assign long-term pic num
p_dpb->active_fs->top_field.long_term_pic_num = (long_term_frame_idx << 1) + ((pInfo->img.structure == TOP_FIELD) ? 1 : 0);
}
else if (polarity == BOTTOM_FIELD)
{
p_dpb->active_fs->bottom_field.long_term_frame_idx = long_term_frame_idx;
p_dpb->active_fs->bottom_field.is_long_term = 1;
viddec_h264_set_is_bottom_long_term(p_dpb->active_fs, 1);
// Assign long-term pic num
p_dpb->active_fs->bottom_field.long_term_pic_num = (long_term_frame_idx << 1) + ((pInfo->img.structure == BOTTOM_FIELD) ? 1 : 0);
}
if (viddec_h264_get_is_long_term(p_dpb->active_fs) == 3)
{
p_dpb->active_fs->frame.is_long_term = 1;
p_dpb->active_fs->frame.long_term_frame_idx = long_term_frame_idx;
h264_dpb_remove_ref_list(p_dpb, p_dpb->active_fs->fs_idc);
}
else
{
// We need to add this idc to the long term ref list...
h264_dpb_add_ltref_list(p_dpb, p_dpb->active_fs->fs_idc);
// If the opposite field is not a short term reference, remove it from the
// short term list. Since we know top field is a reference but both are not long term
// we can simply check that both fields are not references...
if (p_dpb->active_fs->frame.used_for_reference != 3)
h264_dpb_remove_ref_list(p_dpb, p_dpb->active_fs->fs_idc);
}
}
return;
} ///// End of mark pic long term
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_adaptive_memory_management ()
//
// Perform Adaptive memory control decoded reference picture marking process
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_adaptive_memory_management (h264_Info * pInfo)
{
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
int32_t idx;
idx = 0;
while (idx < pInfo->SliceHeader.sh_dec_refpic.dec_ref_pic_marking_count)
{
switch (pInfo->SliceHeader.sh_dec_refpic.memory_management_control_operation[idx])
{
case 1: { //Mark a short-term reference picture as ´┐Żunused for reference?
h264_dpb_mm_unmark_short_term_for_reference(pInfo,
pInfo->SliceHeader.sh_dec_refpic.difference_of_pic_num_minus1[idx]);
}
break;
case 2: { //Mark a long-term reference picture as ´┐Żunused for reference?
h264_dpb_mm_unmark_long_term_for_reference(pInfo,
pInfo->SliceHeader.sh_dec_refpic.long_term_pic_num[idx]);
}
break;
case 3: { //Mark a short-term reference picture as "used for long-term reference" and assign a long-term frame index to it
h264_dpb_mm_assign_long_term_frame_idx(pInfo,
pInfo->SliceHeader.sh_dec_refpic.difference_of_pic_num_minus1[idx],
pInfo->SliceHeader.sh_dec_refpic.long_term_frame_idx[idx]);
}
break;
case 4: { //Specify the maximum long-term frame index and
//mark all long-term reference pictureshaving long-term frame indices greater than
//the maximum value as "unused for reference"
h264_dpb_mm_update_max_long_term_frame_idx (&pInfo->dpb,
pInfo->SliceHeader.sh_dec_refpic.max_long_term_frame_idx_plus1[idx]);
}
break;
case 5: { //Mark all reference pictures as "unused for reference" and set the MaxLongTermFrameIdx variable to
// "no long-term frame indices"
h264_dpb_mm_unmark_all_short_term_for_reference(&pInfo->dpb);
h264_dpb_mm_update_max_long_term_frame_idx(&pInfo->dpb, 0);
pInfo->img.last_has_mmco_5 = 1;
}
break;
case 6: { //Mark the current picture as "used for long-term reference" and assign a long-term frame index to it
h264_dpb_mm_mark_current_picture_long_term(&pInfo->dpb,
pInfo->SliceHeader.sh_dec_refpic.long_term_frame_idx[idx]);
}
break;
}
idx++;
}
if (pInfo->img.last_has_mmco_5)
{
pInfo->img.frame_num = 0;
pInfo->SliceHeader.frame_num=0;
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dec_idc);
if (viddec_h264_get_dec_structure(p_dpb->active_fs) == FRAME)
{
pInfo->img.bottompoc -= p_dpb->active_fs->frame.poc;
pInfo->img.toppoc -= p_dpb->active_fs->frame.poc;
p_dpb->active_fs->frame.poc = 0;
p_dpb->active_fs->frame.pic_num = 0;
p_dpb->active_fs->frame_num = 0;
}
else if (viddec_h264_get_dec_structure(p_dpb->active_fs) == TOP_FIELD)
{
p_dpb->active_fs->top_field.poc = p_dpb->active_fs->top_field.pic_num = 0;
pInfo->img.toppoc = p_dpb->active_fs->top_field.poc;
}
else if (viddec_h264_get_dec_structure(p_dpb->active_fs) == BOTTOM_FIELD)
{
p_dpb->active_fs->bottom_field.poc = p_dpb->active_fs->bottom_field.pic_num = 0;
pInfo->img.bottompoc = 0;
}
h264_dpb_flush_dpb(pInfo, 1, pInfo->img.second_field,pInfo->active_SPS.num_ref_frames);
}
// Reset the marking count operations for the current picture...
pInfo->SliceHeader.sh_dec_refpic.dec_ref_pic_marking_count = 0;
return;
} ////// End of adaptive memory management
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_gaps_in_frame_num_mem_management ()
//
// Produces a set of frame_nums pertaining to "non-existing" pictures
// Calls h264_dpb_store_picture_in_dpb
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_gaps_in_frame_num_mem_management(h264_Info * pInfo)
{
int32_t temp_frame_num = 0;
int32_t idx, prev_idc;
int32_t prev_frame_num_plus1_wrap;
uint32_t temp = 0;
int32_t MaxFrameNum = 1 << (pInfo->active_SPS.log2_max_frame_num_minus4 + 4);
seq_param_set_used_ptr active_sps = &pInfo->active_SPS;
h264_DecodedPictureBuffer *p_dpb = &pInfo->dpb;
pInfo->img.gaps_in_frame_num = 0;
// pInfo->img.last_has_mmco_5 set thru store_picture_in_dpb
if (pInfo->img.last_has_mmco_5)
{
// If the previous picture was an unpaired field, mark it as a dangler
if (p_dpb->used_size)
{
idx = p_dpb->used_size-1;
prev_idc = p_dpb->fs_dpb_idc[idx];
if (prev_idc != MPD_DPB_FS_NULL_IDC)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dpb_idc[idx]);
p_dpb->active_fs->frame_num =0;
}
}
pInfo->img.PreviousFrameNumOffset = 0;
//CONFORMANCE_ISSUE
pInfo->img.PreviousFrameNum = 0;
}
// Check for gaps in frame_num
if (pInfo->SliceHeader.idr_flag) {
pInfo->img.PreviousFrameNum = pInfo->img.frame_num;
}
// Have we re-started following a recovery point message?
/*
else if(got_sei_recovery || aud_got_restart){
pInfo->img.PreviousFrameNum = pInfo->img.frame_num;
//got_sei_recovery = 0;
//aud_got_restart = 0;
}
*/
else if (pInfo->img.frame_num != pInfo->img.PreviousFrameNum)
{
if (MaxFrameNum) {
ldiv_mod_u((uint32_t)(pInfo->img.PreviousFrameNum + 1), (uint32_t)MaxFrameNum, &temp);
} else {
temp = (uint32_t)pInfo->img.PreviousFrameNum + 1;
}
prev_frame_num_plus1_wrap = temp;
if (pInfo->img.frame_num != prev_frame_num_plus1_wrap)
{
pInfo->img.gaps_in_frame_num = (pInfo->img.frame_num < pInfo->img.PreviousFrameNum)? ((MaxFrameNum + pInfo->img.frame_num -1) - pInfo->img.PreviousFrameNum): (pInfo->img.frame_num - pInfo->img.PreviousFrameNum - 1);
// We should test for an error here - should infer an unintentional loss of pictures
}
}
//if(active_sps->gaps_in_frame_num_value_allowed_flag == 0) {
if (pInfo->img.gaps_in_frame_num && (active_sps->gaps_in_frame_num_value_allowed_flag == 0)) {
// infer an unintentional loss of pictures
// only invoke following process for a conforming bitstream
// when gaps_in_frame_num_value_allowed_flag is equal to 1
pInfo->img.gaps_in_frame_num = 0;
#ifdef VBP
#ifdef SW_ERROR_CONCEALEMNT
pInfo->sw_bail = 1;
#endif
#endif
//mfd_printf("ERROR STREAM??\n");
////// Error handling here----
}
/////// Removed following OLO source (Sodaville H.D)
//else if (pInfo->img.gaps_in_frame_num > active_sps->num_ref_frames) {
// // No need to produce any more non-existent frames than the amount required to flush the dpb
// pInfo->img.gaps_in_frame_num = active_sps->num_ref_frames;
//mfd_printf("gaps in frame: %d\n", gaps_in_frame_num);
//}
// If the previous picture was an unpaired field, mark it as a dangler
if (p_dpb->used_size)
{
idx = p_dpb->used_size-1;
prev_idc = p_dpb->fs_dpb_idc[idx];
if (prev_idc != MPD_DPB_FS_NULL_IDC)
{
h264_dpb_set_active_fs(p_dpb, p_dpb->fs_dpb_idc[idx]);
if (viddec_h264_get_is_used(p_dpb->active_fs) != 3) {
h264_dpb_mark_dangling_field(p_dpb, p_dpb->active_fs->fs_idc); //, DANGLING_TYPE_GAP_IN_FRAME
}
}
}
while (temp_frame_num < pInfo->img.gaps_in_frame_num)
{
h264_dpb_assign_frame_store(pInfo, 1);
// Set up initial markings - not sure if all are needed
viddec_h264_set_dec_structure(p_dpb->active_fs, FRAME);
if (MaxFrameNum)
ldiv_mod_u((uint32_t)(pInfo->img.PreviousFrameNum + 1), (uint32_t)MaxFrameNum, &temp);
p_dpb->active_fs->frame.pic_num = temp;
p_dpb->active_fs->long_term_frame_idx = 0;
p_dpb->active_fs->frame.long_term_pic_num = 0;
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 0);
// Note the call below will overwrite some aspects of the img structure with info relating to the
// non-existent picture
// However, since this is called before h264_hdr_decoding_poc() for the current existing picture
// it should be o.k.
if (pInfo->img.pic_order_cnt_type)
h264_hdr_decoding_poc(pInfo, 1, temp);
pInfo->img.structure = FRAME;
p_dpb->active_fs->frame.poc = pInfo->img.framepoc;
// call store_picture_in_dpb
h264_dpb_store_previous_picture_in_dpb(pInfo, 1, 0);
h264_hdr_post_poc(pInfo, 1, temp, 0);
temp_frame_num++;
}
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_unmark_for_reference ()
//
// Mark FrameStore unused for reference. Removes it from the short term reference list
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_unmark_for_reference(h264_DecodedPictureBuffer *p_dpb, int32_t fs_idc)
{
h264_dpb_set_active_fs(p_dpb, fs_idc);
if (viddec_h264_get_is_used(p_dpb->active_fs)&0x1) p_dpb->active_fs->top_field.used_for_reference = 0;
if (viddec_h264_get_is_used(p_dpb->active_fs)&0x2) p_dpb->active_fs->bottom_field.used_for_reference = 0;
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3) p_dpb->active_fs->frame.used_for_reference = 0;
p_dpb->active_fs->frame.used_for_reference = 0;
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_unmark_for_long_term_reference ()
//
// mark FrameStore unused for reference and reset long term flags
// This function does not remove it form the long term list
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_unmark_for_long_term_reference(h264_DecodedPictureBuffer *p_dpb, int32_t fs_idc)
{
h264_dpb_set_active_fs(p_dpb, fs_idc);
if (viddec_h264_get_is_used(p_dpb->active_fs)&0x1)
{
p_dpb->active_fs->top_field.used_for_reference = 0;
p_dpb->active_fs->top_field.is_long_term = 0;
}
if (viddec_h264_get_is_used(p_dpb->active_fs)&0x2)
{
p_dpb->active_fs->bottom_field.used_for_reference = 0;
p_dpb->active_fs->bottom_field.is_long_term = 0;
}
if (viddec_h264_get_is_used(p_dpb->active_fs) == 3)
{
p_dpb->active_fs->frame.used_for_reference = 0;
p_dpb->active_fs->frame.is_long_term = 0;
}
p_dpb->active_fs->frame.used_for_reference = 0;
viddec_h264_set_is_frame_long_term(p_dpb->active_fs, 0);
return;
}
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------ */
//////////////////////////////////////////////////////////////////////////////
// h264_dpb_mark_dangling_field
//
// Tells HW previous field was dangling
// Marks it in SW as so
// Takes appropriate actions. - sys_data needs thought through...
//////////////////////////////////////////////////////////////////////////////
void h264_dpb_mark_dangling_field(h264_DecodedPictureBuffer *p_dpb, int32_t fs_idc)
{
h264_dpb_set_active_fs(p_dpb, fs_idc);
//PRINTF(MFD_NONE, " fs_idc = %d DANGLING_TYPE = %d \n", fs_idc, reason);
/*
Make the check that it has not already been marked
This covers the situation of a dangling field followed by a
frame which is direct output (i.e. never entered into the dpb).
In this case we could attempt to mark the prev unpaired field