C++程序  |  760行  |  21.35 KB

/******************************************************************************
 *
 * 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
*  ih264e_time_stamp.c
*
* @brief
*  This file contains functions used for source and target time stamp management
*
* @author
*  ittiam
*
* @par List of Functions:
*  - gcd()
*  - ih264e_get_range()
*  - ih264e_frame_time_get_init_free_memtab()
*  - ih264e_init_frame_time()
*  - ih264e_should_src_be_skipped()
*  - ih264e_time_stamp_get_init_free_memtab()
*  - ih264e_init_time_stamp()
*  - ih264e_update_time_stamp()
*  - ih264e_frame_time_get_src_frame_rate()
*  - ih264e_frame_time_get_tgt_frame_rate()
*  - ih264e_frame_time_get_src_ticks()
*  - ih264e_frame_time_get_tgt_ticks()
*  - ih264e_frame_time_get_src_time()
*  - ih264e_frame_time_get_tgt_time()
*  - ih264e_frame_time_update_src_frame_rate()
*  - ih264e_frame_time_update_tgt_frame_rate()
*  - ih264_time_stamp_update_frame_rate()
*
* @remarks
*  None
*
*******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/

/* user include files */
#include "irc_datatypes.h"
#include "iv2.h"
#include "ive2.h"
#include "ih264e_error.h"
#include "ih264e_bitstream.h"
#include "ih264_defs.h"
#include "ih264e_defs.h"
#include "ime_distortion_metrics.h"
#include "ime_defs.h"
#include "ime_structs.h"
#include "irc_cntrl_param.h"
#include "irc_frame_info_collector.h"
#include "ih264e_rate_control.h"
#include "ih264_structs.h"
#include "ih264_trans_quant_itrans_iquant.h"
#include "ih264_inter_pred_filters.h"
#include "ih264_mem_fns.h"
#include "ih264_padding.h"
#include "ih264_intra_pred_filters.h"
#include "ih264_deblk_edge_filters.h"
#include "ih264_cabac_tables.h"
#include "ih264e_cabac_structs.h"
#include "ih264e_structs.h"
#include "ih264e_rc_mem_interface.h"
#include "ih264e_time_stamp.h"
#include "irc_common.h"
#include "irc_rate_control_api.h"


/*****************************************************************************/
/* Function Definitions                                                      */
/*****************************************************************************/

/**
*******************************************************************************
*
* @brief Function to compute gcd of two numbers
*
* @par   Description
*  Function to compute gcd of two numbers
*
* @param[in] i4_x
*  value 1
*
* @param[in] i4_y
*  value 2
*
* @returns
*  GCD(value 1, value 2)
*
* @remarks none
*
*******************************************************************************
*/
static WORD32 gcd(WORD32 i4_x, WORD32 i4_y)
{
    if (i4_x > i4_y)
    {
        i4_x = i4_y + i4_x;
        i4_y = i4_x - i4_y;
        i4_x = i4_x - i4_y;
    }
    while (i4_y != 0)
    {
        WORD32 temp;
        i4_x = i4_x % i4_y;
        temp = i4_x;
        i4_x = i4_y;
        i4_y = temp;
    }
    return (i4_x);
}

