diff options
author | Hamsalekha S <hamsalekha.s@ittiam.com> | 2015-03-13 21:24:58 +0530 |
---|---|---|
committer | Hamsalekha S <hamsalekha.s@ittiam.com> | 2015-04-02 15:59:02 +0530 |
commit | 8d3d303c7942ced6a987a52db8977d768dc3605f (patch) | |
tree | cc806c96794356996b13ba9970941d0aed74a97e /encoder/irc_picture_type.c | |
parent | 3956d913d37327dcb340f836e604b04bd478b158 (diff) | |
download | android_external_libavc-8d3d303c7942ced6a987a52db8977d768dc3605f.tar.gz android_external_libavc-8d3d303c7942ced6a987a52db8977d768dc3605f.tar.bz2 android_external_libavc-8d3d303c7942ced6a987a52db8977d768dc3605f.zip |
Initial version
Change-Id: I7efe9a589cd24edf86e8d086b40c27cbbf8b4017
Diffstat (limited to 'encoder/irc_picture_type.c')
-rwxr-xr-x | encoder/irc_picture_type.c | 1585 |
1 files changed, 1585 insertions, 0 deletions
diff --git a/encoder/irc_picture_type.c b/encoder/irc_picture_type.c new file mode 100755 index 0000000..186188c --- /dev/null +++ b/encoder/irc_picture_type.c @@ -0,0 +1,1585 @@ +/****************************************************************************** + * + * 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; + static 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_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_max_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; + 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_max_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 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 = (1 + + 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++; + + /* For any gop */ + 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; + } + } + + /* 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 + == (i4_max_inter_frm_int - 1))) + || (i4_intra_frm_int == 1)) + { + 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); +} |