summaryrefslogtreecommitdiffstats
path: root/encoder/irc_picture_type.c
diff options
context:
space:
mode:
authorHamsalekha S <hamsalekha.s@ittiam.com>2015-03-13 21:24:58 +0530
committerHamsalekha S <hamsalekha.s@ittiam.com>2015-04-02 15:59:02 +0530
commit8d3d303c7942ced6a987a52db8977d768dc3605f (patch)
treecc806c96794356996b13ba9970941d0aed74a97e /encoder/irc_picture_type.c
parent3956d913d37327dcb340f836e604b04bd478b158 (diff)
downloadandroid_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-xencoder/irc_picture_type.c1585
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);
+}