/**
*******************************************************************************
*
* @brief Function to determine number of bits required to represent a given
*  value
*
* @par   Description
*  This function determines the number of bits required to represent the given
*  value. It is used to find out number of bits to read when the data size is
*  not fixed (e.g. vop_time_increment_resolution).
*
* @param[in] u4_value
*  Value for which the number of bits required to represent is to be determined
*
* @param[in] u1_no_of_bits
*  Represents the value's word type = 8/16/32
*
* @returns
*  The number of bits required to represent the given number
*
* @remarks none
*
*******************************************************************************
*/
static UWORD8 ih264e_get_range(UWORD32 u4_value, UWORD8 u1_no_of_bits)
{
    UWORD8 count;
    UWORD32 temp;

    if (u4_value > (UWORD32) ((1 << (u1_no_of_bits >> 1)) - 1))
    {
        temp = (1 << (u1_no_of_bits - 1));
        for (count = 0; count < (u1_no_of_bits >> 1); count++)
        {
            if ((temp & u4_value) != 0)
            {
                return (UWORD8) (u1_no_of_bits - count);
            }
            else
            {
                temp >>= 1;
            }
        }
        return 0;
    }
    else
    {
        temp = (1 << ((u1_no_of_bits >> 1) - 1));
        for (count = 0; count < ((u1_no_of_bits >> 1) - 1); count++)
        {
            if ((temp & u4_value) != 0)
            {
                return (UWORD8) ((u1_no_of_bits >> 1) - count);
            }
            else
            {
                temp >>= 1;
            }
        }
        return 1;
    }
}

/**
*******************************************************************************
*
* @brief
*  Function to init frame time memtabs
*
* @par Description
*  Function to init frame time memtabs
*
* @param[in] pps_frame_time
*  Pointer to frame time contexts
*
* @param[in] ps_memtab
*  Pointer to memtab
*
* @param[in] e_func_type
*  Function type (get memtabs/init memtabs)
*
* @returns
*  none
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_init_free_memtab(frame_time_handle *pps_frame_time,
                                              itt_memtab_t *ps_memtab,
                                              ITT_FUNC_TYPE_E e_func_type)
{
    WORD32 i4_mem_tab_idx = 0;
    frame_time_t s_temp_frame_time_t;

    /* 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_frame_time) = &s_temp_frame_time_t;

    /* for src rate control state structure */
    if (e_func_type != GET_NUM_MEMTAB)
    {
        fill_memtab(&ps_memtab[i4_mem_tab_idx], sizeof(frame_time_t),
                    ALIGN_128_BYTE, PERSISTENT, DDR);
        use_or_fill_base(&ps_memtab[0], (void**) pps_frame_time, e_func_type);
    }
    i4_mem_tab_idx++;

    return (i4_mem_tab_idx);
}

/**
*******************************************************************************
*
* @brief
*  Function to init frame time context
*
* @par Description
*  Frame time structure stores the time of the source and the target frames to
*  be encoded. Based on the time we decide whether or not to encode the source
*  frame
*
* @param[in] ps_frame_time
*  Pointer Frame time context
*
* @param[in] u4_src_frm_rate
*  Source frame rate
*
* @param[in] u4_tgt_frm_rate
*  Target frame rate
*
* @returns
*  none
*
* @remarks
*
*******************************************************************************
*/
void ih264e_init_frame_time(frame_time_t *ps_frame_time,
                            UWORD32 u4_src_frm_rate,
                            UWORD32 u4_tgt_frm_rate)
{
    /* Initialise the common time base based on which the source and target
     * frame times increase */
    WORD32 i4_gcd = gcd(u4_src_frm_rate, u4_tgt_frm_rate);

    /* Avoiding overflow by doing calculations in float */
    number_t s_src_frm_rate, s_tgt_frm_rate, s_gcd, s_common_time_base, s_numerator;

    SET_VAR_Q(s_src_frm_rate, u4_src_frm_rate, 0);
    SET_VAR_Q(s_tgt_frm_rate, u4_tgt_frm_rate, 0);
    SET_VAR_Q(s_gcd, i4_gcd, 0);
    mult32_var_q(s_src_frm_rate, s_tgt_frm_rate, &s_numerator);
    div32_var_q(s_numerator, s_gcd, &s_common_time_base);
    number_t_to_word32(s_common_time_base, &(ps_frame_time->common_time_base));

    /* The source and target increment per vop is initialized */
    ps_frame_time->u4_src_frm_time_incr = ps_frame_time->common_time_base
                    / u4_src_frm_rate;
    ps_frame_time->u4_tgt_frm_time_incr = ps_frame_time->common_time_base
                    / u4_tgt_frm_rate;

    /* Initialise the source and target times to 0 (RESET) */
    ps_frame_time->u4_src_frm_time = 0;
    ps_frame_time->u4_tgt_frm_time = 0;

    /* Initialize the number of frms not to be skipped to 0 */
    ps_frame_time->u4_num_frms_dont_skip = 0;
}

