blob: 2a91572c858b90f006f70484a0bf57b35ea8be78 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
/* System include files */
#include "stdio.h"
#include "string.h"
/* User include files */
#include "irc_datatypes.h"
#include "irc_cntrl_param.h"
#include "irc_mem_req_and_acq.h"
#include "irc_picture_type.h"
#include "irc_trace_support.h"
#define MAX_INTER_FRM_INT 10
/******************************Pic_details ************************************/
typedef struct
{
/* The id sent by the codec */
WORD32 i4_pic_id;
/* The pics come in, in this order */
WORD32 i4_pic_disp_order_no;
/* I,P,B */
picture_type_e e_pic_type;
} pic_details_t;
/**************************Pic_handling structure *****************************/
typedef struct pic_handling_t
{
/***************************************************************************
* Inputs from the codec
**************************************************************************/
/* Number of frames after which an I frame will repeat in display order */
WORD32 i4_intra_frm_int;
/* (num_b_pics_in_subgop + 1) */
WORD32 i4_inter_frm_int;
/* After these many buffered frames, the pics are encoded */
WORD32 i4_max_inter_frm_int;
/* OPEN or CLOSED */
WORD32 i4_is_gop_closed;
/* The pic stack */
/* Stack used to store the input pics in encode order */
pic_details_t as_pic_stack[MAX_INTER_FRM_INT + 2];
/***************************************************************************
* Counters
**************************************************************************/
/* Decides whether a B or ref pic */
WORD32 i4_buf_pic_no;
/* Current pic's number in displayed, and gets reset after an I-frm */
WORD32 i4_pic_disp_order_no;
/* Number of P frms that have come, in the current gop, so far */
WORD32 i4_p_count_in_gop;
/* Number of B frms that have come, in the current gop, so far */
WORD32 i4_b_count_in_gop;
/* Number of B frms that have come, in the current subgop, so far */
WORD32 i4_b_count_in_subgop;
/***************************************************************************
* Indices to the pic stack (Since we store the pics in the encode order,
* these vars are modified to meet that)
**************************************************************************/
/* B_PIC index */
WORD32 i4_b_pic_idx;
/* I,P PIC index */
WORD32 i4_ref_pic_idx;
/***************************************************************************
* Variables operating on the input pics
**************************************************************************/
/* Flag denoting whether it's the first gop or not */
WORD32 i4_is_first_gop;
/* Number of B_PICs in an incomplete subgop */
WORD32 i4_b_in_incomp_subgop;
/* In CLOSED_GOPs, even if inter_frm_int > 1, there can be 2 continous
* P_PICs at the GOP end. This takes values of 0 or 1 */
WORD32 i4_extra_p;
/***************************************************************************
* Arrays storing the number of frms in the gop
**************************************************************************/
/* In the steady state, what's the pic distribution in display order */
WORD32 i4_frms_in_gop[MAX_PIC_TYPE];
/*
* In case of a change in inter frm int call, the pic distribution in
* that gop in display order
*/
WORD32 i4_frms_in_cur_gop[MAX_PIC_TYPE];
/*
* This is used to denote the number of frms remaining to be encoded in the
* current gop
*/
WORD32 i4_rem_frms_in_gop[MAX_PIC_TYPE];
/***************************************************************************
* Variables operating on the output pics
**************************************************************************/
/* Counts the frms encoded in a gop */
WORD32 i4_coded_pic_no;
/* Counts from the start of stack to the end repeatedly */
WORD32 i4_stack_count;
/***************************************************************************
* Tracking a change in the inputs from the codec
**************************************************************************/
/* A flag that is set when the codec calls for a change in inter_frm_int */
WORD32 i4_change_in_inter_frm_int;
/*
* When a change_in_inter_frm_int is called, this stores the new
* inter_frm_int
*/
WORD32 i4_new_inter_frm_int;
/*
* When a change_in_inter_frm_int is called in the middle of a gop,this
* stores the B_PICs in the incomplete subgop of the mixed gop
*/
WORD32 i4_b_in_incomp_subgop_mix_gop;
/*
* For a CLOSED GOP, when a change_in_inter_frm_int is called in the middle
* of a gop,this is a flag denoting if there is an extra P_PIC in the mixed
* gop
*/
WORD32 i4_extra_p_mix_gop;
/* A flag that is set when the codec calls for a change in intra_frm_int */
WORD32 i4_change_in_intra_frm_int;
/*
* When a change_in_intra_frm_int is called, this stores the new
* intra_frm_int
*/
WORD32 i4_new_intra_frm_int;
/***************************************************************************
* Previous pic_stack_indices & details
**************************************************************************/
pic_details_t s_prev_pic_details;
WORD32 i4_prev_b_pic_idx;
WORD32 i4_last_frm_in_gop;
WORD32 i4_first_gop_encoded;
/* NITT TBR */
picture_type_e e_previous_pic_type;
WORD32 i4_force_I_frame;
WORD32 i4_forced_I_frame_cur_frame;
WORD32 i4_sum_remaining_frm_in_gop;
WORD32 i4_mod_temp_ref_cnt;
WORD32 i4_frames_in_fif_gop;
WORD32 i4_prev_intra_frame_interval;
} pic_handling_t;
static void irc_update_pic_distbn(pic_handling_t *ps_pic_handling,
WORD32 i4_intra_frm_int,
WORD32 i4_inter_frm_int,
WORD32 i4_gop_boundary);
static void find_pic_distbn_in_gop(WORD32 i4_frms_in_gop[MAX_PIC_TYPE],
WORD32 i4_intra_frm_int,
WORD32 i4_inter_frm_int,
WORD32 i4_is_gop_closed,
WORD32 *pi4_b_in_incomp_subgop,
WORD32 *pi4_extra_p);
WORD32 irc_pic_handling_num_fill_use_free_memtab(pic_handling_t **pps_pic_handling,
itt_memtab_t *ps_memtab,
ITT_FUNC_TYPE_E e_func_type)
{
WORD32 i4_mem_tab_idx = 0;
pic_handling_t s_pic_handling_temp;
/*
* Hack for al alloc, during which we dont have any state memory.
* Dereferencing can cause issues
*/
if(e_func_type == GET_NUM_MEMTAB || e_func_type == FILL_MEMTAB)
{
(*pps_pic_handling) = &s_pic_handling_temp;
}
/*for src rate control state structure*/
if(e_func_type != GET_NUM_MEMTAB)
{
fill_memtab(&ps_memtab[i4_mem_tab_idx], sizeof(pic_handling_t),
ALIGN_128_BYTE, PERSISTENT, DDR);
use_or_fill_base(&ps_memtab[0], (void**)pps_pic_handling, e_func_type);
}
i4_mem_tab_idx++;
return (i4_mem_tab_idx);
}
/******************************************************************************
Description : initializes the pic handling state struct
*****************************************************************************/
void irc_init_pic_handling(pic_handling_t *ps_pic_handling,
WORD32 i4_intra_frm_int,
WORD32 i4_inter_frm_int,
WORD32 i4_max_inter_frm_int,
WORD32 i4_is_gop_closed)
{
/* Declarations */
WORD32 i;
/* Checks */
/* Codec Parameters */
ps_pic_handling->i4_intra_frm_int = i4_intra_frm_int;
ps_pic_handling->i4_inter_frm_int = i4_inter_frm_int;
ps_pic_handling->i4_max_inter_frm_int = i4_max_inter_frm_int;
ps_pic_handling->i4_is_gop_closed = i4_is_gop_closed;
/* Pic_stack */
memset(ps_pic_handling->as_pic_stack, 0,
sizeof(ps_pic_handling->as_pic_stack));
memset(&ps_pic_handling->s_prev_pic_details, 0,
sizeof(ps_pic_handling->s_prev_pic_details));
/* Counters */
ps_pic_handling->i4_buf_pic_no = 0;
ps_pic_handling->i4_pic_disp_order_no = 0;
/* Indices to the pic_stack */
ps_pic_handling->i4_ref_pic_idx = 0;
/*
* B frame index should be ref_frame_num,
* which is 2 in out case
*/
ps_pic_handling->i4_b_pic_idx = 2;
ps_pic_handling->i4_prev_b_pic_idx = 2;
/* Variables working on the input frames */
ps_pic_handling->i4_is_first_gop = 1;
ps_pic_handling->i4_p_count_in_gop = 0;
ps_pic_handling->i4_b_count_in_gop = 0;
ps_pic_handling->i4_b_count_in_subgop = 0;
/* Variables working on the output frames */
ps_pic_handling->i4_coded_pic_no = -1;
ps_pic_handling->i4_stack_count = -1;
/* Tracks the changes in the Codec Parameters */
ps_pic_handling->i4_change_in_inter_frm_int = 0;
ps_pic_handling->i4_new_inter_frm_int = i4_max_inter_frm_int;
/* Tracks the changes in the Codec Parameters */
ps_pic_handling->i4_change_in_intra_frm_int = 0;
ps_pic_handling->i4_new_intra_frm_int = i4_intra_frm_int;
/* Variables on which the bit allocation is dependent */
/* Get the pic distribution in the gop */
find_pic_distbn_in_gop(ps_pic_handling->i4_frms_in_gop, i4_intra_frm_int,
i4_inter_frm_int, i4_is_gop_closed,
&ps_pic_handling->i4_b_in_incomp_subgop,
&ps_pic_handling->i4_extra_p);
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_frms_in_cur_gop[i] =
ps_pic_handling->i4_frms_in_gop[i];
ps_pic_handling->i4_rem_frms_in_gop[i] =
ps_pic_handling->i4_frms_in_gop[i];
}
ps_pic_handling->e_previous_pic_type = I_PIC;
ps_pic_handling->i4_prev_intra_frame_interval = i4_intra_frm_int;
ps_pic_handling->i4_force_I_frame = 0;
ps_pic_handling->i4_forced_I_frame_cur_frame = 0;
ps_pic_handling->i4_sum_remaining_frm_in_gop = 0;
ps_pic_handling->i4_mod_temp_ref_cnt = 0;
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop =
ps_pic_handling->i4_b_in_incomp_subgop;
ps_pic_handling->i4_extra_p_mix_gop = ps_pic_handling->i4_extra_p;
ps_pic_handling->i4_last_frm_in_gop = 0;
ps_pic_handling->i4_first_gop_encoded = 0;
ps_pic_handling->i4_frames_in_fif_gop = 0;
}
/*******************************************************************************
* @brief registers the new intra frame interval value
******************************************************************************/
void irc_pic_handling_register_new_int_frm_interval(pic_handling_t *ps_pic_handling,
WORD32 i4_intra_frm_int)
{
ps_pic_handling->i4_change_in_intra_frm_int = 1;
ps_pic_handling->i4_new_intra_frm_int = i4_intra_frm_int;
}
void irc_pic_handling_register_new_inter_frm_interval(pic_handling_t *ps_pic_handling,
WORD32 i4_inter_frm_int)
{
/* Update the state structure with the latest values */
ps_pic_handling->i4_change_in_inter_frm_int = 1;
ps_pic_handling->i4_new_inter_frm_int = i4_inter_frm_int;
}
static void start_new_gop(pic_handling_t *ps_pic_handling)
{
WORD32 i;
WORD32 i4_sum_remaining_frm_in_gop = 0;
/* Now, the end of gop updates */
ps_pic_handling->i4_pic_disp_order_no = 0;
ps_pic_handling->i4_buf_pic_no = 0;
ps_pic_handling->i4_is_first_gop = 0;
ps_pic_handling->i4_extra_p_mix_gop = ps_pic_handling->i4_extra_p;
if(ps_pic_handling->i4_is_gop_closed)
{
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop =
ps_pic_handling->i4_b_in_incomp_subgop;
}
/*
* Store the number of frames in the gop that is encoded till now
* just before Force I frame call is made
*/
ps_pic_handling->i4_frames_in_fif_gop = ps_pic_handling->i4_b_count_in_gop
+ ps_pic_handling->i4_p_count_in_gop + 1;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
i4_sum_remaining_frm_in_gop += ps_pic_handling->i4_rem_frms_in_gop[i];
}
ps_pic_handling->i4_sum_remaining_frm_in_gop = i4_sum_remaining_frm_in_gop;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_frms_in_cur_gop[i] =
ps_pic_handling->i4_frms_in_gop[i];
ps_pic_handling->i4_rem_frms_in_gop[i] =
ps_pic_handling->i4_frms_in_cur_gop[i];
}
}
/*******************************************************************************
* @brief Fills the pic_stack with the incoming pics in encode order
******************************************************************************/
void irc_add_pic_to_stack(pic_handling_t *ps_pic_handling, WORD32 i4_enc_pic_id)
{
/* Declarations */
WORD32 i4_inter_frm_int, i4_max_inter_frm_int,
i4_intra_frm_int, i4_new_inter_frm_int;
WORD32 i4_is_gop_closed;
WORD32 i4_buf_pic_no, i4_pic_disp_order_no;
WORD32 i4_b_pic_idx, i4_ref_pic_idx;
WORD32 i4_is_first_gop, i4_b_in_incomp_subgop, i4_p_count_in_gop,
i4_b_count_in_gop, i4_b_count_in_subgop;
WORD32 i, i4_p_frms_in_prd, i4_b_frms_in_prd,
i4_num_b_in_subgop, i4_extra_p;
WORD32 i4_condn_for_change_in_inter_frm_int;
picture_type_e e_previous_pic_type, e_cur_pic_type;
WORD32 i4_force_I_frame;
/*
* Initialize the local vars with the state struct values needed by the
* change calls
*/
i4_intra_frm_int = ps_pic_handling->i4_intra_frm_int;
i4_inter_frm_int = ps_pic_handling->i4_inter_frm_int;
i4_max_inter_frm_int = ps_pic_handling->i4_max_inter_frm_int;
i4_is_gop_closed = ps_pic_handling->i4_is_gop_closed;
i4_buf_pic_no = ps_pic_handling->i4_buf_pic_no;
i4_pic_disp_order_no = ps_pic_handling->i4_pic_disp_order_no;
i4_b_count_in_gop = ps_pic_handling->i4_b_count_in_gop;
i4_b_frms_in_prd = ps_pic_handling->i4_frms_in_cur_gop[B_PIC];
i4_is_first_gop = ps_pic_handling->i4_is_first_gop;
i4_new_inter_frm_int = ps_pic_handling->i4_new_inter_frm_int;
e_previous_pic_type = ps_pic_handling->e_previous_pic_type;
i4_force_I_frame = ps_pic_handling->i4_force_I_frame;
/* Force I frame :
* Two different cases
* 1)OPEN_GOP: New GOP is started after number of B pictures in the last
* sub gop of a gop to mimic the GOP structure.
* 2)Closed GOP:Wait till P frame at input and The frame after a P frame
* a new GOP is started to mimic the GOP structure.
*/
if(i4_force_I_frame)
{
WORD32 i4_temp_is_gop_closed;
WORD32 i4_codn = 0;
/* A special case of Open GOP where the it behaves like Closed GOP*/
if((i4_intra_frm_int % i4_inter_frm_int) == 1)
{
i4_temp_is_gop_closed = 1;
}
else
{
i4_temp_is_gop_closed = i4_is_gop_closed;
}
/* Get the current picture type to aid decision to force an I frame*/
if((i4_buf_pic_no % i4_inter_frm_int)
&& !(i4_is_gop_closed&& (i4_b_count_in_gop == i4_b_frms_in_prd)))
{
e_cur_pic_type = B_PIC;
}
else
{
if(i4_pic_disp_order_no == 0)
{
e_cur_pic_type = I_PIC;
}
else
{
e_cur_pic_type = P_PIC;
}
}
if((i4_intra_frm_int % i4_inter_frm_int) == 0)
{
i4_codn = (e_cur_pic_type == P_PIC);
}
else
{
i4_codn = (ps_pic_handling->i4_b_count_in_subgop
== ps_pic_handling->i4_b_in_incomp_subgop);
}
if(e_cur_pic_type == I_PIC)
{
/*
* Don't do anything. Resetting the force I frame flag
* since the current picture type is already a I frame
*/
i4_force_I_frame = 0;
}
else if(i4_inter_frm_int == 1)
{
/*IPP case , Force I frame immediately*/
start_new_gop(ps_pic_handling);
}
else if((!i4_temp_is_gop_closed) && i4_codn)
{
start_new_gop(ps_pic_handling);
if(ps_pic_handling->i4_b_count_in_subgop)
{
ps_pic_handling->i4_b_pic_idx += 1;
ps_pic_handling->i4_b_pic_idx %= (i4_max_inter_frm_int + 1);
}
}
else if(i4_temp_is_gop_closed && (e_previous_pic_type == P_PIC)
&& (e_cur_pic_type != P_PIC))
{
start_new_gop(ps_pic_handling);
ps_pic_handling->i4_b_pic_idx++;
ps_pic_handling->i4_b_pic_idx %= (i4_max_inter_frm_int + 1);
}
i4_is_first_gop = ps_pic_handling->i4_is_first_gop;
}
/***********************CHANGE_INTRA_FRM_INTERVAL**************************
*
* Call the irc_update_pic_distbn if
* 1)Change in intra frm interval flag is set
* 2)It's the first B_PIC of a gop
*/
if((ps_pic_handling->i4_change_in_intra_frm_int == 1)
&& ((i4_pic_disp_order_no == 1)))
{
irc_update_pic_distbn(ps_pic_handling,
ps_pic_handling->i4_new_intra_frm_int,
ps_pic_handling->i4_inter_frm_int, 1);
ps_pic_handling->i4_change_in_intra_frm_int = 0;
if(ps_pic_handling->i4_new_intra_frm_int == 1)
{
ps_pic_handling->i4_pic_disp_order_no = 0;
}
}
/*********************CHANGE_INTER_FRM_INTERVAL****************************/
/* Call irc_update_pic_distbn if
* 1)Change in inter frm interval flag is set
* 2)It's the first B_PIC after gop/subgop start, and
* 3)The new inter-frm-interval won't cross the intra_frm_interval
*/
if((ps_pic_handling->i4_change_in_inter_frm_int == 1)
&& ((i4_buf_pic_no % i4_inter_frm_int == 1)|| (i4_pic_disp_order_no == 1) || (i4_inter_frm_int == 1)))
{
/*
* Condition which checks if the new inter_frm_int will cross the
* intra_frm_int
*/
i4_condn_for_change_in_inter_frm_int = ((i4_pic_disp_order_no
+ i4_new_inter_frm_int - 1) < i4_intra_frm_int);
if(i4_condn_for_change_in_inter_frm_int)
{
/*
* If there is a change in inter frame interval. We should set the b
* frame IDX to the (num ref frame - num ref frame in buf)+ i4_ref_pic_idx
* Since our case we have a structure of I B P or I B...B P only
* we have three cases
* 1) current incoming frame is I. Then we have to leave space for
* current I and next P hence write b idx as to ref idx + 2
* 2) Current incoming frame is B. In that case, we have I in buffer.
* Only one P needs space hence write b idx as ref idx +1
* 3) Current incoming frame is P. In that case we are at the end of
* gop [sub gop?] and we have to leave space for next gops I and P.
* Thus b idx = ref idx + 2
*
* In case of an closed Gop. The last frame has to be forced to be a P.
* Hence we may have problems in that case.
*
* Also this has the implicit assumption of only 2 ref frames
*/
WORD32 i4_is_curr_frm_b = (i4_buf_pic_no % i4_new_inter_frm_int)&&
!(i4_is_gop_closed && (i4_b_count_in_gop == i4_b_frms_in_prd));
/*If the inter_frm_int = 1, then the b_pic_idx needs to be modified */
if(i4_inter_frm_int == 1)
{
ps_pic_handling->i4_b_pic_idx = ((i4_is_curr_frm_b ? 1 : 2)
+ ps_pic_handling->i4_ref_pic_idx)
% (i4_max_inter_frm_int + 1);
}
/*
* Depending on the gop/subgop boundary, call the change_inter_frm_int
*
* TO DO: make a single call, change the name of the fxn to
* update_state,
* where state = frms_in_gop + b_incomp_subgop + extra_p
*/
/* GOP boundary */
if(i4_pic_disp_order_no == 1)
{
irc_update_pic_distbn(ps_pic_handling,
ps_pic_handling->i4_intra_frm_int,
ps_pic_handling->i4_new_inter_frm_int, 1);
}
/* Subgop boundary */
else
{
irc_update_pic_distbn(ps_pic_handling,
ps_pic_handling->i4_intra_frm_int,
ps_pic_handling->i4_new_inter_frm_int, 0);
}
ps_pic_handling->i4_change_in_inter_frm_int = 0;
ps_pic_handling->i4_new_inter_frm_int =
ps_pic_handling->i4_inter_frm_int;
}
}
/* Initialize the local vars with the state struct values */
i4_buf_pic_no = ps_pic_handling->i4_buf_pic_no;
i4_pic_disp_order_no = ps_pic_handling->i4_pic_disp_order_no;
i4_b_pic_idx = ps_pic_handling->i4_b_pic_idx;
i4_ref_pic_idx = ps_pic_handling->i4_ref_pic_idx;
i4_b_in_incomp_subgop = ps_pic_handling->i4_b_in_incomp_subgop_mix_gop;
i4_p_count_in_gop = ps_pic_handling->i4_p_count_in_gop;
i4_b_count_in_gop = ps_pic_handling->i4_b_count_in_gop;
i4_b_count_in_subgop = ps_pic_handling->i4_b_count_in_subgop;
i4_p_frms_in_prd = ps_pic_handling->i4_frms_in_cur_gop[P_PIC];
i4_b_frms_in_prd = ps_pic_handling->i4_frms_in_cur_gop[B_PIC];
i4_extra_p = ps_pic_handling->i4_extra_p_mix_gop;
i4_inter_frm_int = ps_pic_handling->i4_inter_frm_int;
i4_intra_frm_int = ps_pic_handling->i4_intra_frm_int;
/* Initializing the prev_state vars */
ps_pic_handling->i4_prev_b_pic_idx = ps_pic_handling->i4_b_pic_idx;
i4_num_b_in_subgop = (i4_inter_frm_int - 1);
/*********************** Fill the stack ***********************************/
/* The next part of the code is organized as
*
* if(B_PIC conditions satisfied)
* {
* Fill the pic_stack using the b_pic_index
* Update the b_pic_index and the other b_pic related vars for the
* next B_PIC
* }
* else
* {
* if(I_PIC conditions are satisfied)
* {
* Fill the pic_stack using the ref_pic_index
* Update the ref_pic_index and the other ref_pic related vars for the next
* I_PIC/P_PIC
* }
* else
* {
* Fill the pic_stack using the ref_pic_index
* Update the ref_pic_index and the other ref_pic related vars for the next
* I_PIC/P_PIC
* }
* }
*/
/*
* Condition for a B_PIC -
* 1) Other than the first I_PIC and the periodically appearing P_PICs, after
* every inter_frm_int, rest all pics are B_PICs
* 2) In case of CLOSED_GOP, the last frame of the gop has to be a P_PIC
*/
if((i4_buf_pic_no % i4_inter_frm_int)&& !(i4_is_gop_closed
&& (i4_b_count_in_gop == i4_b_frms_in_prd))) /**** B_PIC ****/
{
/* Fill the pic_stack */
ps_pic_handling->as_pic_stack[i4_b_pic_idx].i4_pic_id = i4_enc_pic_id;
ps_pic_handling->as_pic_stack[i4_b_pic_idx].e_pic_type = B_PIC;
ps_pic_handling->as_pic_stack[i4_b_pic_idx].i4_pic_disp_order_no =
i4_pic_disp_order_no;
/* Store Pic type*/
e_previous_pic_type = B_PIC;
/* Update the prev_pic_details */
memcpy(&ps_pic_handling->s_prev_pic_details,
&ps_pic_handling->as_pic_stack[i4_b_pic_idx],
sizeof(pic_details_t));
i4_b_count_in_gop++;
i4_b_count_in_subgop++;
/* Update the i4_b_pic_idx */
if(!i4_is_gop_closed)
{
/* If this B_PIC features in one of the complete subgops */
if((i4_b_count_in_subgop < i4_num_b_in_subgop)
&& !(i4_b_count_in_gop == i4_b_frms_in_prd))
{
i4_b_pic_idx++;
}
else /* Else if this B_PIC is the last one in a subgop or gop */
{
/*
* If this is the last B_PIC of a GOP, depending on the number
* of incomp B_pics in the subgop, there can be either only I
* or I,P pics between this and the next B_PIC
*/
if(i4_b_count_in_gop == i4_b_frms_in_prd)
{
i4_b_pic_idx += (2 + (!i4_b_in_incomp_subgop)); /*Prev*/
i4_b_count_in_gop = 0;
}
/*
* For the last B_PIC of a subgop, there's always a P b/w
* this & the next B_PIC
*/
else
{
i4_b_pic_idx += 2;
}
i4_b_count_in_subgop = 0;
}
}
else
{
/* For the last B_PIC of a gop
* Normally,there will be 3 pics (P,I,P) between this and the next
* B_PIC for a CLOSED gop, except when
* 1)Number of P_pics in the gop = 1
* 2)There is an extra P at the end of the gop
*/
if(i4_b_count_in_gop == i4_b_frms_in_prd)
{
i4_b_pic_idx += (3 + ((i4_b_in_incomp_subgop == 0)
&& (i4_p_frms_in_prd> 1)
&& (i4_pic_disp_order_no
!= (i4_p_frms_in_prd+ i4_b_frms_in_prd- 1))));
i4_b_count_in_subgop = 0;
}
/* For a B_PIC which is not the last one in a subgop */
else if(i4_b_count_in_subgop < i4_num_b_in_subgop)
{
i4_b_pic_idx++;
}
else /* For the last B_PIC of a subgop */
{
i4_b_pic_idx += 2;
i4_b_count_in_subgop = 0;
}
}
i4_b_pic_idx %= (i4_max_inter_frm_int + 1);
}
/*********** I or P pic *********/
else
{
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_id = i4_enc_pic_id;
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_disp_order_no =
i4_pic_disp_order_no;
/* Store Pic type*/
e_previous_pic_type = I_PIC;
/**** I_PIC ****/
if(i4_pic_disp_order_no == 0)
{
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].e_pic_type = I_PIC;
/* Update the prev_pic_details */
memcpy(&ps_pic_handling->s_prev_pic_details,
&ps_pic_handling->as_pic_stack[i4_ref_pic_idx],
sizeof(pic_details_t));
/*
* In case of an I-frame depending on OPEN or CLOSED gop,
* the ref_pic_idx changes
*/
if((!i4_is_gop_closed) && (i4_is_first_gop == 0))
{
if((i4_p_frms_in_prd <= 1) && (i4_b_in_incomp_subgop == 0))
{
i4_ref_pic_idx++;
}
/*
* From the 2nd gop onwards, the I and first P frame are
* separated by the num_b_in_incomp_subgop
*/
else
{
i4_ref_pic_idx += (i4_b_in_incomp_subgop + 1);
}
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop =
ps_pic_handling->i4_b_in_incomp_subgop;
}
else
{
i4_ref_pic_idx++;
}
i4_b_count_in_gop = 0;
i4_p_count_in_gop = 0;
i4_b_count_in_subgop = 0;
}
/**** P_PIC ****/
else
{
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].e_pic_type = P_PIC;
/* Store Pic type*/
e_previous_pic_type = P_PIC;
/* Update the prev_pic_details */
memcpy(&ps_pic_handling->s_prev_pic_details,
&ps_pic_handling->as_pic_stack[i4_ref_pic_idx],
sizeof(pic_details_t));
i4_p_count_in_gop++;
ps_pic_handling->i4_prev_intra_frame_interval = i4_intra_frm_int;
/*
* In case of an P-frame depending on OPEN or CLOSED gop, the
* ref_pic_idx changes
*/
if(i4_is_gop_closed && (i4_p_count_in_gop == i4_p_frms_in_prd))
{
/*
* For the last P_PIC in a gop, if extra_p or incomp_b are
* present, the number of such pics between this and the next
* ref_pic is (i4_b_in_incomp_subgop + 1)
*/
if((i4_p_count_in_gop > 1)
&& (i4_b_in_incomp_subgop || i4_extra_p))
{
i4_ref_pic_idx += (i4_b_in_incomp_subgop + 1);
}
else
{
i4_ref_pic_idx += i4_inter_frm_int;
}
}
else
{
i4_ref_pic_idx += i4_inter_frm_int;
}
}
i4_ref_pic_idx %= (i4_max_inter_frm_int + 1);
}
/* Update those variables working on the input frames */
i4_pic_disp_order_no++;
i4_buf_pic_no++;
#if 0
/* For any gop */
/* BUG FIX
* This piece of code resets the gop upon I frame(?)
* This introduces a problem of GOP getting reset not at I frames as it should be
* The reason AFAIK is that
* 1) This code uses i4_pic_disp_order_no to reset GOP. I assume it computes
* if are at GOP boundary and does it, but not sure
* 2) The frames rmainign in GOP is done in post enc as it should be.
*
* Also ps_pic_handling->i4_pic_disp_order_no is incremented when a pic is added
* to stack becuase the additon is in disp order while poping is in encode order
*
* SUppose there is a deay od 1 frame between queue and encode.
* then he timing will be. Assume a GOP of IPPIPP
*
* Input buff Input to qu Output buf/encode buff remaining pic in gop
* 1 I I NA rest to 1 2
* 2 P P I 0 2
* 3 P P P 0 1
* 4 I I P reset to 1 2
* 5 P P I 1 1
* 6 P P P 1 0
* 7 NA NA P
*
* Hence our gop gets reset at I(1) and I(4) in the RC.thus the reaming pic in gop
* count will be as shown. We can clearly see that the GOP gets reset at I(4) .Hence
* for the correpondinng QP for output buf p(4) will be that of an I frame.
*
* By hiding this I hope to fix this problem. But Iam not sure exaclty.
* This needs to be investigated further
*
* By hiding this most likely we are in effect disabling the dynanic
* update of gop params.
*/
if(ps_pic_handling->i4_pic_disp_order_no
== (i4_max_inter_frm_int - 1- ((!i4_is_gop_closed)
* ps_pic_handling->i4_b_in_incomp_subgop_mix_gop)))
{
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_rem_frms_in_gop[i] =
ps_pic_handling->i4_frms_in_cur_gop[i];
}
if((!i4_is_gop_closed) && (i4_is_first_gop)
&& (ps_pic_handling->i4_rem_frms_in_gop[B_PIC]
> ps_pic_handling->i4_b_in_incomp_subgop_mix_gop))
{
ps_pic_handling->i4_rem_frms_in_gop[B_PIC] =
ps_pic_handling->i4_frms_in_cur_gop[B_PIC]
- ps_pic_handling->i4_b_in_incomp_subgop_mix_gop;
}
}
#endif
/* End of GOP updates */
if(i4_pic_disp_order_no == (i4_p_frms_in_prd + i4_b_frms_in_prd + 1))
{
/* Now, the end of gop updates */
i4_pic_disp_order_no = 0;
i4_buf_pic_no = 0;
i4_is_first_gop = 0;
ps_pic_handling->i4_extra_p_mix_gop = ps_pic_handling->i4_extra_p;
if(i4_is_gop_closed)
{
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop =
ps_pic_handling->i4_b_in_incomp_subgop;
}
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_frms_in_cur_gop[i] =
ps_pic_handling->i4_frms_in_gop[i];
}
}
/* Updating the vars which work on the encoded pics */
/* For the first gop */
if ((ps_pic_handling->i4_is_first_gop)
&& (ps_pic_handling->i4_pic_disp_order_no == 0))
{
ps_pic_handling->i4_coded_pic_no = 0;
ps_pic_handling->i4_stack_count = 0;
}
/* Update the state struct with the modifiable local vars */
ps_pic_handling->i4_buf_pic_no = i4_buf_pic_no;
ps_pic_handling->i4_pic_disp_order_no = i4_pic_disp_order_no;
ps_pic_handling->i4_b_pic_idx = i4_b_pic_idx;
ps_pic_handling->i4_ref_pic_idx = i4_ref_pic_idx;
ps_pic_handling->i4_is_first_gop = i4_is_first_gop;
ps_pic_handling->i4_p_count_in_gop = i4_p_count_in_gop;
ps_pic_handling->i4_b_count_in_gop = i4_b_count_in_gop;
ps_pic_handling->i4_b_count_in_subgop = i4_b_count_in_subgop;
ps_pic_handling->e_previous_pic_type = e_previous_pic_type;
ps_pic_handling->i4_force_I_frame = i4_force_I_frame;
}
/*******************************************************************************
* @brief Returns the picture type, ip and display order number for the frame to
* be encoded
******************************************************************************/
void irc_get_pic_from_stack(pic_handling_t *ps_pic_handling,
WORD32 *pi4_pic_id,
WORD32 *pi4_pic_disp_order_no,
picture_type_e *pe_pic_type)
{
pic_details_t s_pic_details;
pic_details_t *ps_pic_details = &s_pic_details;
if(ps_pic_handling->i4_stack_count < 0)
{
ps_pic_details->e_pic_type = BUF_PIC;
ps_pic_details->i4_pic_disp_order_no = -1;
ps_pic_details->i4_pic_id = -1;
}
else
{
memcpy(ps_pic_details,
&ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count],
sizeof(pic_details_t));
/* Force I frame updations */
if((ps_pic_handling->i4_force_I_frame == 1)
&& (ps_pic_details->e_pic_type == I_PIC))
{
/* Flag to signal change in remaining bits*/
ps_pic_handling->i4_forced_I_frame_cur_frame = 1;
ps_pic_handling->i4_force_I_frame = 0;
/*
* Indicates count for no. of Pictures whose temporal reference
* has to be modified
* in the new GOP
*/
ps_pic_handling->i4_mod_temp_ref_cnt =
ps_pic_handling->i4_b_in_incomp_subgop + 1;
ps_pic_handling->i4_first_gop_encoded = 1;
}
/*
* In MPEG2, the temporal reference of the first displayed frame in a
* gop is 0.In case of an OPEN_GOP, the B_PICs of the last subgop in a
* gop, maybe coded as a part of the next gop. Hence, in such conditions
* the pic_disp_order needs to be modified so that it gives an
* indication of the temporal reference
*/
if((!ps_pic_handling->i4_is_gop_closed)
&& (ps_pic_handling->i4_first_gop_encoded))
{
if(!ps_pic_handling->i4_mod_temp_ref_cnt)
{
ps_pic_details->i4_pic_disp_order_no =
(ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count].i4_pic_disp_order_no
+ ps_pic_handling->i4_b_in_incomp_subgop)
% (ps_pic_handling->i4_prev_intra_frame_interval);
}
else
{
/*
* due to force I frame First frame will have only
* ps_pic_handling->i4_frames_in_fif_gop number of frames
*/
ps_pic_details->i4_pic_disp_order_no =
(ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count].i4_pic_disp_order_no
+ ps_pic_handling->i4_b_in_incomp_subgop)
% (ps_pic_handling->i4_frames_in_fif_gop);
ps_pic_handling->i4_mod_temp_ref_cnt--;
}
}
}
/* Giving this to the Codec */
*pi4_pic_id = s_pic_details.i4_pic_id;
*pi4_pic_disp_order_no = s_pic_details.i4_pic_disp_order_no;
*pe_pic_type = s_pic_details.e_pic_type;
}
/*******************************************************************************
* @brief Updates the picture handling state whenever there is changes in input
* parameter
*
******************************************************************************/
static void irc_update_pic_distbn(pic_handling_t *ps_pic_handling,
WORD32 i4_intra_frm_int,
WORD32 i4_inter_frm_int,
WORD32 i4_gop_boundary)
{
/* Declarations */
WORD32 i4_is_gop_closed;
WORD32 i, i4_prev_inter_frm_int, i4_max_inter_frm_int, i4_pic_disp_order_no;
WORD32 i4_b_in_incomp_subgop, i4_extra_p,
i4_b_in_incomp_subgop_mix_gop,i4_extra_p_mix_gop;
WORD32 i4_pb_frms_till_prev_p;
WORD32 ai4_diff_in_frms[MAX_PIC_TYPE];
/* Initialize the local vars from the state struct */
i4_is_gop_closed = ps_pic_handling->i4_is_gop_closed;
i4_prev_inter_frm_int = ps_pic_handling->i4_inter_frm_int;
i4_max_inter_frm_int = ps_pic_handling->i4_max_inter_frm_int;
i4_b_in_incomp_subgop = ps_pic_handling->i4_b_in_incomp_subgop;
i4_extra_p = ps_pic_handling->i4_extra_p;
i4_b_in_incomp_subgop_mix_gop =
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop;
i4_extra_p_mix_gop = ps_pic_handling->i4_extra_p_mix_gop;
i4_pic_disp_order_no = ps_pic_handling->i4_pic_disp_order_no;
i4_pb_frms_till_prev_p = (ps_pic_handling->i4_p_count_in_gop
* i4_prev_inter_frm_int);
/* Check for the validity of the intra_frm_int */
if(i4_intra_frm_int <= 0)
{
i4_intra_frm_int = ps_pic_handling->i4_intra_frm_int;
}
/* Check for the validity of the inter_frm_int */
if((i4_inter_frm_int > i4_max_inter_frm_int) || (i4_inter_frm_int < 0))
{
i4_inter_frm_int = ps_pic_handling->i4_inter_frm_int;
}
/* Keep a copy of the older frms_in_gop */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ai4_diff_in_frms[i] = ps_pic_handling->i4_frms_in_cur_gop[i];
}
/* Update all the variables which are calculated from the inter_frm_int */
/* Get the new pic distribution in the gop */
find_pic_distbn_in_gop(ps_pic_handling->i4_frms_in_gop, i4_intra_frm_int,
i4_inter_frm_int, i4_is_gop_closed,
&i4_b_in_incomp_subgop, &i4_extra_p);
/* Find the other related variables */
if(i4_gop_boundary == 0)
{
/*
* Since, the inter frame interval has changed between a gop the
* current gop will be a mixed gop. So, we need to find the values of
* the related variables
*/
find_pic_distbn_in_gop(ps_pic_handling->i4_frms_in_cur_gop,
(i4_intra_frm_int - i4_pb_frms_till_prev_p),
i4_inter_frm_int, i4_is_gop_closed,
&i4_b_in_incomp_subgop_mix_gop,
&i4_extra_p_mix_gop);
ps_pic_handling->i4_frms_in_cur_gop[P_PIC] +=
ps_pic_handling->i4_p_count_in_gop;
ps_pic_handling->i4_frms_in_cur_gop[B_PIC] +=
ps_pic_handling->i4_b_count_in_gop;
}
else
{
/*
* Since, the inter_frm_interval has changed at a gop boundary, the
* new gop will have all the subgops with the new inter_frm_interval
*/
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_frms_in_cur_gop[i] =
ps_pic_handling->i4_frms_in_gop[i];
}
i4_b_in_incomp_subgop_mix_gop = i4_b_in_incomp_subgop;
i4_extra_p_mix_gop = i4_extra_p;
}
/* For bit-allocation the rem_frms_in_gop need to be updated */
/* Checks needed:
1) If the encoding is happening on the same gop as that of the buffering */
if(ps_pic_handling->i4_pic_disp_order_no
>= (i4_max_inter_frm_int - 1- ((!i4_is_gop_closed)
* ps_pic_handling->i4_b_in_incomp_subgop_mix_gop)))
{
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_rem_frms_in_gop[i] +=
(ps_pic_handling->i4_frms_in_cur_gop[i]
- ai4_diff_in_frms[i]);
}
}
/* Update the vars which will affect the proper filling of the pic_stack */
if(i4_pic_disp_order_no == 0) /*Check if redundant*/
{
ps_pic_handling->i4_buf_pic_no = 0;
}
else
{
ps_pic_handling->i4_buf_pic_no = 1;
}
ps_pic_handling->i4_b_count_in_subgop = 0;
/* Update the state struct with the new inter_frm_int */
ps_pic_handling->i4_inter_frm_int = i4_inter_frm_int;
ps_pic_handling->i4_intra_frm_int = i4_intra_frm_int;
ps_pic_handling->i4_b_in_incomp_subgop = i4_b_in_incomp_subgop;
ps_pic_handling->i4_extra_p = i4_extra_p;
ps_pic_handling->i4_b_in_incomp_subgop_mix_gop =
i4_b_in_incomp_subgop_mix_gop;
ps_pic_handling->i4_extra_p_mix_gop = i4_extra_p_mix_gop;
}
/* *****************************************************************************
* @brief Distributes the frames as I, P and B based on intra/inter frame interval.
* Along with it it fills the number of frames in sub-gop and extra p frame
*
******************************************************************************/
static void find_pic_distbn_in_gop(WORD32 i4_frms_in_gop[MAX_PIC_TYPE],
WORD32 i4_intra_frm_int,
WORD32 i4_inter_frm_int,
WORD32 i4_is_gop_closed,
WORD32 *pi4_b_in_incomp_subgop,
WORD32 *pi4_extra_p)
{
/*
* Find the pic distribution in the gop depending on the inter and intra
* frm intervals
*/
i4_frms_in_gop[I_PIC] = 1;
/* All I frames */
if(i4_intra_frm_int == 1)
{
i4_frms_in_gop[P_PIC] = 0;
i4_frms_in_gop[B_PIC] = 0;
*pi4_b_in_incomp_subgop = 0;
*pi4_extra_p = 0;
}
else
{
if(i4_is_gop_closed)
{
i4_frms_in_gop[P_PIC] = ((i4_intra_frm_int - 2) / i4_inter_frm_int)
+ 1;
if((((i4_intra_frm_int - 2) / i4_inter_frm_int) * i4_inter_frm_int)
== (i4_intra_frm_int - 2))
{
*pi4_extra_p = 1;
}
else
{
*pi4_extra_p = 0;
}
}
else
{
i4_frms_in_gop[P_PIC] = ((i4_intra_frm_int - 1) / i4_inter_frm_int);
*pi4_extra_p = 0;
}
i4_frms_in_gop[B_PIC] = (i4_intra_frm_int - 1 - i4_frms_in_gop[P_PIC]);
*pi4_b_in_incomp_subgop = (i4_frms_in_gop[B_PIC] - (i4_inter_frm_int - 1)
* ((i4_intra_frm_int - 1)/ i4_inter_frm_int));
}
}
WORD32 irc_pic_type_get_intra_frame_interval(pic_handling_t *ps_pic_handling)
{
return (ps_pic_handling->i4_intra_frm_int);
}
WORD32 irc_pic_type_get_inter_frame_interval(pic_handling_t *ps_pic_handling)
{
return (ps_pic_handling->i4_inter_frm_int);
}
void irc_pic_type_get_rem_frms_in_gop(pic_handling_t *ps_pic_handling,
WORD32 ai4_rem_frms_in_gop[MAX_PIC_TYPE])
{
memcpy(ai4_rem_frms_in_gop, ps_pic_handling->i4_rem_frms_in_gop,
sizeof(ps_pic_handling->i4_rem_frms_in_gop));
}
WORD32 irc_pic_type_get_frms_in_gop_force_I_frm(pic_handling_t *ps_pic_handling)
{
return (ps_pic_handling->i4_frames_in_fif_gop);
}
void irc_pic_type_get_frms_in_gop(pic_handling_t *ps_pic_handling,
WORD32 ai4_frms_in_gop[MAX_PIC_TYPE])
{
memcpy(ai4_frms_in_gop, ps_pic_handling->i4_frms_in_cur_gop,
sizeof(ps_pic_handling->i4_frms_in_cur_gop));
}
WORD32 irc_pic_type_get_disp_order_no(pic_handling_t *ps_pic_handling)
{
return (ps_pic_handling->i4_pic_disp_order_no);
}
void irc_set_force_I_frame_flag(pic_handling_t *ps_pic_handling)
{
ps_pic_handling->i4_force_I_frame = 1;
}
WORD32 irc_get_forced_I_frame_cur_frm_flag(pic_handling_t *ps_pic_handling)
{
return (ps_pic_handling->i4_forced_I_frame_cur_frame);
}
void irc_reset_forced_I_frame_cur_frm_flag(pic_handling_t *ps_pic_handling)
{
ps_pic_handling->i4_forced_I_frame_cur_frame = 0;
}
/******************************************************************************/
/* Functions that work on the encoded frames */
/******************************************************************************/
/******************************************************************************
Function Name : irc_update_pic_handling
Description : Will be called only for the frames to be encoded
*****************************************************************************/
void irc_update_pic_handling(pic_handling_t *ps_pic_handling,
picture_type_e e_pic_type)
{
WORD32 i4_max_inter_frm_int;
WORD32 i;
/* Initializing the local vars with that of the state struct */
i4_max_inter_frm_int = ps_pic_handling->i4_max_inter_frm_int;
/* Update the variables working on the output frames */
/* Update the stack count */
ps_pic_handling->i4_stack_count++;
if(ps_pic_handling->i4_stack_count == (i4_max_inter_frm_int + 1))
{
ps_pic_handling->i4_stack_count = 0;
}
/* Update the rem_frms_in_gop */
ps_pic_handling->i4_rem_frms_in_gop[e_pic_type]--;
/* Assumption : Rem_frms_in_gop needs to be taken care of, for every change in frms */
ps_pic_handling->i4_last_frm_in_gop = 0;
if((ps_pic_handling->i4_rem_frms_in_gop[I_PIC] <= 0)
&& (ps_pic_handling->i4_rem_frms_in_gop[P_PIC] <= 0)
&& (ps_pic_handling->i4_rem_frms_in_gop[B_PIC] <= 0))
{
/* Copy the cur_frms_in_gop to the rem_frm_in_gop */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_pic_handling->i4_rem_frms_in_gop[i] =
ps_pic_handling->i4_frms_in_cur_gop[i];
}
ps_pic_handling->i4_last_frm_in_gop = 1;
ps_pic_handling->i4_first_gop_encoded = 1;
}
}
WORD32 irc_is_last_frame_in_gop(pic_handling_handle ps_pic_handling)
{
return (ps_pic_handling->i4_last_frm_in_gop);
}
/******************************************************************************
Function Name : irc_skip_encoded_frame
Description : Needs to go to the current pic in the pic_stack.
If it's B_PIC don't do anything
If it's a reference picture, push all but the last B_PICs
in the current subgop one place down (i.e. just copy their
pic_details) and move the last B_PIC in that subgop to the
next slot of the skipped picture and convert it's pic_type
to that of the reference picture
*****************************************************************************/
void irc_skip_encoded_frame(pic_handling_t *ps_pic_handling,
picture_type_e e_pic_type)
{
pic_details_t s_pic_details;
WORD32 i4_stack_count, i4_next_ref_pic_idx, i4_pic_idx;
WORD32 i4_max_inter_frm_int, i4_last_b_pic_idx, i4_first_b_pic_idx;
WORD32 i4_next_pic_idx;
/* State variables used to initialize the local vars (Not to be changed) */
i4_stack_count = ps_pic_handling->i4_stack_count;
i4_next_ref_pic_idx = ps_pic_handling->i4_ref_pic_idx;
i4_max_inter_frm_int = ps_pic_handling->i4_max_inter_frm_int;
i4_next_pic_idx = ((i4_stack_count + 1) % (i4_max_inter_frm_int + 1));
/*
* Check what is the encoded frm_type
* Changing a B_PIC to a ref_pic is not reqd if
* there are no B_PICs referring from the skipped ref_pic
*/
if(((e_pic_type == P_PIC) || (e_pic_type == I_PIC))
&& (i4_next_pic_idx != i4_next_ref_pic_idx))
{
/* Go to the last B_PIC before the next_ref_pic */
if(i4_next_ref_pic_idx == 0)
{
i4_last_b_pic_idx = i4_max_inter_frm_int;
}
else
{
i4_last_b_pic_idx = (i4_next_ref_pic_idx - 1);
}
/* Keep a copy of the last B_PIC pic_details */
memcpy(&s_pic_details,
&ps_pic_handling->as_pic_stack[i4_last_b_pic_idx],
sizeof(pic_details_t));
i4_pic_idx = i4_last_b_pic_idx;
i4_first_b_pic_idx = (i4_stack_count + 1) % (i4_max_inter_frm_int + 1);
/*
* All the B_PICs other than the last one, need to be shifted one place
* in the stack
*/
while((i4_pic_idx != i4_stack_count)
&& (i4_first_b_pic_idx != i4_last_b_pic_idx))
{
if(i4_pic_idx == 0)
{
i4_pic_idx = i4_max_inter_frm_int;
}
else
{
i4_pic_idx--;
}
memcpy(&ps_pic_handling->as_pic_stack[(i4_pic_idx + 1)
% (i4_max_inter_frm_int + 1)],
&ps_pic_handling->as_pic_stack[i4_pic_idx],
sizeof(pic_details_t));
}
/*
* Copy the last B_PIC pic_details to the first B_PIC place and change
* it's pic type to the ref_PIC
*/
/*e_ref_pic_type*/
ps_pic_handling->as_pic_stack[i4_first_b_pic_idx].e_pic_type = P_PIC;
ps_pic_handling->as_pic_stack[i4_first_b_pic_idx].i4_pic_disp_order_no =
s_pic_details.i4_pic_disp_order_no;
ps_pic_handling->as_pic_stack[i4_first_b_pic_idx].i4_pic_id =
s_pic_details.i4_pic_id;
/* Change the rem_frms_in_prd so that the update works properly */
if(ps_pic_handling->i4_rem_frms_in_gop[B_PIC] > 0)
{
ps_pic_handling->i4_rem_frms_in_gop[B_PIC]--;
ps_pic_handling->i4_rem_frms_in_gop[P_PIC]++;
}
}
}
/******************************************************************************
Function Name : flush_frame
Description : Since when a flush frame is called, there will be no valid
frames after it, the last frame cannot be a B_PIC, as there
will be no reference frame for it (Input in display order)
So,this fxn needs to go to the last added pic in the pic_stack.
If it's reference pic don't do anything
If it's a B_PIC, copy it's pic_details and put it in the
place of the next reference pic, changing the pic_type to
P_PIC
*****************************************************************************/
void irc_flush_frame_from_pic_stack(pic_handling_t *ps_pic_handling)
{
pic_details_t s_prev_pic_details;
/* Get the last entered pic_details (not to be modified here) */
WORD32 i4_prev_b_pic_idx = ps_pic_handling->i4_prev_b_pic_idx;
WORD32 i4_ref_pic_idx = ps_pic_handling->i4_ref_pic_idx;
WORD32 i4_b_pic_idx = ps_pic_handling->i4_b_pic_idx;
memcpy(&s_prev_pic_details, &ps_pic_handling->s_prev_pic_details,
sizeof(pic_details_t));
if(s_prev_pic_details.e_pic_type == B_PIC)
{
/* Copy the last B_PIC details to the next reference pic in display order */
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_disp_order_no =
s_prev_pic_details.i4_pic_disp_order_no;
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_id =
s_prev_pic_details.i4_pic_id;
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].e_pic_type = P_PIC;
/*
* Modify the last B_PIC pic_type, so that codec gets to know when
* all the buffered frames
* are flushed
*/
ps_pic_handling->as_pic_stack[i4_prev_b_pic_idx].e_pic_type =
MAX_PIC_TYPE;
ps_pic_handling->as_pic_stack[i4_prev_b_pic_idx].i4_pic_id = -1;
ps_pic_handling->as_pic_stack[i4_prev_b_pic_idx].i4_pic_disp_order_no =
-1;
}
else
{
/*
* Modify the next pic_type details in the stack, so that codec gets to
* know when all the
* buffered frames are flushed
*/
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].e_pic_type = MAX_PIC_TYPE;
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_id = -1;
ps_pic_handling->as_pic_stack[i4_ref_pic_idx].i4_pic_disp_order_no = -1;
if(ps_pic_handling->i4_inter_frm_int != 1)
{
ps_pic_handling->as_pic_stack[i4_b_pic_idx].e_pic_type =
MAX_PIC_TYPE;
ps_pic_handling->as_pic_stack[i4_b_pic_idx].i4_pic_id = -1;
ps_pic_handling->as_pic_stack[i4_b_pic_idx].i4_pic_disp_order_no =
-1;
}
}
}
/******************************************************************************
Function Name : irc_add_pic_to_stack_re_enc
Description : In case of a re-enc, we can assume the pictures to be coming
in the encode order.
In case of re-encoder basically, there are 2 problematic cases.
1)Inter_frm_int is not known to start with
2)Inter_frm_int can keep changing
3)Intra_frm_int set by the application and that actually in the
decoded bitstream may be different
*****************************************************************************/
WORD32 irc_add_pic_to_stack_re_enc(pic_handling_t *ps_pic_handling,
WORD32 i4_enc_pic_id,
picture_type_e e_pic_type)
{
WORD32 i4_b_count_in_subgop;
WORD32 i4_max_inter_frm_int, i4_inter_frm_int, i4_intra_frm_int;
WORD32 i4_pic_disp_order_no;
WORD32 i4_is_gop_closed;
picture_type_e e_out_pic_type;
WORD32 i4_b_in_incomp_subgop;
/* Check if a change in intra_frm_int call has been made */
if(ps_pic_handling->i4_change_in_intra_frm_int == 1)
{
irc_update_pic_distbn(ps_pic_handling,
ps_pic_handling->i4_new_intra_frm_int,
ps_pic_handling->i4_inter_frm_int, 1);
ps_pic_handling->i4_change_in_intra_frm_int = 0;
}
/* Check if a change in inter_frm_int call has been made */
if(ps_pic_handling->i4_change_in_inter_frm_int == 1)
{
irc_update_pic_distbn(ps_pic_handling,
ps_pic_handling->i4_intra_frm_int,
ps_pic_handling->i4_new_inter_frm_int, 1);
ps_pic_handling->i4_change_in_inter_frm_int = 0;
}
/* Initialize the local vars with the state vars */
i4_b_count_in_subgop = ps_pic_handling->i4_b_count_in_subgop;
i4_max_inter_frm_int = ps_pic_handling->i4_max_inter_frm_int;
i4_inter_frm_int = ps_pic_handling->i4_inter_frm_int;
i4_intra_frm_int = ps_pic_handling->i4_intra_frm_int;
i4_pic_disp_order_no = ps_pic_handling->i4_pic_disp_order_no;
i4_is_gop_closed = ps_pic_handling->i4_is_gop_closed;
i4_b_in_incomp_subgop = ps_pic_handling->i4_b_in_incomp_subgop;
e_out_pic_type = e_pic_type;
/* Initially the rate_control assumes an IPP sequence */
if(e_pic_type == B_PIC)
{
/* Update the number of B_PICs in a subgop */
i4_b_count_in_subgop++;
if(i4_b_count_in_subgop > i4_max_inter_frm_int)
{
return (-1);
}
/* If the number of B_PICs exceed the set inter_frm_int then
change the inter_frm_int */
if(i4_b_count_in_subgop > (i4_inter_frm_int - 1))
{
i4_inter_frm_int = (i4_b_count_in_subgop + 1);
irc_update_pic_distbn(ps_pic_handling, i4_intra_frm_int,
i4_inter_frm_int, 0);
}
}
else if((e_pic_type == I_PIC) || (e_pic_type == P_PIC))
{
/* If the B_PICs in the prev subgop were fewer than the current
* (inter_frm_int-1) and none of these conditions occur, it'll mean the
* decrease in the inter_frm_int
* 1)End of a GOP
* 2)Beginning of an OPEN_GOP
*/
if((i4_b_count_in_subgop < (i4_inter_frm_int - 1))
&& !((!i4_is_gop_closed)
&& (i4_b_count_in_subgop
>= i4_b_in_incomp_subgop))
&& !((i4_pic_disp_order_no
+ (i4_inter_frm_int - 1
- i4_b_count_in_subgop))
> i4_intra_frm_int))
{
i4_inter_frm_int = (i4_b_count_in_subgop + 1);
irc_update_pic_distbn(ps_pic_handling, i4_intra_frm_int,
i4_inter_frm_int, 0);
}
/* Reset the number of B_PICs in a subgop */
i4_b_count_in_subgop = 0;
}
/* Updation of the frame level vars */
i4_pic_disp_order_no++;
/* End of gop condition
*Two cases can arise :
*1) The intra_frm_int set by the application is greater than the actual
* bitstream intra_frm_int (i.e. we will get an I frame before
* pic_disp_order_no goes to intra_frm_int)
*2) The intra_frm_int set by the application is smaller than the actual bitstream intra_frm_int
* (i.e. we won't get an I_PIC even if pic_disp_order_no goes to
* intra_frm_int) Constraints :
* 1) I_PIC cannot be changed to B_PIC
* 2) B_PIC cannot be changed to I_PIC
*/
if(i4_pic_disp_order_no >= i4_intra_frm_int)
{
if(e_pic_type != B_PIC)
{
e_out_pic_type = I_PIC;
}
else
{
e_out_pic_type = B_PIC;
ps_pic_handling->i4_rem_frms_in_gop[B_PIC]++;
ps_pic_handling->i4_frms_in_cur_gop[B_PIC]++;
ps_pic_handling->i4_frms_in_gop[B_PIC]++;
}
}
else
{
if((e_pic_type == I_PIC) && (!ps_pic_handling->i4_is_first_gop))
{
e_out_pic_type = P_PIC;
ps_pic_handling->i4_rem_frms_in_gop[P_PIC]++;
ps_pic_handling->i4_frms_in_cur_gop[P_PIC]++;
ps_pic_handling->i4_frms_in_gop[P_PIC]++;
}
else
{
e_out_pic_type = e_pic_type;
}
}
/* Update the frm_vars at the end of the gop */
if(i4_pic_disp_order_no
== (ps_pic_handling->i4_frms_in_cur_gop[P_PIC]
+ ps_pic_handling->i4_frms_in_cur_gop[B_PIC]
+ 1))
{
i4_pic_disp_order_no = 0;
ps_pic_handling->i4_is_first_gop = 0;
}
/* Update the vars working on the encoded pics */
if((ps_pic_handling->i4_is_first_gop)
&& (ps_pic_handling->i4_stack_count == -1))
{
ps_pic_handling->i4_coded_pic_no = 0;
ps_pic_handling->i4_stack_count = 0;
}
/* Add the pic_details to the pic_stack */
ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count].e_pic_type =
e_out_pic_type;
ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count].i4_pic_disp_order_no =
ps_pic_handling->i4_pic_disp_order_no;
ps_pic_handling->as_pic_stack[ps_pic_handling->i4_stack_count].i4_pic_id =
i4_enc_pic_id;
/* Writing back those values which need to be updated */
ps_pic_handling->i4_inter_frm_int = i4_inter_frm_int;
ps_pic_handling->i4_pic_disp_order_no = i4_pic_disp_order_no;
ps_pic_handling->i4_b_count_in_subgop = i4_b_count_in_subgop;
return (0);
}