/**
*******************************************************************************
*
* @brief
*  Function to check if frame can be skipped
*
* @par Description
*  Based on the source and target frame time and the delta time stamp
*  we decide whether to code the source or not.
*  This is based on the assumption
*  that the source frame rate is greater that target frame rate.
*  Updates the time_stamp structure
*
* @param[in] ps_frame_time
*  Handle to frame time context
*
* @param[in] u4_delta_time_stamp
*  Time stamp difference between frames
*
* @param[out] pu4_frm_not_skipped_for_dts
*  Flag to indicate if frame is already skipped by application
*
* @returns
*  Flag to skip frame
*
* @remarks
*
*******************************************************************************
*/
UWORD8 ih264e_should_src_be_skipped(frame_time_t *ps_frame_time,
                                    UWORD32 u4_delta_time_stamp,
                                    UWORD32 *pu4_frm_not_skipped_for_dts)
{
    UWORD8 skip_src = 0;

    if (ps_frame_time->u4_tgt_frm_time > ps_frame_time->u4_src_frm_time &&
        ps_frame_time->u4_tgt_frm_time >= (ps_frame_time->u4_src_frm_time +
                        ps_frame_time->u4_src_frm_time_incr))
    {
        skip_src = 1;
    }

    /* source time gets updated every frame */
    ps_frame_time->u4_src_frm_time += ps_frame_time->u4_src_frm_time_incr;

    /* target time gets updated only when the source is coded */
    if (!skip_src)
    {
        ps_frame_time->u4_tgt_frm_time += ps_frame_time->u4_tgt_frm_time_incr;
    }

    /* If the source and target frame times get incremented properly
     both should be equal to the common time base at the same time. If
     that happens we reset the time to zero*/
    if (( ps_frame_time->common_time_base ==(WORD32)ps_frame_time->u4_src_frm_time)
         && (ps_frame_time->common_time_base ==(WORD32) ps_frame_time->u4_tgt_frm_time ))
    {
        ps_frame_time->u4_src_frm_time = 0;
        ps_frame_time->u4_tgt_frm_time = 0;
    }

    /* This keeps a count of how many frames need not be skipped in order
     to take care of the delta time stamp */
    ps_frame_time->u4_num_frms_dont_skip += (u4_delta_time_stamp - 1);

    /** If this frame is to be skipped in order to maintain the tgt_frm_rate
     check if already a frame has been skipped by the application.
     In that case, do not skip this frame **/
    if (ps_frame_time->u4_num_frms_dont_skip && skip_src)
    {
        skip_src = 0;
        *pu4_frm_not_skipped_for_dts = 1;
        ps_frame_time->u4_num_frms_dont_skip -= 1;
    }
    else
    {
        pu4_frm_not_skipped_for_dts[0] = 0;
    }

    return (skip_src);
}

/**
*******************************************************************************
*
* @brief
*  Function to inititialize time stamp memtabs
*
* @par Description
*  Function to initialize time stamp memtabs
*
* @param[in] pps_time_stamp
*  Pointer to time stamp context
*
* @param[in] ps_memtab
*  Pointer to memtab
*
* @param[in] e_func_type
*  Funcion type (Get memtab/ init memtab)
*
* @returns
*   number of memtabs used
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_time_stamp_get_init_free_memtab(time_stamp_handle *pps_time_stamp,
                                              itt_memtab_t *ps_memtab,
                                              ITT_FUNC_TYPE_E e_func_type)
{
    WORD32 i4_mem_tab_idx = 0;
    time_stamp_t s_temp_time_stamp_t;

    /* 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_time_stamp) = &s_temp_time_stamp_t;

    /* for src rate control state structure */
    if (e_func_type != GET_NUM_MEMTAB)
    {
        fill_memtab(&ps_memtab[i4_mem_tab_idx], sizeof(time_stamp_t),
                    ALIGN_128_BYTE, PERSISTENT, DDR);
        use_or_fill_base(&ps_memtab[0], (void**) pps_time_stamp, e_func_type);
    }
    i4_mem_tab_idx++;

    return (i4_mem_tab_idx);
}

/**
*******************************************************************************
*
* @brief
*  Function to initialize time stamp context
*
* @par Description
*  Time stamp structure stores the time stamp data that
*  needs to be sent in to the header of MPEG4. Based on the
*  max target frame rate the vop_time increment resolution is set
*  so as to support all the frame rates below max frame rate.
*  A support till the third decimal point is assumed.
*
* @param[in] ps_time_stamp
*  Pointer to time stamp structure
*
* @param[in] u4_max_frm_rate
*  Maximum frame rate
*
* @param[in] u4_src_frm_rate
*  Source frame rate
*
* @returns
*  none
*
* @remarks
*
*******************************************************************************
*/
void ih264e_init_time_stamp(time_stamp_t *ps_time_stamp,
                            UWORD32 u4_max_frm_rate,
                            UWORD32 u4_src_frm_rate)
{
    /* We expect the max frame rate to be less than 60000,
     * if not we divide it by zero and work with it */
    if (u4_max_frm_rate > 60000)
    {
        u4_max_frm_rate >>= 1;
        ps_time_stamp->is_max_frame_rate_scaled = 1;
    }
    else
    {
        ps_time_stamp->is_max_frame_rate_scaled = 0;
    }

    ps_time_stamp->u4_vop_time_incr_res = u4_max_frm_rate;
    ps_time_stamp->u4_vop_time_incr_range = ih264e_get_range(u4_max_frm_rate, 32);
    ps_time_stamp->u4_vop_time_incr = (ps_time_stamp->u4_vop_time_incr_res * 1000) / u4_src_frm_rate;/* Since frm rate is in millisec */
    ps_time_stamp->u4_vop_time = 0;
    ps_time_stamp->u4_cur_tgt_vop_time = 0;
    ps_time_stamp->u4_prev_tgt_vop_time = 0;
}

/**
*******************************************************************************
*
* @brief Function to update time stamp context
*
* @par Description
*  Vop time is incremented by increment value. When vop time goes
*  more than the vop time resolution set the modulo time base to
*  1 and reduce the vop time by vop time resolution so that the
*  excess value is present in vop time and get accumulated over time
*  so that the corresponding frame rate is achieved at a average of
*  1000 seconds
*
* @param[in] ps_time_stamp
*  Pointer to time stamp structure
*
* @returns
*  none
*
* @remarks
*
*******************************************************************************
*/
void ih264e_update_time_stamp(time_stamp_t *ps_time_stamp)
{
    /* Since get time stamp is called after the update
     A copy of the vop time and the modulo time is stored */
    ps_time_stamp->u4_cur_tgt_vop_time = ps_time_stamp->u4_vop_time;

    ps_time_stamp->u4_vop_time += ps_time_stamp->u4_vop_time_incr;
    if (ps_time_stamp->u4_vop_time >= ps_time_stamp->u4_vop_time_incr_res)
    {
        ps_time_stamp->u4_vop_time -= ps_time_stamp->u4_vop_time_incr_res;
    }
}

/****************************************************************************
                       Run-Time Modifying functions
****************************************************************************/

/**
*******************************************************************************
*
* @brief Function to get source frame rate
*
* @par Description
*  Function to get source frame rate
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*  source frame rate
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_src_frame_rate(frame_time_t *ps_frame_time)
{
    return (ps_frame_time->common_time_base / ps_frame_time->u4_src_frm_time_incr);
}

/**
*******************************************************************************
*
* @brief Function to get target frame rate
*
* @par Description
*  Function to get target frame rate
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*   target frame rate
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_tgt_frame_rate(frame_time_t *ps_frame_time)
{
    return (ps_frame_time->common_time_base / ps_frame_time->u4_tgt_frm_time_incr);
}

/**
*******************************************************************************
*
* @brief Function to get source time increment
*
* @par Description
*  Function to get source time increment
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*  source time increment
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_src_ticks(frame_time_t *ps_frame_time)
{
    return (ps_frame_time->u4_src_frm_time_incr);
}

/**
*******************************************************************************
*
* @brief Function to get target time increment
*
* @par Description
*  Function to get target time increment
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*  target time increment
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_tgt_ticks(frame_time_t *ps_frame_time)
{
    return (ps_frame_time->u4_tgt_frm_time_incr);
}

/**
*******************************************************************************
*
* @brief Function to get src frame time
*
* @par Description
*  Function to get src frame time
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*  src frame time
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_src_time(frame_time_t *frame_time)
{
    return (frame_time->u4_src_frm_time);
}

/**
*******************************************************************************
*
* @brief Function to get tgt frame time
*
* @par Description
*  Function to get tgt frame time
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @returns
*  tgt frame time
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_frame_time_get_tgt_time(frame_time_t *frame_time)
{
    return (frame_time->u4_tgt_frm_time);
}

/**
*******************************************************************************
*
* @brief Function to update source frame time with a new source frame rate
*
* @par Description
*  Function to update source frame time with a new source frame rate
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @param[in] src_frm_rate
*  source frame rate
*
* @returns
*  None
*
* @remarks
*
*******************************************************************************
*/
void ih264e_frame_time_update_src_frame_rate(frame_time_t *ps_frame_time,
                                             WORD32 src_frm_rate)
{
    /* Since tgt frame rate does not change deriving the tgt_frm rate from
     * common_time_base */
    WORD32 tgt_frm_rate = ps_frame_time->common_time_base / ps_frame_time->u4_tgt_frm_time_incr;

    /* Re-initialise frame_time based on the new src_frame_rate and
     * old tgt_frame_rate */
    ih264e_init_frame_time(ps_frame_time, src_frm_rate, tgt_frm_rate);
}

/**
*******************************************************************************
*
* @brief Function to update target frame time with a new source frame rate
*
* @par Description
*  Function to update target frame time with a new source frame rate
*
* @param[in] ps_frame_time
*  Pointer to frame time context
*
* @param[in] tgt_frm_rate
*  target frame rate
*
* @returns
*  None
*
* @remarks
*
*******************************************************************************
*/
void ih264e_frame_time_update_tgt_frame_rate(frame_time_t *ps_frame_time,
                                             WORD32 tgt_frm_rate)
{
    /* Since src frame rate does not change deriving the src_frm rate from
     * common_time_base */
    WORD32 src_frm_rate = ps_frame_time->common_time_base / ps_frame_time->u4_src_frm_time_incr;

    /* Re-initialise frame_time based on the new tgt_frame_rate and
     * old src_frame_rate */
    ih264e_init_frame_time(ps_frame_time, src_frm_rate, tgt_frm_rate);
}

/**
*******************************************************************************
*
* @brief Function to update target frame time with a new source frame rate
*
* @par Description
*  When the frame rate changes the time increment is modified by appropriate ticks
*
* @param[in] ps_time_stamp
*  Pointer to time stamp structure
*
* @param[in] src_frm_rate
*  source frame rate
*
* @returns
*  None
*
* @remarks
*
*******************************************************************************
*/
void ih264_time_stamp_update_frame_rate(time_stamp_t *ps_time_stamp,
                                        UWORD32 src_frm_rate)
{
    ps_time_stamp->u4_vop_time_incr = (ps_time_stamp->u4_vop_time_incr_res * 1000) / src_frm_rate;/* Since frm rate is in millisec */
}