/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
* Copyright (c) Imagination Technologies Limited, UK
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Elaine Wang <elaine.wang@intel.com>
* Zeng Li <zeng.li@intel.com>
* Edward Lin <edward.lin@intel.com>
*
*/
#include "psb_drv_video.h"
//#include "tng_H263ES.h"
#include "tng_hostheader.h"
#include "tng_hostcode.h"
#include "psb_def.h"
#include "psb_drv_debug.h"
#include "psb_cmdbuf.h"
#include "psb_buffer.h"
#include <stdio.h>
#include "psb_output.h"
#include "tng_picmgmt.h"
#include "tng_hostbias.h"
#include "tng_hostair.h"
#ifdef _TOPAZHP_PDUMP_
#include "tng_trace.h"
#endif
#include <wsbm/wsbm_manager.h>
#include "hwdefs/topazhp_core_regs.h"
#include "hwdefs/topazhp_multicore_regs_old.h"
#include "hwdefs/topaz_db_regs.h"
#include "hwdefs/topaz_vlc_regs.h"
#include "hwdefs/mvea_regs.h"
#include "hwdefs/topazhp_default_params.h"
#define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1))
#define PAGE_ALIGN(value) ALIGN_TO(value, 4096)
#define DEFAULT_MVCALC_CONFIG ((0x00040303)|(MASK_TOPAZHP_CR_MVCALC_JITTER_POINTER_RST))
#define DEFAULT_MVCALC_COLOCATED (0x00100100)
#define MVEA_MV_PARAM_REGION_SIZE 16
#define MVEA_ABOVE_PARAM_REGION_SIZE 96
#define QUANT_LISTS_SIZE (224)
#define _1080P_30FPS (((1920*1088)/256)*30)
#define tng_align_64(X) (((X)+63) &~63)
#define tng_align_4(X) (((X)+3) &~3)
/* #define MTX_CONTEXT_ITEM_OFFSET(type, member) (size_t)&(((type*)0)->member) */
#define DEFAULT_CABAC_DB_MARGIN (0x190)
#define NOT_USED_BY_TOPAZ 0
/*
#define _TOPAZHP_CMDBUF_
*/
#ifdef _TOPAZHP_CMDBUF_
static void tng__trace_cmdbuf_words(tng_cmdbuf_p cmdbuf)
{
int i = 0;
IMG_UINT32 *ptmp = (IMG_UINT32 *)(cmdbuf->cmd_start);
IMG_UINT32 *pend = (IMG_UINT32 *)(cmdbuf->cmd_idx);
do {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: command words [%d] = 0x%08x\n", __FUNCTION__, i++, (unsigned int)(*ptmp++));
} while(ptmp < pend);
return ;
}
#endif
#if 0
static IMG_UINT32 tng__get_codedbuffer_size(
IMG_STANDARD eStandard,
IMG_UINT16 ui16MBWidth,
IMG_UINT16 ui16MBHeight,
IMG_RC_PARAMS * psRCParams
)
{
if (eStandard == IMG_STANDARD_H264) {
// allocate based on worst case qp size
return ((IMG_UINT32)ui16MBWidth * (IMG_UINT32)ui16MBHeight * 400);
}
if (psRCParams->ui32InitialQp <= 5)
return ((IMG_UINT32)ui16MBWidth * (IMG_UINT32)ui16MBHeight * 1600);
return ((IMG_UINT32)ui16MBWidth * (IMG_UINT32)ui16MBHeight * 900);
}
static IMG_UINT32 tng__get_codedbuf_size_according_bitrate(
IMG_RC_PARAMS * psRCParams
)
{
return ((psRCParams->ui32BitsPerSecond + psRCParams->ui32FrameRate / 2) / psRCParams->ui32FrameRate) * 2;
}
static IMG_UINT32 tng__get_buffer_size(IMG_UINT32 src_size)
{
return (src_size + 0x1000) & (~0xfff);
}
#endif
//static inline
VAStatus tng__alloc_init_buffer(
psb_driver_data_p driver_data,
unsigned int size,
psb_buffer_type_t type,
psb_buffer_p buf)
{
unsigned char *pch_virt_addr;
VAStatus vaStatus = VA_STATUS_SUCCESS;
vaStatus = psb_buffer_create(driver_data, size, type, buf);
if (VA_STATUS_SUCCESS != vaStatus) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "alloc mem params buffer");
return vaStatus;
}
vaStatus = psb_buffer_map(buf, &pch_virt_addr);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: phy addr 0x%08x, vir addr 0x%08x\n", __FUNCTION__, buf->drm_buf, pch_virt_addr);
if ((vaStatus) || (pch_virt_addr == NULL)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: map buf 0x%08x\n", __FUNCTION__, (IMG_UINT32)pch_virt_addr);
psb_buffer_destroy(buf);
} else {
memset(pch_virt_addr, 0, size);
psb_buffer_unmap(buf);
}
return vaStatus;
}
static VAStatus tng__alloc_context_buffer(context_ENC_p ctx, IMG_UINT8 ui8IsJpeg, IMG_UINT32 ui32StreamID)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT32 ui32_pic_width, ui32_pic_height;
IMG_UINT32 ui32_mb_per_row, ui32_mb_per_column;
IMG_UINT32 ui32_adj_mb_per_row = 0;
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
psb_driver_data_p ps_driver_data = ctx->obj_context->driver_data;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamID]);
context_ENC_mem_size *ps_mem_size = &(ctx->ctx_mem_size);
if (ctx->eStandard == IMG_STANDARD_H264) {
ctx->ui8PipesToUse = tng__min(ctx->ui8PipesToUse, ctx->ui8SlicesPerPicture);
} else {
ctx->ui8PipesToUse = 1;
}
ctx->i32PicNodes = (psRCParams->b16Hierarchical ? MAX_REF_B_LEVELS : 0) + 4;
ctx->i32MVStores = (ctx->i32PicNodes * 2);
ctx->i32CodedBuffers = (IMG_INT32)(ctx->ui8PipesToUse) * (ctx->bIsInterlaced ? 3 : 2);
ctx->ui8SlotsInUse = psRCParams->ui16BFrames + 2;
if (0 != ui8IsJpeg) {
ctx->jpeg_pic_params_size = (sizeof(JPEG_MTX_QUANT_TABLE) + 0x3f) & (~0x3f);
ctx->jpeg_header_mem_size = (sizeof(JPEG_MTX_DMA_SETUP) + 0x3f) & (~0x3f);
ctx->jpeg_header_interface_mem_size = (sizeof(JPEG_MTX_WRITEBACK_MEMORY) + 0x3f) & (~0x3f);
//write back region
ps_mem_size->writeback = tng_align_KB(COMM_WB_DATA_BUF_SIZE);
tng__alloc_init_buffer(ps_driver_data, WB_FIFO_SIZE * ps_mem_size->writeback, psb_bt_cpu_vpu, &(ctx->bufs_writeback));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n", __FUNCTION__);
return vaStatus;
}
/* width and height should be source surface's w and h or ?? */
ui32_pic_width = ctx->obj_context->picture_width;
ui32_mb_per_row = (ctx->obj_context->picture_width + 15) >> 4;
ui32_pic_height = ctx->obj_context->picture_height;
ui32_mb_per_column = (ctx->obj_context->picture_height + 15) >> 4;
ui32_adj_mb_per_row = ((ui32_mb_per_row + 7)>>3)<<3; // Ensure multiple of 8 MBs per row
//command buffer use
ps_mem_size->pic_template = ps_mem_size->slice_template =
ps_mem_size->seq_header = tng_align_KB(TNG_HEADER_SIZE);
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->seq_header,
psb_bt_cpu_vpu, &(ps_mem->bufs_seq_header));
if (ctx->bEnableMVC)
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->seq_header,
psb_bt_cpu_vpu, &(ps_mem->bufs_sub_seq_header));
tng__alloc_init_buffer(ps_driver_data, 4 * ps_mem_size->pic_template,
psb_bt_cpu_vpu, &(ps_mem->bufs_pic_template));
tng__alloc_init_buffer(ps_driver_data, NUM_SLICE_TYPES * ps_mem_size->slice_template,
psb_bt_cpu_vpu, &(ps_mem->bufs_slice_template));
ps_mem_size->mtx_context = tng_align_KB(MTX_CONTEXT_SIZE);
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->mtx_context,
psb_bt_cpu_vpu, &(ps_mem->bufs_mtx_context));
//sei header(AUDHeader+SEIBufferPeriodMem+SEIPictureTimingHeaderMem)
ps_mem_size->sei_header = tng_align_KB(64);
tng__alloc_init_buffer(ps_driver_data, 3 * ps_mem_size->sei_header,
psb_bt_cpu_vpu, &(ps_mem->bufs_sei_header));
//gop header
ps_mem_size->flat_gop = ps_mem_size->hierar_gop = tng_align_KB(64);
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->flat_gop,
psb_bt_cpu_vpu, &(ps_mem->bufs_flat_gop));
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->hierar_gop,
psb_bt_cpu_vpu, &(ps_mem->bufs_hierar_gop));
//above params
ps_mem_size->above_params = tng_align_KB(MVEA_ABOVE_PARAM_REGION_SIZE * tng_align_64(ui32_mb_per_row));
tng__alloc_init_buffer(ps_driver_data, (IMG_UINT32)(ctx->ui8PipesToUse) * ps_mem_size->above_params,
psb_bt_cpu_vpu, &(ps_mem->bufs_above_params));
//ctx->mv_setting_btable_size = tng_align_KB(MAX_BFRAMES * (tng_align_64(sizeof(IMG_MV_SETTINGS) * MAX_BFRAMES)));
ps_mem_size->mv_setting_btable = tng_align_KB(MAX_BFRAMES * MV_ROW_STRIDE);
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->mv_setting_btable,
psb_bt_cpu_vpu, &(ps_mem->bufs_mv_setting_btable));
ps_mem_size->mv_setting_hierar = tng_align_KB(MAX_BFRAMES * sizeof(IMG_MV_SETTINGS));
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->mv_setting_hierar,
psb_bt_cpu_vpu, &(ps_mem->bufs_mv_setting_hierar));
//colocated params
ps_mem_size->colocated = tng_align_KB(MVEA_MV_PARAM_REGION_SIZE * tng_align_4(ui32_mb_per_row * ui32_mb_per_column));
tng__alloc_init_buffer(ps_driver_data, ctx->i32PicNodes * ps_mem_size->colocated,
psb_bt_cpu_vpu, &(ps_mem->bufs_colocated));
ps_mem_size->interview_mv = ps_mem_size->mv = ps_mem_size->colocated;
tng__alloc_init_buffer(ps_driver_data, ctx->i32MVStores * ps_mem_size->mv,
psb_bt_cpu_vpu, &(ps_mem->bufs_mv));
if (ctx->bEnableMVC) {
tng__alloc_init_buffer(ps_driver_data, 2 * ps_mem_size->interview_mv,
psb_bt_cpu_vpu, &(ps_mem->bufs_interview_mv));
}
//write back region
ps_mem_size->writeback = tng_align_KB(COMM_WB_DATA_BUF_SIZE);
tng__alloc_init_buffer(ps_driver_data, WB_FIFO_SIZE * ps_mem_size->writeback,
psb_bt_cpu_vpu, &(ctx->bufs_writeback));
ps_mem_size->slice_map = tng_align_KB(0x1500); //(1 + MAX_SLICESPERPIC * 2 + 15) & ~15);
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ps_mem_size->slice_map,
psb_bt_cpu_vpu, &(ps_mem->bufs_slice_map));
ps_mem_size->weighted_prediction = tng_align_KB(sizeof(WEIGHTED_PREDICTION_VALUES));
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ps_mem_size->weighted_prediction,
psb_bt_cpu_vpu, &(ps_mem->bufs_weighted_prediction));
#ifdef LTREFHEADER
ps_mem_size->lt_ref_header = tng_align_KB((sizeof(MTX_HEADER_PARAMS)+63)&~63);
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ps_mem_size->lt_ref_header,
psb_bt_cpu_vpu, &(ps_mem->bufs_lt_ref_header));
#endif
ps_mem_size->recon_pictures = tng_align_KB((tng_align_64(ui32_pic_width)*tng_align_64(ui32_pic_height))*3/2);
tng__alloc_init_buffer(ps_driver_data, ctx->i32PicNodes * ps_mem_size->recon_pictures,
psb_bt_cpu_vpu, &(ps_mem->bufs_recon_pictures));
ctx->ctx_mem_size.first_pass_out_params = tng_align_KB(sizeof(IMG_FIRST_STAGE_MB_PARAMS) * ui32_mb_per_row * ui32_mb_per_column);
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ctx->ctx_mem_size.first_pass_out_params,
psb_bt_cpu_vpu, &(ps_mem->bufs_first_pass_out_params));
#ifndef EXCLUDE_BEST_MP_DECISION_DATA
ctx->ctx_mem_size.first_pass_out_best_multipass_param = tng_align_KB(ui32_mb_per_column * (((5*ui32_mb_per_row)+3)>>2) * 64);
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ctx->ctx_mem_size.first_pass_out_best_multipass_param,
psb_bt_cpu_vpu, &(ps_mem->bufs_first_pass_out_best_multipass_param));
#endif
ctx->ctx_mem_size.mb_ctrl_in_params = tng_align_KB(sizeof(IMG_FIRST_STAGE_MB_PARAMS) * ui32_adj_mb_per_row * ui32_mb_per_column);
tng__alloc_init_buffer(ps_driver_data, ctx->ui8SlotsInUse * ctx->ctx_mem_size.mb_ctrl_in_params,
psb_bt_cpu_vpu, &(ps_mem->bufs_mb_ctrl_in_params));
ctx->ctx_mem_size.lowpower_params = tng_align_KB(TNG_HEADER_SIZE);
tng__alloc_init_buffer(ps_driver_data, ps_mem_size->lowpower_params,
psb_bt_cpu_vpu, &(ps_mem->bufs_lowpower_params));
ctx->ctx_mem_size.lowpower_data = tng_align_KB(0x10000);
return vaStatus;
}
static void tng__free_context_buffer(context_ENC_p ctx, unsigned char is_JPEG, unsigned int stream_id)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[stream_id]);
if (0 != is_JPEG) {
psb_buffer_destroy(&(ctx->bufs_writeback));
return;
}
psb_buffer_destroy(&(ps_mem->bufs_seq_header));
if (ctx->bEnableMVC)
psb_buffer_destroy(&(ps_mem->bufs_sub_seq_header));
psb_buffer_destroy(&(ps_mem->bufs_pic_template));
psb_buffer_destroy(&(ps_mem->bufs_slice_template));
psb_buffer_destroy(&(ps_mem->bufs_mtx_context));
psb_buffer_destroy(&(ps_mem->bufs_sei_header));
psb_buffer_destroy(&(ps_mem->bufs_flat_gop));
psb_buffer_destroy(&(ps_mem->bufs_hierar_gop));
psb_buffer_destroy(&(ps_mem->bufs_above_params));
psb_buffer_destroy(&(ps_mem->bufs_mv_setting_btable));
psb_buffer_destroy(&(ps_mem->bufs_mv_setting_hierar));
psb_buffer_destroy(&(ps_mem->bufs_colocated));
psb_buffer_destroy(&(ps_mem->bufs_mv));
if (ctx->bEnableMVC)
psb_buffer_destroy(&(ps_mem->bufs_interview_mv));
psb_buffer_destroy(&(ctx->bufs_writeback));
psb_buffer_destroy(&(ps_mem->bufs_slice_map));
psb_buffer_destroy(&(ps_mem->bufs_weighted_prediction));
#ifdef LTREFHEADER
psb_buffer_destroy(&(ps_mem->bufs_lt_ref_header));
#endif
psb_buffer_destroy(&(ps_mem->bufs_recon_pictures));
psb_buffer_destroy(&(ps_mem->bufs_first_pass_out_params));
#ifndef EXCLUDE_BEST_MP_DECISION_DATA
psb_buffer_destroy(&(ps_mem->bufs_first_pass_out_best_multipass_param));
#endif
psb_buffer_destroy(&(ps_mem->bufs_mb_ctrl_in_params));
psb_buffer_destroy(&(ps_mem->bufs_lowpower_params));
return ;
}
unsigned int tng__get_ipe_control(IMG_CODEC eEncodingFormat)
{
unsigned int RegVal = 0;
RegVal = F_ENCODE(2, MVEA_CR_IPE_GRID_FINE_SEARCH) |
F_ENCODE(0, MVEA_CR_IPE_GRID_SEARCH_SIZE) |
F_ENCODE(1, MVEA_CR_IPE_Y_FINE_SEARCH);
switch (eEncodingFormat) {
case IMG_CODEC_H263_NO_RC:
case IMG_CODEC_H263_VBR:
case IMG_CODEC_H263_CBR:
RegVal |= F_ENCODE(0, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(0, MVEA_CR_IPE_ENCODING_FORMAT);
break;
case IMG_CODEC_MPEG4_NO_RC:
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_MPEG4_CBR:
RegVal |= F_ENCODE(1, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(1, MVEA_CR_IPE_ENCODING_FORMAT);
default:
break;
case IMG_CODEC_H264_NO_RC:
case IMG_CODEC_H264_VBR:
case IMG_CODEC_H264_CBR:
case IMG_CODEC_H264_VCM:
RegVal |= F_ENCODE(2, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(2, MVEA_CR_IPE_ENCODING_FORMAT);
break;
}
RegVal |= F_ENCODE(6, MVEA_CR_IPE_Y_CANDIDATE_NUM);
return RegVal;
}
void tng__setup_enc_profile_features(context_ENC_p ctx, IMG_UINT32 ui32EncProfile)
{
IMG_ENCODE_FEATURES * pEncFeatures = &ctx->sEncFeatures;
/* Set the default values first */
pEncFeatures->bDisableBPicRef_0 = IMG_FALSE;
pEncFeatures->bDisableBPicRef_1 = IMG_FALSE;
pEncFeatures->bDisableInter8x8 = IMG_FALSE;
pEncFeatures->bRestrictInter4x4 = IMG_FALSE;
pEncFeatures->bDisableIntra4x4 = IMG_FALSE;
pEncFeatures->bDisableIntra8x8 = IMG_FALSE;
pEncFeatures->bDisableIntra16x16 = IMG_FALSE;
pEncFeatures->bEnable8x16MVDetect = IMG_TRUE;
pEncFeatures->bEnable16x8MVDetect = IMG_TRUE;
pEncFeatures->bDisableBFrames = IMG_FALSE;
pEncFeatures->eMinBlkSz = BLK_SZ_DEFAULT;
switch (ui32EncProfile) {
case ENC_PROFILE_LOWCOMPLEXITY:
pEncFeatures->bDisableInter8x8 = IMG_TRUE;
pEncFeatures->bRestrictInter4x4 = IMG_TRUE;
pEncFeatures->bDisableIntra4x4 = IMG_TRUE;
pEncFeatures->bDisableIntra8x8 = IMG_TRUE;
pEncFeatures->bRestrictInter4x4 = IMG_TRUE;
pEncFeatures->eMinBlkSz = BLK_SZ_16x16;
pEncFeatures->bDisableBFrames = IMG_TRUE;
break;
case ENC_PROFILE_HIGHCOMPLEXITY:
pEncFeatures->bDisableBPicRef_0 = IMG_FALSE;
pEncFeatures->bDisableBPicRef_1 = IMG_FALSE;
pEncFeatures->bDisableInter8x8 = IMG_FALSE;
pEncFeatures->bRestrictInter4x4 = IMG_FALSE;
pEncFeatures->bDisableIntra4x4 = IMG_FALSE;
pEncFeatures->bDisableIntra8x8 = IMG_FALSE;
pEncFeatures->bDisableIntra16x16 = IMG_FALSE;
pEncFeatures->bEnable8x16MVDetect = IMG_TRUE;
pEncFeatures->bEnable16x8MVDetect = IMG_TRUE;
break;
}
if (ctx->eStandard != IMG_STANDARD_H264) {
pEncFeatures->bEnable8x16MVDetect = IMG_FALSE;
pEncFeatures->bEnable16x8MVDetect = IMG_FALSE;
}
return;
}
VAStatus tng__patch_hw_profile(context_ENC_p ctx)
{
IMG_UINT32 ui32IPEControl = 0;
IMG_UINT32 ui32PredCombControl = 0;
IMG_ENCODE_FEATURES * psEncFeatures = &(ctx->sEncFeatures);
// bDisableIntra4x4
if (psEncFeatures->bDisableIntra4x4)
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTRA4X4_DISABLE);
//bDisableIntra8x8
if (psEncFeatures->bDisableIntra8x8)
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTRA8X8_DISABLE);
//bDisableIntra16x16, check if atleast one of the other Intra mode is enabled
if ((psEncFeatures->bDisableIntra16x16) &&
(!(psEncFeatures->bDisableIntra8x8) || !(psEncFeatures->bDisableIntra4x4))) {
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTRA16X16_DISABLE);
}
if (psEncFeatures->bRestrictInter4x4) {
// ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTER4X4_RESTRICT);
ui32IPEControl |= F_ENCODE(1, TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION);
}
if (psEncFeatures->bDisableInter8x8)
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTER8X8_DISABLE);
if (psEncFeatures->bDisableBPicRef_1)
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_B_PIC1_DISABLE);
else if (psEncFeatures->bDisableBPicRef_0)
ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_B_PIC0_DISABLE);
// save predictor combiner control in video encode parameter set
ctx->ui32PredCombControl = ui32PredCombControl;
// set blocksize
ui32IPEControl |= F_ENCODE(psEncFeatures->eMinBlkSz, TOPAZHP_CR_IPE_BLOCKSIZE);
if (psEncFeatures->bEnable8x16MVDetect)
ui32IPEControl |= F_ENCODE(1, TOPAZHP_CR_IPE_8X16_ENABLE);
if (psEncFeatures->bEnable16x8MVDetect)
ui32IPEControl |= F_ENCODE(1, TOPAZHP_CR_IPE_16X8_ENABLE);
if (psEncFeatures->bDisableBFrames)
ctx->sRCParams.ui16BFrames = 0;
//save IPE-control register
ctx->ui32IPEControl = ui32IPEControl;
return VA_STATUS_SUCCESS;
}
#ifdef _TOPAZHP_CMDBUF_
static void tng__trace_cmdbuf(tng_cmdbuf_p cmdbuf, int idx)
{
IMG_UINT32 ui32CmdTmp[4];
IMG_UINT32 *ptmp = (IMG_UINT32 *)(cmdbuf->cmd_start);
IMG_UINT32 *pend = (IMG_UINT32 *)(cmdbuf->cmd_idx);
IMG_UINT32 ui32Len;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start, stream (%d), ptmp (0x%08x), pend (0x%08x}\n", __FUNCTION__, idx, (unsigned int)ptmp, (unsigned int)pend);
if (idx)
return ;
while (ptmp < pend) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: ptmp (0x%08x}\n", __FUNCTION__, *ptmp);
if ((*ptmp & 0x7f) == MTX_CMDID_SW_NEW_CODEC) {
ptmp += 4;
} else if ((*ptmp & 0x7f) == MTX_CMDID_SW_LEAVE_LOWPOWER) {
ptmp += 2;
} else if ((*ptmp & 0x7f) == MTX_CMDID_SW_WRITEREG) {
ui32Len = *(++ptmp);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: len = %d\n", __FUNCTION__, ui32Len);
ptmp += (ui32Len * 3) + 1;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: reg ptmp (0x%08x}\n", __FUNCTION__, *ptmp);
} else if ((*ptmp & 0x7f) == MTX_CMDID_DO_HEADER) {
ui32CmdTmp[0] = *ptmp++;
ui32CmdTmp[1] = *ptmp++;
ui32CmdTmp[2] = *ptmp++;
ui32CmdTmp[3] = 0;
//topazhp_dump_command((unsigned int*)ui32CmdTmp);
ptmp += 2;
} else if (
((*ptmp & 0x7f) == MTX_CMDID_SETVIDEO)||
((*ptmp & 0x7f) == MTX_CMDID_SHUTDOWN)) {
ui32CmdTmp[0] = *ptmp++;
ui32CmdTmp[1] = *ptmp++;
ui32CmdTmp[2] = *ptmp++;
ui32CmdTmp[3] = *ptmp++;
//topazhp_dump_command((unsigned int*)ui32CmdTmp);
} else if (
((*ptmp & 0x7f) == MTX_CMDID_PROVIDE_SOURCE_BUFFER) ||
((*ptmp & 0x7f) == MTX_CMDID_PROVIDE_REF_BUFFER) ||
((*ptmp & 0x7f) == MTX_CMDID_PROVIDE_CODED_BUFFER) ||
((*ptmp & 0x7f) == MTX_CMDID_PICMGMT) ||
((*ptmp & 0x7f) == MTX_CMDID_ENCODE_FRAME)) {
ui32CmdTmp[0] = *ptmp++;
ui32CmdTmp[1] = *ptmp++;
ui32CmdTmp[2] = *ptmp++;
ui32CmdTmp[3] = 0;
//topazhp_dump_command((unsigned int*)ui32CmdTmp);
} else {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: error leave lowpower = 0x%08x\n", __FUNCTION__, *ptmp++);
}
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n", __FUNCTION__);
return ;
}
#endif
void tng_DestroyContext(object_context_p obj_context, unsigned char is_JPEG)
{
context_ENC_p ctx;
// tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
ctx = (context_ENC_p)obj_context->format_data;
FRAME_ORDER_INFO *psFrameInfo = &(ctx->sFrameOrderInfo);
if (psFrameInfo->slot_consume_dpy_order != NULL)
free(psFrameInfo->slot_consume_dpy_order);
if (psFrameInfo->slot_consume_enc_order != NULL)
free(psFrameInfo->slot_consume_enc_order);
tng_air_buf_free(ctx);
tng__free_context_buffer(ctx, is_JPEG, 0);
if (ctx->bEnableMVC)
tng__free_context_buffer(ctx, is_JPEG, 1);
free(obj_context->format_data);
obj_context->format_data = NULL;
}
static VAStatus tng__init_rc_params(context_ENC_p ctx, object_config_p obj_config)
{
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
unsigned int eRCmode = 0;
memset(psRCParams, 0, sizeof(IMG_RC_PARAMS));
IMG_INT32 i;
//set RC mode
for (i = 0; i < obj_config->attrib_count; i++) {
if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
break;
}
if (i >= obj_config->attrib_count) {
eRCmode = VA_RC_NONE;
} else {
eRCmode = obj_config->attrib_list[i].value;
}
ctx->sRCParams.bRCEnable = IMG_TRUE;
ctx->sRCParams.bDisableBitStuffing = IMG_FALSE;
if (eRCmode == VA_RC_NONE) {
ctx->sRCParams.bRCEnable = IMG_FALSE;
ctx->sRCParams.eRCMode = IMG_RCMODE_NONE;
} else if (eRCmode == VA_RC_CBR) {
ctx->sRCParams.eRCMode = IMG_RCMODE_CBR;
} else if (eRCmode == VA_RC_VBR) {
ctx->sRCParams.eRCMode = IMG_RCMODE_VBR;
} else if (eRCmode == VA_RC_VCM) {
ctx->sRCParams.eRCMode = IMG_RCMODE_VCM;
} else {
ctx->sRCParams.bRCEnable = IMG_FALSE;
drv_debug_msg(VIDEO_DEBUG_ERROR, "not support this RT Format\n");
return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
}
psRCParams->bScDetectDisable = IMG_FALSE;
psRCParams->ui32SliceByteLimit = 0;
psRCParams->ui32SliceMBLimit = 0;
psRCParams->bIsH264Codec = (ctx->eStandard == IMG_STANDARD_H264) ? IMG_TRUE : IMG_FALSE;
return VA_STATUS_SUCCESS;
}
/**************************************************************************************************
* Function: IMG_C_GetEncoderCaps
* Description: Get the capabilities of the encoder for the given codec
*
***************************************************************************************************/
//FIXME
static const IMG_UINT32 g_ui32PipesAvailable = TOPAZHP_PIPE_NUM;
static const IMG_UINT32 g_ui32CoreDes1 = TOPAZHP_PIPE_NUM;
static const IMG_UINT32 g_ui32CoreRev = 0x00030401;
static IMG_UINT32 tng__get_num_pipes()
{
return g_ui32PipesAvailable;
}
static IMG_UINT32 tng__get_core_des1()
{
return g_ui32CoreDes1;
}
static IMG_UINT32 tng__get_core_rev()
{
return g_ui32CoreRev;
}
static VAStatus tng__get_encoder_caps(context_ENC_p ctx)
{
IMG_ENC_CAPS *psCaps = &(ctx->sCapsParams);
IMG_UINT16 ui16Height = ctx->ui16FrameHeight;
IMG_UINT32 ui32NumCores = 0;
IMG_UINT16 ui16MBRows = 0; //MB Rows in a GOB(slice);
ctx->ui32CoreRev = tng__get_core_rev();
psCaps->ui32CoreFeatures = tng__get_core_des1();
/* get the actual number of cores */
ui32NumCores = tng__get_num_pipes();
switch (ctx->eStandard) {
case IMG_STANDARD_JPEG:
psCaps->ui16MaxSlices = ui16Height / 8;
psCaps->ui16MinSlices = 1;
psCaps->ui16RecommendedSlices = ui32NumCores;
break;
case IMG_STANDARD_H264:
psCaps->ui16MaxSlices = ui16Height / 16;
psCaps->ui16MinSlices = 1;
psCaps->ui16RecommendedSlices = ui32NumCores;
break;
case IMG_STANDARD_MPEG2:
psCaps->ui16MaxSlices = 174; // Slice labelling dictates a maximum of 174 slices
psCaps->ui16MinSlices = 1;
psCaps->ui16RecommendedSlices = (ui16Height + 15) / 16;
break;
case IMG_STANDARD_H263:
// if the original height of the pic is less than 400 , k is 1. refer standard.
if (ui16Height <= 400) {
ui16MBRows = 1;
} else if (ui16Height < 800) { // if between 400 and 800 it's 2.
ui16MBRows = 2;
} else {
ui16MBRows = 4;
}
// before rounding is done for the height.
// get the GOB's based on this MB Rows and not vice-versa.
psCaps->ui16RecommendedSlices = (ui16Height + 15) >> (4 + (ui16MBRows >> 1));
psCaps->ui16MaxSlices = psCaps->ui16MinSlices = psCaps->ui16RecommendedSlices;
break;
case IMG_STANDARD_MPEG4:
psCaps->ui16MaxSlices = 1;
psCaps->ui16MinSlices = 1;
psCaps->ui16RecommendedSlices = 1;
break;
default:
break;
}
return VA_STATUS_SUCCESS;
}
static VAStatus tng__init_context(context_ENC_p ctx)
{
VAStatus vaStatus = 0;
/* Mostly sure about the following video parameters */
//ctx->ui32HWProfile = pParams->ui32HWProfile;
ctx->ui32FrameCount[0] = ctx->ui32FrameCount[1] = 0;
/* Using Extended parameters */
ctx->ui8PipesToUse = (IMG_UINT8)(tng__get_num_pipes() & (IMG_UINT32)0xff);
//carc params
ctx->sCARCParams.bCARC = 0;
ctx->sCARCParams.i32CARCBaseline = 0;
ctx->sCARCParams.ui32CARCThreshold = TOPAZHP_DEFAULT_uCARCThreshold;
ctx->sCARCParams.ui32CARCCutoff = TOPAZHP_DEFAULT_uCARCCutoff;
ctx->sCARCParams.ui32CARCNegRange = TOPAZHP_DEFAULT_uCARCNegRange;
ctx->sCARCParams.ui32CARCNegScale = TOPAZHP_DEFAULT_uCARCNegScale;
ctx->sCARCParams.ui32CARCPosRange = TOPAZHP_DEFAULT_uCARCPosRange;
ctx->sCARCParams.ui32CARCPosScale = TOPAZHP_DEFAULT_uCARCPosScale;
ctx->sCARCParams.ui32CARCShift = TOPAZHP_DEFAULT_uCARCShift;
ctx->bUseDefaultScalingList = IMG_FALSE;
ctx->ui32CabacBinLimit = TOPAZHP_DEFAULT_uCABACBinLimit; //This parameter need not be exposed
if (ctx->ui32CabacBinLimit == 0)
ctx->ui32CabacBinFlex = 0;//This parameter need not be exposed
else
ctx->ui32CabacBinFlex = TOPAZHP_DEFAULT_uCABACBinFlex;//This parameter need not be exposed
ctx->ui32FCode = 4; //This parameter need not be exposed
ctx->iFineYSearchSize = 2;//This parameter need not be exposed
ctx->ui32VopTimeResolution = 15;//This parameter need not be exposed
// ctx->bEnabledDynamicBPic = IMG_FALSE;//Related to Rate Control,which is no longer needed.
ctx->bH264IntraConstrained = IMG_FALSE;//This parameter need not be exposed
ctx->bEnableInpCtrl = IMG_FALSE;//This parameter need not be exposed
ctx->bEnableAIR = 0;
ctx->bEnableCIR = 0;
ctx->bEnableHostBias = (ctx->bEnableAIR != 0);//This parameter need not be exposed
ctx->bEnableHostQP = IMG_FALSE; //This parameter need not be exposed
ctx->ui8CodedSkippedIndex = 3;//This parameter need not be exposed
ctx->ui8InterIntraIndex = 3;//This parameter need not be exposed
ctx->uMaxChunks = 0xA0;//This parameter need not be exposed
ctx->uChunksPerMb = 0x40;//This parameter need not be exposed
ctx->uPriorityChunks = (0xA0 - 0x60);//This parameter need not be exposed
ctx->bWeightedPrediction = IMG_FALSE;//Weighted Prediction is not supported in TopazHP Version 3.0
ctx->ui8VPWeightedImplicitBiPred = 0;//Weighted Prediction is not supported in TopazHP Version 3.0
ctx->bSkipDuplicateVectors = IMG_FALSE;//By default false Newly Added
ctx->bEnableCumulativeBiases = IMG_FALSE;//By default false Newly Added
ctx->ui16UseCustomScalingLists = 0;//By default false Newly Added
ctx->bPpsScaling = IMG_FALSE;//By default false Newly Added
ctx->ui8MPEG2IntraDCPrecision = 0;//By default 0 Newly Added
ctx->uMBspS = 0;//By default 0 Newly Added
ctx->bMultiReferenceP = IMG_FALSE;//By default false Newly Added
ctx->ui8RefSpacing=0;//By default 0 Newly Added
ctx->bSpatialDirect = 0;//By default 0 Newly Added
ctx->ui32DebugCRCs = 0;//By default false Newly Added
ctx->bEnableMVC = IMG_FALSE;//By default false Newly Added
ctx->ui16MVCViewIdx = (IMG_UINT16)(NON_MVC_VIEW);//Newly Added
ctx->bSrcAllocInternally = IMG_FALSE;//By default false Newly Added
ctx->bCodedAllocInternally = IMG_FALSE;//By default true Newly Added
ctx->bHighLatency = IMG_TRUE;//Newly Added
ctx->i32NumAIRMBs = -1;
ctx->i32AIRThreshold = -1;
ctx->i16AIRSkipCnt = -1;
ctx->i32LastCIRIndex = -1;
//Need to check on the following parameters
ctx->ui8EnableSelStatsFlags = IMG_FALSE;//Default Value ?? Extended Parameter ??
ctx->bH2648x8Transform = IMG_FALSE;//Default Value ?? Extended Parameter or OMX_VIDEO_PARAM_AVCTYPE -> bDirect8x8Inference??
//FIXME: Zhaohan, eStandard is always 0 here.
ctx->bNoOffscreenMv = (ctx->eStandard == IMG_STANDARD_H263) ? IMG_TRUE : IMG_FALSE; //Default Value ?? Extended Parameter and bUseOffScreenMVUserSetting
ctx->bNoSequenceHeaders = IMG_FALSE;
ctx->bTopFieldFirst = IMG_TRUE;
ctx->sBiasTables.ui32FCode = ctx->ui32FCode;
ctx->ui32pseudo_rand_seed = UNINIT_PARAM;
ctx->bVPAdaptiveRoundingDisable = IMG_TRUE;
//Default fcode is 4
if (!ctx->sBiasTables.ui32FCode)
ctx->sBiasTables.ui32FCode = 4;
ctx->uiCbrBufferTenths = TOPAZHP_DEFAULT_uiCbrBufferTenths;
tng__setup_enc_profile_features(ctx, ENC_PROFILE_DEFAULT);
vaStatus = tng__patch_hw_profile(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__patch_hw_profile\n", __FUNCTION__);
}
return VA_STATUS_SUCCESS;
}
VAStatus tng_CreateContext(
object_context_p obj_context,
object_config_p obj_config,
unsigned char is_JPEG)
{
VAStatus vaStatus = 0;
unsigned short ui16Width, ui16Height;
context_ENC_p ctx;
ui16Width = obj_context->picture_width;
ui16Height = obj_context->picture_height;
ctx = (context_ENC_p) calloc(1, sizeof(struct context_ENC_s));
if (NULL == ctx) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
return vaStatus;
}
memset((void*)ctx, 0, sizeof(struct context_ENC_s));
obj_context->format_data = (void*) ctx;
ctx->obj_context = obj_context;
if (is_JPEG == 0) {
ctx->ui16Width = (unsigned short)(~0xf & (ui16Width + 0xf));
ctx->ui16FrameHeight = (unsigned short)(~0xf & (ui16Height + 0xf));
vaStatus = tng__init_context(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "init Context params");
}
vaStatus = tng__init_rc_params(ctx, obj_config);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "init rc params");
}
} else {
/*JPEG only require them are even*/
ctx->ui16Width = (unsigned short)(~0x1 & (ui16Width + 0x1));
ctx->ui16FrameHeight = (unsigned short)(~0x1 & (ui16Height + 0x1));
}
ctx->eFormat = IMG_CODEC_PL12; // use default
tng__setup_enc_profile_features(ctx, ENC_PROFILE_DEFAULT);
if (is_JPEG) {
vaStatus = tng__alloc_context_buffer(ctx, is_JPEG, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "setup enc profile");
}
}
return vaStatus;
}
VAStatus tng_BeginPicture(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
tng_cmdbuf_p cmdbuf;
int ret;
ctx->ui32StreamID = 0;
if (ctx->ui32RawFrameCount != 0)
ps_buf->previous_src_surface = ps_buf->src_surface;
ps_buf->src_surface = ctx->obj_context->current_render_target;
vaStatus = tng__get_encoder_caps(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__get_encoder_caps\n", __FUNCTION__);
}
/* clear frameskip flag to 0 */
CLEAR_SURFACE_INFO_skipped_flag(ps_buf->src_surface->psb_surface);
/* Initialise the command buffer */
ret = tng_context_get_next_cmdbuf(ctx->obj_context);
if (ret) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "get next cmdbuf fail\n");
vaStatus = VA_STATUS_ERROR_UNKNOWN;
return vaStatus;
}
cmdbuf = ctx->obj_context->tng_cmdbuf;
//FIXME
/* only map topaz param when necessary */
cmdbuf->topaz_in_params_I_p = NULL;
cmdbuf->topaz_in_params_P_p = NULL;
ctx->obj_context->slice_count = 0;
tng_cmdbuf_buffer_ref(cmdbuf, &(ctx->obj_context->current_render_target->psb_surface->buf));
return vaStatus;
}
static VAStatus tng__provide_buffer_BFrames(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
IMG_RC_PARAMS * psRCParams = &(ctx->sRCParams);
FRAME_ORDER_INFO *psFrameInfo = &(ctx->sFrameOrderInfo);
int slot_index = 0;
unsigned long long display_order = 0;
IMG_INT32 i32SlotBuf = (IMG_INT32)(psRCParams->ui16BFrames + 2);
IMG_UINT32 ui32SlotBuf = (IMG_UINT32)(psRCParams->ui16BFrames + 2);
IMG_UINT32 ui32FrameIdx = ctx->ui32FrameCount[ui32StreamIndex];
if (ui32StreamIndex == 0)
getFrameDpyOrder(ui32FrameIdx, psRCParams->ui16BFrames, ctx->ui32IntraCnt,
ctx->ui32IdrPeriod, psFrameInfo, &display_order);
slot_index = psFrameInfo->last_slot;
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: (int)ui32FrameIdx = %d, psRCParams->ui16BFrames = %d, psRCParams->ui32IntraFreq = %d, ctx->ui32IdrPeriod = %d\n",
__FUNCTION__, (int)ui32FrameIdx, (int)psRCParams->ui16BFrames, (int)psRCParams->ui32IntraFreq, ctx->ui32IdrPeriod);
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: last_slot = %d, last_frame_type = %d, display_order = %d\n",
__FUNCTION__, psFrameInfo->last_slot, psFrameInfo->last_frame_type, display_order);
if (ui32FrameIdx < ui32SlotBuf) {
if (ui32FrameIdx == 0) {
tng_send_source_frame(ctx, 0, 0);
} else if (ui32FrameIdx == 1) {
slot_index = 1;
do {
tng_send_source_frame(ctx, slot_index, slot_index);
++slot_index;
} while(slot_index < i32SlotBuf);
} else {
slot_index = ui32FrameIdx - 1;
tng_send_source_frame(ctx, slot_index, slot_index);
}
} else {
tng_send_source_frame(ctx, slot_index , display_order);
}
return VA_STATUS_SUCCESS;
}
VAStatus tng__provide_buffer_PFrames(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
IMG_UINT32 ui32FrameIdx = ctx->ui32FrameCount[ui32StreamIndex];
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: frame count = %d, SlotsInUse = %d, ui32FrameIdx = %d\n",
__FUNCTION__, (int)ui32FrameIdx, ctx->ui8SlotsInUse, ui32FrameIdx);
tng_send_source_frame(ctx, ctx->ui8SlotsCoded, ui32FrameIdx);
/*
if (ctx->ui32IntraCnt == 0)
ctx->eFrameType = IMG_INTRA_FRAME;
else
if (ui32FrameIdx % ctx->ui32IntraCnt == 0)
ctx->eFrameType = IMG_INTRA_FRAME;
else
ctx->eFrameType = IMG_INTER_P;
if (ctx->ui32IdrPeriod == 0) {
if (ui32FrameIdx == 0)
ctx->eFrameType = IMG_INTRA_IDR;
} else {
if (ctx->ui32IntraCnt == 0) {
if (ui32FrameIdx % ctx->ui32IdrPeriod == 0)
ctx->eFrameType = IMG_INTRA_IDR;
} else {
if (ui32FrameIdx % (ctx->ui32IntraCnt * ctx->ui32IdrPeriod) == 0)
ctx->eFrameType = IMG_INTRA_IDR;
}
}
*/
ctx->eFrameType = IMG_INTER_P;
if (ui32FrameIdx % ctx->ui32IntraCnt == 0)
ctx->eFrameType = IMG_INTRA_FRAME;
if (ui32FrameIdx % (ctx->ui32IdrPeriod * ctx->ui32IntraCnt) == 0)
ctx->eFrameType = IMG_INTRA_IDR;
drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: ctx->eFrameType = %d\n", __FUNCTION__, ctx->eFrameType);
return VA_STATUS_SUCCESS;
}
static IMG_UINT16 H264_ROUNDING_OFFSETS[18][4] = {
{ 683, 683, 683, 683 }, /* 0 I-Slice - INTRA4 LUMA */
{ 683, 683, 683, 683 }, /* 1 P-Slice - INTRA4 LUMA */
{ 683, 683, 683, 683 }, /* 2 B-Slice - INTRA4 LUMA */
{ 683, 683, 683, 683 }, /* 3 I-Slice - INTRA8 LUMA */
{ 683, 683, 683, 683 }, /* 4 P-Slice - INTRA8 LUMA */
{ 683, 683, 683, 683 }, /* 5 B-Slice - INTRA8 LUMA */
{ 341, 341, 341, 341 }, /* 6 P-Slice - INTER8 LUMA */
{ 341, 341, 341, 341 }, /* 7 B-Slice - INTER8 LUMA */
{ 683, 683, 683, 000 }, /* 8 I-Slice - INTRA16 LUMA */
{ 683, 683, 683, 000 }, /* 9 P-Slice - INTRA16 LUMA */
{ 683, 683, 683, 000 }, /* 10 B-Slice - INTRA16 LUMA */
{ 341, 341, 341, 341 }, /* 11 P-Slice - INTER16 LUMA */
{ 341, 341, 341, 341 }, /* 12 B-Slice - INTER16 LUMA */
{ 683, 683, 683, 000 }, /* 13 I-Slice - INTRA16 CHROMA */
{ 683, 683, 683, 000 }, /* 14 P-Slice - INTRA16 CHROMA */
{ 683, 683, 683, 000 }, /* 15 B-Slice - INTRA16 CHROMA */
{ 341, 341, 341, 000 }, /* 16 P-Slice - INTER16 CHROMA */
{ 341, 341, 341, 000 } /* 17 B-Slice - INTER16 CHROMA */
};
static IMG_UINT16 tng__create_gop_frame(
IMG_UINT8 * pui8Level, IMG_BOOL bReference,
IMG_UINT8 ui8Pos, IMG_UINT8 ui8Ref0Level,
IMG_UINT8 ui8Ref1Level, IMG_FRAME_TYPE eFrameType)
{
*pui8Level = ((ui8Ref0Level > ui8Ref1Level) ? ui8Ref0Level : ui8Ref1Level) + 1;
return F_ENCODE(bReference, GOP_REFERENCE) |
F_ENCODE(ui8Pos, GOP_POS) |
F_ENCODE(ui8Ref0Level, GOP_REF0) |
F_ENCODE(ui8Ref1Level, GOP_REF1) |
F_ENCODE(eFrameType, GOP_FRAMETYPE);
}
static void tng__minigop_generate_flat(void* buffer_p, IMG_UINT32 ui32BFrameCount, IMG_UINT32 ui32RefSpacing, IMG_UINT8 aui8PicOnLevel[])
{
/* B B B B P */
IMG_UINT8 ui8EncodeOrderPos;
IMG_UINT8 ui8Level;
IMG_UINT16 * psGopStructure = (IMG_UINT16 *)buffer_p;
psGopStructure[0] = tng__create_gop_frame(&ui8Level, IMG_TRUE, MAX_BFRAMES, ui32RefSpacing, 0, IMG_INTER_P);
aui8PicOnLevel[ui8Level]++;
for (ui8EncodeOrderPos = 1; ui8EncodeOrderPos < MAX_GOP_SIZE; ui8EncodeOrderPos++) {
psGopStructure[ui8EncodeOrderPos] = tng__create_gop_frame(&ui8Level, IMG_FALSE,
ui8EncodeOrderPos - 1, ui32RefSpacing, ui32RefSpacing + 1, IMG_INTER_B);
aui8PicOnLevel[ui8Level] = ui32BFrameCount;
}
for( ui8EncodeOrderPos = 0; ui8EncodeOrderPos < MAX_GOP_SIZE; ui8EncodeOrderPos++) {
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: psGopStructure = 0x%06x\n", __FUNCTION__, psGopStructure[ui8EncodeOrderPos]);
}
return ;
}
static void tng__gop_split(IMG_UINT16 ** pasGopStructure, IMG_INT8 i8Ref0, IMG_INT8 i8Ref1,
IMG_UINT8 ui8Ref0Level, IMG_UINT8 ui8Ref1Level, IMG_UINT8 aui8PicOnLevel[])
{
IMG_UINT8 ui8Distance = i8Ref1 - i8Ref0;
IMG_UINT8 ui8Position = i8Ref0 + (ui8Distance >> 1);
IMG_UINT8 ui8Level;
if (ui8Distance == 1)
return;
/* mark middle as this level */
(*pasGopStructure)++;
**pasGopStructure = tng__create_gop_frame(&ui8Level, ui8Distance >= 3, ui8Position, ui8Ref0Level, ui8Ref1Level, IMG_INTER_B);
aui8PicOnLevel[ui8Level]++;
if (ui8Distance >= 4)
tng__gop_split(pasGopStructure, i8Ref0, ui8Position, ui8Ref0Level, ui8Level, aui8PicOnLevel);
if (ui8Distance >= 3)
tng__gop_split(pasGopStructure, ui8Position, i8Ref1, ui8Level, ui8Ref1Level, aui8PicOnLevel);
}
static void tng_minigop_generate_hierarchical(void* buffer_p, IMG_UINT32 ui32BFrameCount,
IMG_UINT32 ui32RefSpacing, IMG_UINT8 aui8PicOnLevel[])
{
IMG_UINT8 ui8Level;
IMG_UINT16 * psGopStructure = (IMG_UINT16 *)buffer_p;
psGopStructure[0] = tng__create_gop_frame(&ui8Level, IMG_TRUE, ui32BFrameCount, ui32RefSpacing, 0, IMG_INTER_P);
aui8PicOnLevel[ui8Level]++;
tng__gop_split(&psGopStructure, -1, ui32BFrameCount, ui32RefSpacing, ui32RefSpacing + 1, aui8PicOnLevel);
}
static void tng__generate_scale_tables(IMG_MTX_VIDEO_CONTEXT* psMtxEncCtx)
{
psMtxEncCtx->ui32InterIntraScale[0] = 0x0004; // Force intra by scaling its cost by 0
psMtxEncCtx->ui32InterIntraScale[1] = 0x0103; // favour intra by a factor 3
psMtxEncCtx->ui32InterIntraScale[2] = 0x0102; // favour intra by a factor 2
psMtxEncCtx->ui32InterIntraScale[3] = 0x0101; // no bias
psMtxEncCtx->ui32InterIntraScale[4] = 0x0101; // no bias
psMtxEncCtx->ui32InterIntraScale[5] = 0x0201; // favour inter by a factor 2
psMtxEncCtx->ui32InterIntraScale[6] = 0x0301; // favour inter by a factor 3
psMtxEncCtx->ui32InterIntraScale[7] = 0x0400; // Force inter by scaling it's cost by 0
psMtxEncCtx->ui32SkippedCodedScale[0] = 0x0004; // Force coded by scaling its cost by 0
psMtxEncCtx->ui32SkippedCodedScale[1] = 0x0103; // favour coded by a factor 3
psMtxEncCtx->ui32SkippedCodedScale[2] = 0x0102; // favour coded by a factor 2
psMtxEncCtx->ui32SkippedCodedScale[3] = 0x0101; // no bias
psMtxEncCtx->ui32SkippedCodedScale[4] = 0x0101; // no bias
psMtxEncCtx->ui32SkippedCodedScale[5] = 0x0201; // favour skipped by a factor 2
psMtxEncCtx->ui32SkippedCodedScale[6] = 0x0301; // favour skipped by a factor 3
psMtxEncCtx->ui32SkippedCodedScale[7] = 0x0400; // Force skipped by scaling it's cost by 0
return ;
}
/*!
******************************************************************************
@Function tng_update_driver_mv_scaling
@details
Setup the registers for scaling candidate motion vectors to take into account
how far away (temporally) the reference pictures are
******************************************************************************/
static IMG_INT tng__abs(IMG_INT a)
{
if (a < 0)
return -a;
else
return a;
}
static IMG_INT tng__abs32(IMG_INT32 a)
{
if (a < 0)
return -a;
else
return a;
}
void tng_update_driver_mv_scaling(
IMG_UINT32 uFrameNum,
IMG_UINT32 uRef0Num,
IMG_UINT32 uRef1Num,
IMG_UINT32 ui32PicFlags,
IMG_BOOL bSkipDuplicateVectors,
IMG_UINT32 * pui32MVCalc_Below,
IMG_UINT32 * pui32MVCalc_Colocated,
IMG_UINT32 * pui32MVCalc_Config)
{
IMG_UINT32 uMvCalcConfig = 0;
IMG_UINT32 uMvCalcColocated = F_ENCODE(0x10, TOPAZHP_CR_TEMPORAL_BLEND);
IMG_UINT32 uMvCalcBelow = 0;
//If b picture calculate scaling factor for colocated motion vectors
if (ui32PicFlags & ISINTERB_FLAGS) {
IMG_INT tb, td, tx;
IMG_INT iDistScale;
//calculation taken from H264 spec
tb = (uFrameNum * 2) - (uRef1Num * 2);
td = (uRef0Num * 2) - (uRef1Num * 2);
tx = (16384 + tng__abs(td / 2)) / td;
iDistScale = (tb * tx + 32) >> 6;
if (iDistScale > 1023) iDistScale = 1023;
if (iDistScale < -1024) iDistScale = -1024;
uMvCalcColocated |= F_ENCODE(iDistScale, TOPAZHP_CR_COL_DIST_SCALE_FACT);
//We assume the below temporal mvs are from the latest reference frame
//rather then the most recently encoded B frame (as Bs aren't reference)
//Fwd temporal is same as colocated mv scale
uMvCalcBelow |= F_ENCODE(iDistScale, TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR);
//Bkwd temporal needs to be scaled by the recipricol amount in the other direction
tb = (uFrameNum * 2) - (uRef0Num * 2);
td = (uRef0Num * 2) - (uRef1Num * 2);
tx = (16384 + tng__abs(td / 2)) / td;
iDistScale = (tb * tx + 32) >> 6;
if (iDistScale > 1023) iDistScale = 1023;
if (iDistScale < -1024) iDistScale = -1024;
uMvCalcBelow |= F_ENCODE(iDistScale, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR);
} else {
//Don't scale the temporal below mvs
uMvCalcBelow |= F_ENCODE(1 << 8, TOPAZHP_CR_PIC0_DIST_SCALE_FACTOR);
if (uRef0Num != uRef1Num) {
IMG_INT iRef0Dist, iRef1Dist;
IMG_INT iScale;
//Distance to second reference picture may be different when
//using multiple reference frames on P. Scale based on difference
//in temporal distance to ref pic 1 compared to distance to ref pic 0
iRef0Dist = (uFrameNum - uRef0Num);
iRef1Dist = (uFrameNum - uRef1Num);
iScale = (iRef1Dist << 8) / iRef0Dist;
if (iScale > 1023) iScale = 1023;
if (iScale < -1024) iScale = -1024;
uMvCalcBelow |= F_ENCODE(iScale, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR);
} else
uMvCalcBelow |= F_ENCODE(1 << 8, TOPAZHP_CR_PIC1_DIST_SCALE_FACTOR);
}
if (uFrameNum > 0) {
IMG_INT ref0_distance, ref1_distance;
IMG_INT jitter0, jitter1;
ref0_distance = tng__abs32((IMG_INT32)uFrameNum - (IMG_INT32)uRef0Num);
ref1_distance = tng__abs32((IMG_INT32)uFrameNum - (IMG_INT32)uRef1Num);
if (!(ui32PicFlags & ISINTERB_FLAGS)) {
jitter0 = ref0_distance * 1;
jitter1 = jitter0 > 1 ? 1 : 2;
} else {
jitter0 = ref1_distance * 1;
jitter1 = ref0_distance * 1;
}
//Hardware can only cope with 1 - 4 jitter factors
jitter0 = (jitter0 > 4) ? 4 : (jitter0 < 1) ? 1 : jitter0;
jitter1 = (jitter1 > 4) ? 4 : (jitter1 < 1) ? 1 : jitter1;
//Hardware can only cope with 1 - 4 jitter factors
assert(jitter0 > 0 && jitter0 <= 4 && jitter1 > 0 && jitter1 <= 4);
uMvCalcConfig |= F_ENCODE(jitter0 - 1, TOPAZHP_CR_MVCALC_IPE0_JITTER_FACTOR) |
F_ENCODE(jitter1 - 1, TOPAZHP_CR_MVCALC_IPE1_JITTER_FACTOR);
}
uMvCalcConfig |= F_ENCODE(1, TOPAZHP_CR_MVCALC_DUP_VEC_MARGIN);
uMvCalcConfig |= F_ENCODE(7, TOPAZHP_CR_MVCALC_GRID_MB_X_STEP);
uMvCalcConfig |= F_ENCODE(13, TOPAZHP_CR_MVCALC_GRID_MB_Y_STEP);
uMvCalcConfig |= F_ENCODE(3, TOPAZHP_CR_MVCALC_GRID_SUB_STEP);
uMvCalcConfig |= F_ENCODE(1, TOPAZHP_CR_MVCALC_GRID_DISABLE);
if (bSkipDuplicateVectors)
uMvCalcConfig |= F_ENCODE(1, TOPAZHP_CR_MVCALC_NO_PSEUDO_DUPLICATES);
* pui32MVCalc_Below = uMvCalcBelow;
* pui32MVCalc_Colocated = uMvCalcColocated;
* pui32MVCalc_Config = uMvCalcConfig;
}
static void tng__prepare_mv_estimates(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem* ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
IMG_MTX_VIDEO_CONTEXT* psMtxEncCtx = NULL;
IMG_UINT32 ui32Distance;
psb_buffer_map(&(ps_mem->bufs_mtx_context), &(ps_mem->bufs_mtx_context.virtual_addr));
if (ps_mem->bufs_mtx_context.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping mtx context\n", __FUNCTION__);
return ;
}
psMtxEncCtx = (IMG_MTX_VIDEO_CONTEXT*)(ps_mem->bufs_mtx_context.virtual_addr);
/* IDR */
psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Config = DEFAULT_MVCALC_CONFIG; // default based on TRM
psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Colocated = 0x00100100;// default based on TRM
psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Below = 0x01000100; // default based on TRM
tng_update_driver_mv_scaling(
0, 0, 0, 0, IMG_FALSE, //psMtxEncCtx->bSkipDuplicateVectors, //By default false Newly Added
&psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Below,
&psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Colocated,
&psMtxEncCtx->sMVSettingsIdr.ui32MVCalc_Config);
/* NonB (I or P) */
for (ui32Distance = 1; ui32Distance <= MAX_BFRAMES + 1; ui32Distance++) {
psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Config = DEFAULT_MVCALC_CONFIG; // default based on TRM
psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Colocated = 0x00100100;// default based on TRM
psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Below = 0x01000100; // default based on TRM
tng_update_driver_mv_scaling(ui32Distance, 0, 0, 0, IMG_FALSE, //psMtxEncCtx->bSkipDuplicateVectors,
&psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Below,
&psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Colocated,
&psMtxEncCtx->sMVSettingsNonB[ui32Distance - 1].ui32MVCalc_Config);
}
{
IMG_UINT32 ui32DistanceB;
IMG_UINT32 ui32Position;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
IMG_MV_SETTINGS *pHostMVSettingsHierarchical = NULL;
IMG_MV_SETTINGS *pMvElement = NULL;
IMG_MV_SETTINGS *pHostMVSettingsBTable = NULL;
psb_buffer_map(&(ps_mem->bufs_mv_setting_btable), &(ps_mem->bufs_mv_setting_btable.virtual_addr));
if (ps_mem->bufs_mv_setting_btable.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping mv setting btable\n", __FUNCTION__);
return ;
}
pHostMVSettingsBTable = (IMG_MV_SETTINGS *)(ps_mem->bufs_mv_setting_btable.virtual_addr);
for (ui32DistanceB = 0; ui32DistanceB < MAX_BFRAMES; ui32DistanceB++) {
for (ui32Position = 1; ui32Position <= ui32DistanceB + 1; ui32Position++) {
pMvElement = (IMG_MV_SETTINGS * ) ((IMG_UINT8 *) pHostMVSettingsBTable + MV_OFFSET_IN_TABLE(ui32DistanceB, ui32Position - 1));
pMvElement->ui32MVCalc_Config= (DEFAULT_MVCALC_CONFIG|MASK_TOPAZHP_CR_MVCALC_GRID_DISABLE); // default based on TRM
pMvElement->ui32MVCalc_Colocated=0x00100100;// default based on TRM
pMvElement->ui32MVCalc_Below=0x01000100; // default based on TRM
tng_update_driver_mv_scaling(
ui32Position, ui32DistanceB + 2, 0, ISINTERB_FLAGS, IMG_FALSE,
&pMvElement->ui32MVCalc_Below,
&pMvElement->ui32MVCalc_Colocated,
&pMvElement->ui32MVCalc_Config);
}
}
if (ctx->b_is_mv_setting_hierar){
pHostMVSettingsHierarchical = (IMG_MV_SETTINGS *)(ps_mem->bufs_mv_setting_hierar.virtual_addr);
for (ui32DistanceB = 0; ui32DistanceB < MAX_BFRAMES; ui32DistanceB++) {
pMvElement = (IMG_MV_SETTINGS * ) ((IMG_UINT8 *)pHostMVSettingsBTable + MV_OFFSET_IN_TABLE(ui32DistanceB, ui32DistanceB >> 1));
//memcpy(pHostMVSettingsHierarchical + ui32DistanceB, , sizeof(IMG_MV_SETTINGS));
pHostMVSettingsHierarchical[ui32DistanceB].ui32MVCalc_Config = pMvElement->ui32MVCalc_Config;
pHostMVSettingsHierarchical[ui32DistanceB].ui32MVCalc_Colocated = pMvElement->ui32MVCalc_Colocated;
pHostMVSettingsHierarchical[ui32DistanceB].ui32MVCalc_Below = pMvElement->ui32MVCalc_Below;
}
}
psb_buffer_unmap(&(ps_mem->bufs_mv_setting_btable));
}
psb_buffer_unmap(&(ps_mem->bufs_mtx_context));
return ;
}
static void tng__adjust_picflags(
context_ENC_p ctx,
IMG_RC_PARAMS * psRCParams,
IMG_BOOL bFirstPic,
IMG_UINT32 * pui32Flags)
{
IMG_UINT32 ui32Flags;
PIC_PARAMS * psPicParams = &ctx->sPicParams;
ui32Flags = psPicParams->ui32Flags;
if (!psRCParams->bRCEnable || (!bFirstPic))
ui32Flags = 0;
switch (ctx->eStandard) {
case IMG_STANDARD_NONE:
break;
case IMG_STANDARD_H264:
break;
case IMG_STANDARD_H263:
ui32Flags |= ISH263_FLAGS;
break;
case IMG_STANDARD_MPEG4:
ui32Flags |= ISMPEG4_FLAGS;
break;
case IMG_STANDARD_MPEG2:
ui32Flags |= ISMPEG2_FLAGS;
break;
default:
break;
}
* pui32Flags = ui32Flags;
}
#define gbLowLatency 0
static void tng__setup_rcdata(context_ENC_p ctx)
{
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
PIC_PARAMS *psPicParams = &(ctx->sPicParams);
IMG_INT32 i32FrameRate, i32TmpQp;
double L1, L2, L3,L4, L5, L6, flBpp;
IMG_INT32 i32BufferSizeInFrames;
if (ctx->bInsertHRDParams &&
(ctx->eStandard == IMG_STANDARD_H264)) {
psRCParams->ui32BufferSize = ctx->buffer_size;
psRCParams->i32InitialLevel = ctx->buffer_size - ctx->initial_buffer_fullness;
psRCParams->i32InitialDelay = ctx->initial_buffer_fullness;
}
// If Bit Rate and Basic Units are not specified then set to default values.
if (psRCParams->ui32BitsPerSecond == 0 && !ctx->bEnableMVC) {
psRCParams->ui32BitsPerSecond = 640000; // kbps
}
if (!psRCParams->ui32BUSize) {
psRCParams->ui32BUSize = (ctx->ui16PictureHeight>>4) * (ctx->ui16Width>>4); // BU = 1 Frame
}
if (!psRCParams->ui32FrameRate) {
psRCParams->ui32FrameRate = 30; // fps
}
// Calculate Bits Per Pixel
if (ctx->ui16Width <= 176 ) {
i32FrameRate = 30;
} else {
i32FrameRate = psRCParams->ui32FrameRate;
}
flBpp = 1.0 * psRCParams->ui32BitsPerSecond / (i32FrameRate * ctx->ui16Width * ctx->ui16FrameHeight);
psPicParams->sInParams.ui8SeInitQP = psRCParams->ui32InitialQp;
psPicParams->sInParams.ui8MBPerRow = (ctx->ui16Width>>4);
psPicParams->sInParams.ui16MBPerBU = psRCParams->ui32BUSize;
psPicParams->sInParams.ui16MBPerFrm = (ctx->ui16Width>>4) * (ctx->ui16PictureHeight>>4);
psPicParams->sInParams.ui16BUPerFrm = (psPicParams->sInParams.ui16MBPerFrm) / psRCParams->ui32BUSize;
psPicParams->sInParams.ui16IntraPeriod = psRCParams->ui32IntraFreq;
psPicParams->sInParams.ui16BFrames = psRCParams->ui16BFrames;
psPicParams->sInParams.i32BitRate = psRCParams->ui32BitsPerSecond;
psPicParams->sInParams.bFrmSkipDisable = psRCParams->bDisableFrameSkipping;
psPicParams->sInParams.i32BitsPerFrm = (psRCParams->ui32BitsPerSecond + psRCParams->ui32FrameRate/2) / psRCParams->ui32FrameRate;
psPicParams->sInParams.i32BitsPerBU = psPicParams->sInParams.i32BitsPerFrm / (4 * psPicParams->sInParams.ui16BUPerFrm);
// Codec-dependant fields
if (ctx->eStandard == IMG_STANDARD_H264) {
psPicParams->sInParams.mode.h264.i32TransferRate = (psRCParams->ui32TransferBitsPerSecond + psRCParams->ui32FrameRate/2) / psRCParams->ui32FrameRate;
psPicParams->sInParams.mode.h264.bHierarchicalMode = psRCParams->b16Hierarchical;
} else {
psPicParams->sInParams.mode.other.i32BitsPerGOP = (psRCParams->ui32BitsPerSecond / psRCParams->ui32FrameRate) * psRCParams->ui32IntraFreq;
psPicParams->sInParams.mode.other.ui16AvQPVal = psRCParams->ui32InitialQp;
psPicParams->sInParams.mode.other.ui16MyInitQP = psRCParams->ui32InitialQp;
}
if (psPicParams->sInParams.i32BitsPerFrm) {
i32BufferSizeInFrames = (psRCParams->ui32BufferSize + (psPicParams->sInParams.i32BitsPerFrm/2))/psPicParams->sInParams.i32BitsPerFrm;
} else {
IMG_ASSERT(ctx->bEnableMvc && "Can happen only in MVC mode");
/* Asigning more or less `normal` value. To be overriden by MVC RC module */
i32BufferSizeInFrames = 30;
}
// select thresholds and initial Qps etc that are codec dependent
switch (ctx->eStandard) {
case IMG_STANDARD_H264:
L1 = 0.1; L2 = 0.15; L3 = 0.2;
psPicParams->sInParams.ui8MaxQPVal = 51;
ctx->ui32KickSize = psPicParams->sInParams.ui16MBPerBU;
// Setup MAX and MIN Quant Values
if (psRCParams->iMinQP == 0) {
if (flBpp >= 0.50)
i32TmpQp = 4;
else if (flBpp > 0.133)
i32TmpQp = (IMG_INT32)(22 - (40*flBpp));
else
i32TmpQp = (IMG_INT32)(30 - (100 * flBpp));
/* Adjust minQp up for small buffer size and down for large buffer size */
if (i32BufferSizeInFrames < 5) {
i32TmpQp += 2;
}
if (i32BufferSizeInFrames > 40) {
if(i32TmpQp>=1)
i32TmpQp -= 1;
}
/* for HD content allow a lower minQp as bitrate is more easily controlled in this case */
if (psPicParams->sInParams.ui16MBPerFrm > 2000) {
i32TmpQp -= 6;
}
} else
i32TmpQp = psRCParams->iMinQP;
if (i32TmpQp < 2) {
psPicParams->sInParams.ui8MinQPVal = 2;
} else {
psPicParams->sInParams.ui8MinQPVal = i32TmpQp;
}
// Calculate Initial QP if it has not been specified
i32TmpQp = psPicParams->sInParams.ui8SeInitQP;
if (psPicParams->sInParams.ui8SeInitQP==0) {
L1 = 0.050568;
L2 = 0.202272;
L3 = 0.40454321;
L4 = 0.80908642;
L5 = 1.011358025;
if (flBpp < L1)
i32TmpQp = (IMG_INT32)(45 - 78.10*flBpp);
else if (flBpp>=L1 && flBpp<L2)
i32TmpQp = (IMG_INT32)(44 - 72.51*flBpp);
else if (flBpp>=L2 && flBpp<L3)
i32TmpQp = (IMG_INT32)(34 - 24.72*flBpp);
else if (flBpp>=L3 && flBpp<L4)
i32TmpQp = (IMG_INT32)(32 - 19.78*flBpp);
else if (flBpp>=L4 && flBpp<L5)
i32TmpQp = (IMG_INT32)(25 - 9.89*flBpp);
else if (flBpp>=L5)
i32TmpQp = (IMG_INT32)(18 - 4.95*flBpp);
/* Adjust ui8SeInitQP up for small buffer size or small fps */
/* Adjust ui8SeInitQP up for small gop size */
if ((i32BufferSizeInFrames < 20) || (psRCParams->ui32IntraFreq < 20)) {
i32TmpQp += 2;
}
/* for very small buffers increase initial Qp even more */
if(i32BufferSizeInFrames < 5)
{
i32TmpQp += 8;
}
/* start on a lower initial Qp for HD content as the coding is more efficient */
if (psPicParams->sInParams.ui16MBPerFrm > 2000) {
i32TmpQp -= 2;
}
if(psPicParams->sInParams.ui16IntraPeriod ==1)
{
/* for very small GOPS start with a much higher initial Qp */
i32TmpQp += 12;
} else if (psPicParams->sInParams.ui16IntraPeriod<5) {
/* for very small GOPS start with a much higher initial Qp */
i32TmpQp += 6;
}
}
if (i32TmpQp>49) {
i32TmpQp = 49;
}
if (i32TmpQp < psPicParams->sInParams.ui8MinQPVal) {
i32TmpQp = psPicParams->sInParams.ui8MinQPVal;
}
psPicParams->sInParams.ui8SeInitQP = i32TmpQp;
if(flBpp <= 0.3)
psPicParams->ui32Flags |= ISRC_I16BIAS;
break;
case IMG_STANDARD_MPEG4:
case IMG_STANDARD_MPEG2:
case IMG_STANDARD_H263:
psPicParams->sInParams.ui8MaxQPVal = 31;
if (ctx->ui16Width == 176) {
L1 = 0.042; L2 = 0.084; L3 = 0.126; L4 = 0.168; L5 = 0.336; L6=0.505;
} else if (ctx->ui16Width == 352) {
L1 = 0.064; L2 = 0.084; L3 = 0.106; L4 = 0.126; L5 = 0.168; L6=0.210;
} else {
L1 = 0.050; L2 = 0.0760; L3 = 0.096; L4 = 0.145; L5 = 0.193; L6=0.289;
}
if (psPicParams->sInParams.ui8SeInitQP==0) {
if (flBpp < L1)
psPicParams->sInParams.ui8SeInitQP = 31;
else if (flBpp>=L1 && flBpp<L2)
psPicParams->sInParams.ui8SeInitQP = 26;
else if (flBpp>=L2 && flBpp<L3)
psPicParams->sInParams.ui8SeInitQP = 22;
else if (flBpp>=L3 && flBpp<L4)
psPicParams->sInParams.ui8SeInitQP = 18;
else if (flBpp>=L4 && flBpp<L5)
psPicParams->sInParams.ui8SeInitQP = 14;
else if (flBpp>=L5 && flBpp<L6)
psPicParams->sInParams.ui8SeInitQP = 10;
else
psPicParams->sInParams.ui8SeInitQP = 8;
/* Adjust ui8SeInitQP up for small buffer size or small fps */
/* Adjust ui8SeInitQP up for small gop size */
if ((i32BufferSizeInFrames < 20) || (psRCParams->ui32IntraFreq < 20)) {
psPicParams->sInParams.ui8SeInitQP += 2;
}
if (psPicParams->sInParams.ui8SeInitQP > psPicParams->sInParams.ui8MaxQPVal) {
psPicParams->sInParams.ui8SeInitQP = psPicParams->sInParams.ui8MaxQPVal;
}
psPicParams->sInParams.mode.other.ui16AvQPVal = psPicParams->sInParams.ui8SeInitQP;
}
psPicParams->sInParams.ui8MinQPVal = 2;
/* Adjust minQp up for small buffer size and down for large buffer size */
if (i32BufferSizeInFrames < 20) {
psPicParams->sInParams.ui8MinQPVal += 1;
}
break;
default:
/* the NO RC cases will fall here */
break;
}
if (ctx->sRCParams.eRCMode == IMG_RCMODE_VBR) {
psPicParams->sInParams.ui16MBPerBU = psPicParams->sInParams.ui16MBPerFrm;
psPicParams->sInParams.ui16BUPerFrm = 1;
// Initialize the parameters of fluid flow traffic model.
psPicParams->sInParams.i32BufferSize = psRCParams->ui32BufferSize;
// These scale factor are used only for rate control to avoid overflow
// in fixed-point calculation these scale factors are decided by bit rate
if (psRCParams->ui32BitsPerSecond < 640000) {
psPicParams->sInParams.ui8ScaleFactor = 2; // related to complexity
}
else if (psRCParams->ui32BitsPerSecond < 2000000) {
// 2 Mbits
psPicParams->sInParams.ui8ScaleFactor = 4;
}
else if(psRCParams->ui32BitsPerSecond < 8000000) {
// 8 Mbits
psPicParams->sInParams.ui8ScaleFactor = 6;
} else
psPicParams->sInParams.ui8ScaleFactor = 8;
} else {
// Set up Input Parameters that are mode dependent
switch (ctx->eStandard) {
case IMG_STANDARD_H264:
// ------------------- H264 CBR RC ------------------- //
// Initialize the parameters of fluid flow traffic model.
psPicParams->sInParams.i32BufferSize = psRCParams->ui32BufferSize;
// HRD consideration - These values are used by H.264 reference code.
if (psRCParams->ui32BitsPerSecond < 1000000) {
// 1 Mbits/s
psPicParams->sInParams.ui8ScaleFactor = 0;
} else if (psRCParams->ui32BitsPerSecond < 2000000) {
// 2 Mbits/s
psPicParams->sInParams.ui8ScaleFactor = 1;
} else if (psRCParams->ui32BitsPerSecond < 4000000) {
// 4 Mbits/s
psPicParams->sInParams.ui8ScaleFactor = 2;
} else if (psRCParams->ui32BitsPerSecond < 8000000) {
// 8 Mbits/s
psPicParams->sInParams.ui8ScaleFactor = 3;
} else {
psPicParams->sInParams.ui8ScaleFactor = 4;
}
if (ctx->sRCParams.eRCMode == IMG_RCMODE_VCM) {
psPicParams->sInParams.i32BufferSize = i32BufferSizeInFrames;
}
break;
case IMG_STANDARD_MPEG4:
case IMG_STANDARD_MPEG2:
case IMG_STANDARD_H263:
flBpp = 256 * (psRCParams->ui32BitsPerSecond/ctx->ui16Width);
flBpp /= (ctx->ui16FrameHeight * psRCParams->ui32FrameRate);
if ((psPicParams->sInParams.ui16MBPerFrm > 1024 && flBpp < 16) || (psPicParams->sInParams.ui16MBPerFrm <= 1024 && flBpp < 24))
psPicParams->sInParams.mode.other.ui8HalfFrameRate = 1;
else
psPicParams->sInParams.mode.other.ui8HalfFrameRate = 0;
if (psPicParams->sInParams.mode.other.ui8HalfFrameRate >= 1) {
psPicParams->sInParams.ui8SeInitQP = 31;
psPicParams->sInParams.mode.other.ui16AvQPVal = 31;
psPicParams->sInParams.mode.other.ui16MyInitQP = 31;
}
psPicParams->sInParams.i32BufferSize = psRCParams->ui32BufferSize;
break;
default:
break;
}
}
if (psRCParams->bScDetectDisable)
psPicParams->ui32Flags |= ISSCENE_DISABLED;
psPicParams->sInParams.i32InitialDelay = psRCParams->i32InitialDelay;
psPicParams->sInParams.i32InitialLevel = psRCParams->i32InitialLevel;
psRCParams->ui32InitialQp = psPicParams->sInParams.ui8SeInitQP;
/* The rate control uses this value to adjust the reaction rate to larger than expected frames */
if (ctx->eStandard == IMG_STANDARD_H264) {
if (psPicParams->sInParams.i32BitsPerFrm) {
const IMG_INT32 bitsPerGop = (psRCParams->ui32BitsPerSecond / psRCParams->ui32FrameRate) * psRCParams->ui32IntraFreq;
psPicParams->sInParams.mode.h264.ui32RCScaleFactor = (bitsPerGop * 256) /
(psPicParams->sInParams.i32BufferSize - psPicParams->sInParams.i32InitialLevel);
} else {
psPicParams->sInParams.mode.h264.ui32RCScaleFactor = 0;
}
} else {
psPicParams->sInParams.mode.other.ui16MyInitQP = psPicParams->sInParams.ui8SeInitQP;
}
return ;
}
static void tng__save_slice_params_template(
context_ENC_p ctx,
IMG_UINT32 ui32SliceBufIdx,
IMG_UINT32 ui32SliceType,
IMG_UINT32 ui32IPEControl,
IMG_UINT32 ui32Flags,
IMG_UINT32 ui32SliceConfig,
IMG_UINT32 ui32SeqConfig,
IMG_UINT32 ui32StreamIndex
)
{
IMG_FRAME_TEMPLATE_TYPE eSliceType = (IMG_FRAME_TEMPLATE_TYPE)ui32SliceType;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
SLICE_PARAMS *slice_temp_p = NULL;
psb_buffer_map(&(ps_mem->bufs_slice_template), &(ps_mem->bufs_slice_template.virtual_addr));
if (ps_mem->bufs_slice_template.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping slice template\n", __FUNCTION__);
return ;
}
slice_temp_p = (SLICE_PARAMS*)(ps_mem->bufs_slice_template.virtual_addr + (ctx->ctx_mem_size.slice_template * ui32SliceBufIdx));
slice_temp_p->eTemplateType = eSliceType;
slice_temp_p->ui32Flags = ui32Flags;
slice_temp_p->ui32IPEControl = ui32IPEControl;
slice_temp_p->ui32SliceConfig = ui32SliceConfig;
slice_temp_p->ui32SeqConfig = ui32SeqConfig;
psb_buffer_unmap(&(ps_mem->bufs_slice_template));
return ;
}
/*****************************************************************************
* Function Name : PrepareEncodeSliceParams
*
****************************************************************************/
static IMG_UINT32 tng__prepare_encode_sliceparams(
context_ENC_p ctx,
IMG_UINT32 ui32SliceBufIdx,
IMG_UINT32 ui32SliceType,
IMG_UINT16 __maybe_unused ui16CurrentRow,
IMG_UINT16 ui16SliceHeight,
IMG_UINT8 uiDeblockIDC,
IMG_BOOL bFieldMode,
IMG_INT iFineYSearchSize,
IMG_UINT32 ui32StreamIndex
)
{
IMG_UINT32 ui32FrameStoreFormat;
IMG_UINT8 ui8SwapChromas;
IMG_UINT32 ui32MBsPerKick, ui32KicksPerSlice;
IMG_UINT32 ui32IPEControl;
IMG_UINT32 ui32Flags = 0;
IMG_UINT32 ui32SliceConfig = 0;
IMG_UINT32 ui32SeqConfig = 0;
IMG_BOOL bIsIntra = IMG_FALSE;
IMG_BOOL bIsBPicture = IMG_FALSE;
IMG_BOOL bIsIDR = IMG_FALSE;
IMG_IPE_MINBLOCKSIZE blkSz;
IMG_FRAME_TEMPLATE_TYPE eSliceType = (IMG_FRAME_TEMPLATE_TYPE)ui32SliceType;
if (!ctx) {
return VA_STATUS_ERROR_INVALID_CONTEXT;
}
/* We want multiple ones of these so we can submit multiple slices without having to wait for the next*/
ui32IPEControl = ctx->ui32IPEControl;
bIsIntra = ((eSliceType == IMG_FRAME_IDR) || (eSliceType == IMG_FRAME_INTRA));
bIsBPicture = (eSliceType == IMG_FRAME_INTER_B);
bIsIDR = ((eSliceType == IMG_FRAME_IDR) || (eSliceType == IMG_FRAME_INTER_P_IDR));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG bIsIntra = %x\n", __FUNCTION__, bIsIntra);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG bIsBFrame = %x\n", __FUNCTION__, bIsBPicture);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG bIsIDR = %x\n", __FUNCTION__, bIsIDR);
/* extract block size */
blkSz = F_EXTRACT(ui32IPEControl, TOPAZHP_CR_IPE_BLOCKSIZE);
/* mask-out the block size bits from ui32IPEControl */
ui32IPEControl &= ~(F_MASK(TOPAZHP_CR_IPE_BLOCKSIZE));
switch (ctx->eStandard) {
case IMG_STANDARD_NONE:
case IMG_STANDARD_JPEG:
break;
case IMG_STANDARD_H264:
if (blkSz > 2) blkSz = 2;
if (bIsBPicture) {
if (blkSz > 1) blkSz = 1;
}
#ifdef BRN_30322
else if (bIsIntra) {
if (blkSz == 0) blkSz = 1; // Workaround for BRN 30322
}
#endif
#ifdef BRN_30550
if (ctx->bCabacEnabled)
if (blkSz == 0) blkSz = 1;
#endif
if (ctx->uMBspS >= _1080P_30FPS) {
ui32IPEControl |= F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_LRITC_BOUNDARY) |
F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH);
} else {
ui32IPEControl |= F_ENCODE(iFineYSearchSize + 1, TOPAZHP_CR_IPE_LRITC_BOUNDARY) |
F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH);
}
if (ctx->bLimitNumVectors)
ui32IPEControl |= F_ENCODE(1, TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION);
break;
case IMG_STANDARD_H263:
blkSz = 0;
ui32IPEControl = F_ENCODE(iFineYSearchSize + 1, TOPAZHP_CR_IPE_LRITC_BOUNDARY) |
F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH) |
F_ENCODE(0, TOPAZHP_CR_IPE_4X4_SEARCH);
//We only support a maxium vector of 15.5 pixels in H263
break;
case IMG_STANDARD_MPEG4:
if (blkSz > BLK_SZ_8x8) blkSz = BLK_SZ_8x8;
ui32IPEControl |= F_ENCODE(iFineYSearchSize + 1, TOPAZHP_CR_IPE_LRITC_BOUNDARY) |
F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH) |
F_ENCODE(0, TOPAZHP_CR_IPE_4X4_SEARCH);
// FIXME Should be 1, set to zero for hardware testing.
break;
case IMG_STANDARD_MPEG2:
if (blkSz != BLK_SZ_16x16) blkSz = BLK_SZ_16x16;
ui32IPEControl |= F_ENCODE(iFineYSearchSize + 1, TOPAZHP_CR_IPE_LRITC_BOUNDARY) |
F_ENCODE(iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH) |
F_ENCODE(0, TOPAZHP_CR_IPE_4X4_SEARCH);
// FIXME Should be 1, set to zero for hardware testing.
break;
}
{
IMG_BOOL bRestrict4x4SearchSize;
IMG_UINT32 uLritcBoundary;
if (ctx->uMBspS >= _1080P_30FPS)
bRestrict4x4SearchSize = 1;
else
bRestrict4x4SearchSize = 0;
ui32IPEControl |= F_ENCODE(blkSz, TOPAZHP_CR_IPE_BLOCKSIZE);
uLritcBoundary = (blkSz != BLK_SZ_16x16) ? (iFineYSearchSize + (bRestrict4x4SearchSize ? 0 : 1)) : 1;
if (uLritcBoundary > 3) {
return VA_STATUS_ERROR_UNKNOWN;
}
/* Minium sub block size to calculate motion vectors for. 0=16x16, 1=8x8, 2=4x4 */
ui32IPEControl = F_INSERT(ui32IPEControl, blkSz, TOPAZHP_CR_IPE_BLOCKSIZE);
ui32IPEControl = F_INSERT(ui32IPEControl, iFineYSearchSize, TOPAZHP_CR_IPE_Y_FINE_SEARCH);
ui32IPEControl = F_INSERT(ui32IPEControl, ctx->bLimitNumVectors, TOPAZHP_CR_IPE_MV_NUMBER_RESTRICTION);
ui32IPEControl = F_INSERT(ui32IPEControl, uLritcBoundary, TOPAZHP_CR_IPE_LRITC_BOUNDARY); // 8x8 search
ui32IPEControl = F_INSERT(ui32IPEControl, bRestrict4x4SearchSize ? 0 : 1, TOPAZHP_CR_IPE_4X4_SEARCH);
}
ui32IPEControl = F_INSERT(ui32IPEControl, ctx->bHighLatency, TOPAZHP_CR_IPE_HIGH_LATENCY);
// psSliceParams->ui32IPEControl = ui32IPEControl;
if (!bIsIntra) {
if (bIsBPicture)
ui32Flags |= ISINTERB_FLAGS;
else
ui32Flags |= ISINTERP_FLAGS;
}
switch (ctx->eStandard) {
case IMG_STANDARD_NONE:
break;
case IMG_STANDARD_H263:
ui32Flags |= ISH263_FLAGS;
break;
case IMG_STANDARD_MPEG4:
ui32Flags |= ISMPEG4_FLAGS;
break;
case IMG_STANDARD_MPEG2:
ui32Flags |= ISMPEG2_FLAGS;
break;
default:
break;
}
if (ctx->bMultiReferenceP && !(bIsIntra || bIsBPicture))
ui32Flags |= ISMULTIREF_FLAGS;
if (ctx->bSpatialDirect && bIsBPicture)
ui32Flags |= SPATIALDIRECT_FLAGS;
if (bIsIntra) {
ui32SliceConfig = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_I_SLICE, TOPAZHP_CR_SLICE_TYPE);
} else {
if (bIsBPicture) {
ui32SliceConfig = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_B_SLICE, TOPAZHP_CR_SLICE_TYPE);
} else {
// p frame
ui32SliceConfig = F_ENCODE(TOPAZHP_CR_SLICE_TYPE_P_SLICE, TOPAZHP_CR_SLICE_TYPE);
}
}
ui32MBsPerKick = ctx->ui32KickSize;
// we need to figure out the number of kicks and mb's per kick to use.
// on H.264 we will use a MB's per kick of basic unit
// on other rc varients we will use mb's per kick of width
ui32KicksPerSlice = ((ui16SliceHeight / 16) * (ctx->ui16Width / 16)) / ui32MBsPerKick;
assert((ui32KicksPerSlice * ui32MBsPerKick) == ((ui16SliceHeight / 16)*(ctx->ui16Width / 16)));
// need some sensible ones don't look to be implemented yet...
// change per stream
if ((ctx->eFormat == IMG_CODEC_UY0VY1_8888) || (ctx->eFormat == IMG_CODEC_VY0UY1_8888))
ui32FrameStoreFormat = 3;
else if ((ctx->eFormat == IMG_CODEC_Y0UY1V_8888) || (ctx->eFormat == IMG_CODEC_Y0VY1U_8888))
ui32FrameStoreFormat = 2;
else if ((ctx->eFormat == IMG_CODEC_PL12) || (ctx->eFormat == IMG_CODEC_422_PL12))
ui32FrameStoreFormat = 1;
else
ui32FrameStoreFormat = 0;
if ((ctx->eFormat == IMG_CODEC_VY0UY1_8888) || (ctx->eFormat == IMG_CODEC_Y0VY1U_8888))
ui8SwapChromas = 1;
else
ui8SwapChromas = 0;
switch (ctx->eStandard) {
case IMG_STANDARD_NONE:
case IMG_STANDARD_JPEG:
break;
case IMG_STANDARD_H264:
/* H264 */
ui32SeqConfig = F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID)
| F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC0_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC1_VALID)
| F_ENCODE(!bIsBPicture, TOPAZHP_CR_REF_PIC1_EQUAL_PIC0)
| F_ENCODE(bFieldMode ? 1 : 0 , TOPAZHP_CR_FIELD_MODE)
| F_ENCODE(ui8SwapChromas, TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP)
| F_ENCODE(ui32FrameStoreFormat, TOPAZHP_CR_FRAME_STORE_FORMAT)
| F_ENCODE(TOPAZHP_CR_ENCODER_STANDARD_H264, TOPAZHP_CR_ENCODER_STANDARD)
| F_ENCODE(uiDeblockIDC == 1 ? 0 : 1, TOPAZHP_CR_DEBLOCK_ENABLE);
if (ctx->sRCParams.ui16BFrames) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID);
if ((ui32Flags & ISINTERB_FLAGS) == ISINTERB_FLAGS)
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_TEMPORAL_COL_IN_VALID);
}
if (!bIsBPicture) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_WRITE_TEMPORAL_COL_VALID);
}
break;
case IMG_STANDARD_MPEG4:
/* MPEG4 */
ui32SeqConfig = F_ENCODE(1, TOPAZHP_CR_WRITE_RECON_PIC)
| F_ENCODE(0, TOPAZHP_CR_DEBLOCK_ENABLE)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID)
| F_ENCODE(((ui32Flags & ISINTERP_FLAGS) == ISINTERP_FLAGS), TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC0_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC1_VALID)
| F_ENCODE(1, TOPAZHP_CR_REF_PIC1_EQUAL_PIC0)
| F_ENCODE(0, TOPAZHP_CR_FIELD_MODE)
| F_ENCODE(ui8SwapChromas, TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP)
| F_ENCODE(ui32FrameStoreFormat, TOPAZHP_CR_FRAME_STORE_FORMAT)
| F_ENCODE(TOPAZHP_CR_ENCODER_STANDARD_MPEG4, TOPAZHP_CR_ENCODER_STANDARD);
break;
case IMG_STANDARD_MPEG2:
/* MPEG2 */
ui32SeqConfig = F_ENCODE(1, TOPAZHP_CR_WRITE_RECON_PIC)
| F_ENCODE(0, TOPAZHP_CR_DEBLOCK_ENABLE)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID)
| F_ENCODE(((ui32Flags & ISINTERP_FLAGS) == ISINTERP_FLAGS), TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID)
| F_ENCODE(1, TOPAZHP_CR_REF_PIC0_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC1_VALID)
| F_ENCODE(1, TOPAZHP_CR_REF_PIC1_EQUAL_PIC0)
| F_ENCODE(bFieldMode ? 1 : 0 , TOPAZHP_CR_FIELD_MODE)
| F_ENCODE(ui8SwapChromas, TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP)
| F_ENCODE(ui32FrameStoreFormat, TOPAZHP_CR_FRAME_STORE_FORMAT)
| F_ENCODE(TOPAZHP_CR_ENCODER_STANDARD_MPEG2, TOPAZHP_CR_ENCODER_STANDARD);
break;
case IMG_STANDARD_H263:
/* H263 */
ui32SeqConfig = F_ENCODE(1, TOPAZHP_CR_WRITE_RECON_PIC)
| F_ENCODE(0, TOPAZHP_CR_DEBLOCK_ENABLE)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC0_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_ABOVE_OUT_OF_SLICE_VALID)
| F_ENCODE(((ui32Flags & ISINTERP_FLAGS) == ISINTERP_FLAGS), TOPAZHP_CR_WRITE_TEMPORAL_PIC0_BELOW_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC0_VALID)
| F_ENCODE(0, TOPAZHP_CR_REF_PIC1_VALID)
| F_ENCODE(1, TOPAZHP_CR_REF_PIC1_EQUAL_PIC0)
| F_ENCODE(0, TOPAZHP_CR_FIELD_MODE)
| F_ENCODE(ui8SwapChromas, TOPAZHP_CR_FRAME_STORE_CHROMA_SWAP)
| F_ENCODE(ui32FrameStoreFormat, TOPAZHP_CR_FRAME_STORE_FORMAT)
| F_ENCODE(TOPAZHP_CR_ENCODER_STANDARD_H263, TOPAZHP_CR_ENCODER_STANDARD);
break;
}
if (bIsBPicture) {
ui32SeqConfig |= F_ENCODE(0, TOPAZHP_CR_TEMPORAL_PIC1_BELOW_IN_VALID)
| F_ENCODE(0, TOPAZHP_CR_WRITE_TEMPORAL_PIC1_BELOW_VALID)
| F_ENCODE(1, TOPAZHP_CR_REF_PIC1_VALID)
| F_ENCODE(1, TOPAZHP_CR_TEMPORAL_COL_IN_VALID);
}
if (ctx->ui8EnableSelStatsFlags & ESF_FIRST_STAGE_STATS) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_WRITE_MB_FIRST_STAGE_VALID);
}
if (ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MB_DECISION_STATS ||
ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MOTION_VECTOR_STATS) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_BEST_MULTIPASS_OUT_VALID);
if (!(ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MOTION_VECTOR_STATS)) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_BEST_MVS_OUT_DISABLE);// 64 Byte Best Multipass Motion Vector output disabled by default
}
}
if (ctx->bEnableInpCtrl) {
ui32SeqConfig |= F_ENCODE(1, TOPAZHP_CR_MB_CONTROL_IN_VALID);
}
if (eSliceType == IMG_FRAME_IDR) {
ctx->sBiasTables.ui32SeqConfigInit = ui32SeqConfig;
}
tng__save_slice_params_template(ctx, ui32SliceBufIdx, eSliceType,
ui32IPEControl, ui32Flags, ui32SliceConfig, ui32SeqConfig, ui32StreamIndex);
return 0;
}
void tng__mpeg4_generate_pic_hdr_template(
context_ENC_p ctx,
IMG_FRAME_TEMPLATE_TYPE ui8SliceType,
IMG_UINT8 ui8Search_range)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
MTX_HEADER_PARAMS * pPicHeaderMem;
VOP_CODING_TYPE eVop_Coding_Type;
IMG_BOOL8 b8IsVopCoded;
IMG_UINT8 ui8OriginalSliceType = ui8SliceType;
/* MPEG4: We do not support B-frames at the moment, so we use a spare slot, to store a template for the skipped frame */
if (ui8SliceType == IMG_FRAME_INTER_B)
{
ui8SliceType = IMG_FRAME_INTER_P;
b8IsVopCoded = IMG_FALSE;
} else {
b8IsVopCoded = IMG_TRUE;
}
eVop_Coding_Type = (ui8SliceType == IMG_FRAME_INTER_P) ? P_FRAME : I_FRAME;
psb_buffer_map(&(ps_mem->bufs_pic_template), &(ps_mem->bufs_pic_template.virtual_addr));
if (ps_mem->bufs_pic_template.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping pic template\n", __FUNCTION__);
return ;
}
pPicHeaderMem = (MTX_HEADER_PARAMS *)((IMG_UINT8*)(ps_mem->bufs_pic_template.virtual_addr + (ctx->ctx_mem_size.pic_template * ui8OriginalSliceType)));
//todo fix time resolution
tng__MPEG4_notforsims_prepare_vop_header(pPicHeaderMem, b8IsVopCoded, ui8Search_range, eVop_Coding_Type);
psb_buffer_unmap(&(ps_mem->bufs_pic_template));
}
void tng__h263_generate_pic_hdr_template(
context_ENC_p ctx,
IMG_FRAME_TEMPLATE_TYPE eFrameType,
IMG_UINT16 ui16Width,
IMG_UINT16 ui16Heigh)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
MTX_HEADER_PARAMS * pPicHeaderMem = NULL;
H263_PICTURE_CODING_TYPE ePictureCodingType = ((eFrameType == IMG_FRAME_INTRA)|| (eFrameType == IMG_FRAME_IDR)) ? I_FRAME : P_FRAME;
psb_buffer_map(&(ps_mem->bufs_pic_template), &(ps_mem->bufs_pic_template.virtual_addr));
if (ps_mem->bufs_pic_template.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping pic template\n", __FUNCTION__);
return ;
}
pPicHeaderMem = (MTX_HEADER_PARAMS *)((IMG_UINT8*)(ps_mem->bufs_pic_template.virtual_addr + (ctx->ctx_mem_size.pic_template * eFrameType)));
IMG_UINT8 ui8FrameRate = (IMG_UINT8)ctx->sRCParams.ui32FrameRate;
// Get a pointer to the memory the header will be written to
tng__H263_notforsims_prepare_video_pictureheader(
pPicHeaderMem,
ePictureCodingType,
ctx->ui8H263SourceFormat,
ui8FrameRate,
ui16Width,
ui16Heigh);
psb_buffer_unmap(&(ps_mem->bufs_pic_template));
}
static void tng__MPEG4ES_send_seq_header(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
psb_buffer_map(&(ps_mem->bufs_seq_header), &(ps_mem->bufs_seq_header.virtual_addr));
if (ps_mem->bufs_seq_header.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping seq template\n", __FUNCTION__);
return ;
}
tng__MPEG4_prepare_sequence_header(ps_mem->bufs_seq_header.virtual_addr,
IMG_FALSE,//FIXME: Zhaohan bFrame
ctx->ui8ProfileIdc,//profile
ctx->ui8LevelIdc,//ui8Profile_lvl_indication
3,//ui8Fixed_vop_time_increment
ctx->obj_context->picture_width,//ui8Fixed_vop_time_increment
ctx->obj_context->picture_height,//ui32Picture_Height_Pixels
NULL,//VBVPARAMS
ctx->ui32VopTimeResolution);
psb_buffer_unmap(&(ps_mem->bufs_seq_header));
cmdbuf->cmd_idx_saved[TNG_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx;
}
static void tng__H264ES_send_seq_header(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
H264_VUI_PARAMS *psVuiParams = &(ctx->sVuiParams);
// memset(psVuiParams, 0, sizeof(H264_VUI_PARAMS));
if (psRCParams->eRCMode != IMG_RCMODE_NONE) {
psVuiParams->vui_flag = 1;
if (psVuiParams->num_units_in_tick == 0 || psVuiParams->Time_Scale == 0) {
psVuiParams->num_units_in_tick = 1;
psVuiParams->Time_Scale = psRCParams->ui32FrameRate * 2;
}
psVuiParams->bit_rate_value_minus1 = psRCParams->ui32BitsPerSecond / 64 - 1;
psVuiParams->cbp_size_value_minus1 = psRCParams->ui32BufferSize / 64 - 1;
psVuiParams->CBR = ((psRCParams->eRCMode == IMG_RCMODE_CBR) && (!psRCParams->bDisableBitStuffing)) ? 1 : 0;
psVuiParams->initial_cpb_removal_delay_length_minus1 = BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE - 1;
psVuiParams->cpb_removal_delay_length_minus1 = PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE - 1;
psVuiParams->dpb_output_delay_length_minus1 = PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE - 1;
psVuiParams->time_offset_length = 24;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s psVuiParams->vui_flag = %d\n", __FUNCTION__, psVuiParams->vui_flag);
psb_buffer_map(&(ps_mem->bufs_seq_header), &(ps_mem->bufs_seq_header.virtual_addr));
if (ps_mem->bufs_seq_header.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping seq header\n", __FUNCTION__);
return ;
}
tng__H264ES_prepare_sequence_header(
ps_mem->bufs_seq_header.virtual_addr,
&(ctx->sVuiParams),
&(ctx->sCropParams),
ctx->ui16Width, //ui8_picture_width_in_mbs
ctx->ui16PictureHeight, //ui8_picture_height_in_mbs
ctx->ui32CustomQuantMask, //0, ui8_custom_quant_mask
ctx->ui8ProfileIdc, //ui8_profile
ctx->ui8LevelIdc, //ui8_level
ctx->ui8FieldCount, //1, ui8_field_count
ctx->ui8MaxNumRefFrames, //1, ui8_max_num_ref_frames
ctx->bPpsScaling, //0 ui8_pps_scaling_cnt
ctx->bUseDefaultScalingList, //0, b_use_default_scaling_list
ctx->bEnableLossless, //0, blossless
ctx->bArbitrarySO
);
psb_buffer_unmap(&(ps_mem->bufs_seq_header));
if (ctx->bEnableMVC) {
psb_buffer_map(&(ps_mem->bufs_sub_seq_header), &(ps_mem->bufs_sub_seq_header.virtual_addr));
if (ps_mem->bufs_sub_seq_header.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping sub seq header\n", __FUNCTION__);
return ;
}
tng__H264ES_prepare_mvc_sequence_header(
ps_mem->bufs_sub_seq_header.virtual_addr,
&(ctx->sCropParams),
ctx->ui16Width, //ui8_picture_width_in_mbs
ctx->ui16PictureHeight, //ui8_picture_height_in_mbs
ctx->ui32CustomQuantMask, //0, ui8_custom_quant_mask
ctx->ui8ProfileIdc, //ui8_profile
ctx->ui8LevelIdc, //ui8_level
ctx->ui8FieldCount, //1, ui8_field_count
ctx->ui8MaxNumRefFrames, //1, ui8_max_num_ref_frames
ctx->bPpsScaling, //0 ui8_pps_scaling_cnt
ctx->bUseDefaultScalingList, //0, b_use_default_scaling_list
ctx->bEnableLossless, //0, blossless
ctx->bArbitrarySO
);
psb_buffer_unmap(&(ps_mem->bufs_sub_seq_header));
}
cmdbuf->cmd_idx_saved[TNG_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx;
return ;
}
static void tng__H264ES_send_pic_header(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
IMG_BOOL bDepViewPPS = IMG_FALSE;
if ((ctx->bEnableMVC) && (ctx->ui16MVCViewIdx != 0) &&
(ctx->ui16MVCViewIdx != (IMG_UINT16)(NON_MVC_VIEW))) {
bDepViewPPS = IMG_TRUE;
}
psb_buffer_map(&(ps_mem->bufs_pic_template), &(ps_mem->bufs_pic_template.virtual_addr));
if (ps_mem->bufs_pic_template.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping pic template\n", __FUNCTION__);
return ;
}
tng__H264ES_prepare_picture_header(
ps_mem->bufs_pic_template.virtual_addr,
ctx->bCabacEnabled,
ctx->bH2648x8Transform, //IMG_BOOL b_8x8transform,
ctx->bH264IntraConstrained, //IMG_BOOL bIntraConstrained,
0, //IMG_INT8 i8CQPOffset,
0, //IMG_BOOL bWeightedPrediction,
0, //IMG_UINT8 ui8WeightedBiPred,
bDepViewPPS, //IMG_BOOL bMvcPPS,
0, //IMG_BOOL bScalingMatrix,
0 //IMG_BOOL bScalingLists
);
psb_buffer_unmap(&(ps_mem->bufs_pic_template));
return ;
}
static void tng__H264ES_send_hrd_header(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
unsigned int ui32nal_initial_cpb_removal_delay;
unsigned int ui32nal_initial_cpb_removal_delay_offset;
uint32_t ui32cpb_removal_delay;
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
H264_VUI_PARAMS *psVuiParams = &(ctx->sVuiParams);
IMG_UINT8 aui8clocktimestampflag[1];
aui8clocktimestampflag[0] = IMG_FALSE;
ui32nal_initial_cpb_removal_delay =
90000 * (1.0 * psRCParams->i32InitialDelay / psRCParams->ui32BitsPerSecond);
ui32nal_initial_cpb_removal_delay_offset =
90000 * (1.0 * ctx->buffer_size / psRCParams->ui32BitsPerSecond)
- ui32nal_initial_cpb_removal_delay;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI buffer period message with "
"ui32nal_initial_cpb_removal_delay(%d) and "
"ui32nal_initial_cpb_removal_delay_offset(%d)\n",
ui32nal_initial_cpb_removal_delay,
ui32nal_initial_cpb_removal_delay_offset);
psb_buffer_map(&(ps_mem->bufs_sei_header), &(ps_mem->bufs_sei_header.virtual_addr));
if (ps_mem->bufs_sei_header.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping sei header\n", __FUNCTION__);
return ;
}
if ((!ctx->bEnableMVC) || (ctx->ui16MVCViewIdx == 0)) {
tng__H264ES_prepare_AUD_header(ps_mem->bufs_sei_header.virtual_addr);
}
tng__H264ES_prepare_SEI_buffering_period_header(
ps_mem->bufs_sei_header.virtual_addr + (ctx->ctx_mem_size.sei_header),
0,// ui8cpb_cnt_minus1,
psVuiParams->initial_cpb_removal_delay_length_minus1+1, //ui8initial_cpb_removal_delay_length,
1, //ui8NalHrdBpPresentFlag,
ui32nal_initial_cpb_removal_delay, // ui32nal_initial_cpb_removal_delay,
ui32nal_initial_cpb_removal_delay_offset, //ui32nal_initial_cpb_removal_delay_offset,
0, //ui8VclHrdBpPresentFlag - CURRENTLY HARD CODED TO ZERO IN TOPAZ
NOT_USED_BY_TOPAZ, // ui32vcl_initial_cpb_removal_delay, (not used when ui8VclHrdBpPresentFlag = 0)
NOT_USED_BY_TOPAZ); // ui32vcl_initial_cpb_removal_delay_offset (not used when ui8VclHrdBpPresentFlag = 0)
/* ui32cpb_removal_delay is zero for 1st frame and will be reset
* after a IDR frame */
if (ctx->ui32FrameCount[ui32StreamIndex] == 0) {
if (ctx->ui32RawFrameCount == 0)
ui32cpb_removal_delay = 0;
else
ui32cpb_removal_delay =
ctx->ui32IdrPeriod * ctx->ui32IntraCnt * 2;
} else
ui32cpb_removal_delay = 2 * ctx->ui32FrameCount[ui32StreamIndex];
tng__H264ES_prepare_SEI_picture_timing_header(
ps_mem->bufs_sei_header.virtual_addr + (ctx->ctx_mem_size.sei_header * 2),
1, //ui8CpbDpbDelaysPresentFlag,
psVuiParams->cpb_removal_delay_length_minus1, //cpb_removal_delay_length_minus1,
psVuiParams->dpb_output_delay_length_minus1, //dpb_output_delay_length_minus1,
ui32cpb_removal_delay, //ui32cpb_removal_delay,
2, //ui32dpb_output_delay,
0, //ui8pic_struct_present_flag (contained in the sequence header, Topaz hard-coded default to 0)
NOT_USED_BY_TOPAZ, //ui8pic_struct, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //NumClockTS, (not used when ui8pic_struct_present_flag = 0)
aui8clocktimestampflag, //abclock_timestamp_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8full_timestamp_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8seconds_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8minutes_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8hours_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //seconds_value, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //minutes_value, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //hours_value, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ct_type (2=Unknown) See TRM Table D 2 ?Mapping of ct_type to source picture scan (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //nuit_field_based_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //counting_type (See TRM Table D 3 ?Definition of counting_type values) (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8discontinuity_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //ui8cnt_dropped_flag, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //n_frames, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ, //time_offset_length, (not used when ui8pic_struct_present_flag = 0)
NOT_USED_BY_TOPAZ); //time_offset (not used when ui8pic_struct_present_flag = 0)
psb_buffer_unmap(&(ps_mem->bufs_sei_header));
return ;
}
static void tng__generate_slice_params_template(
context_ENC_p ctx,
IMG_UINT32 slice_buf_idx,
IMG_UINT32 slice_type,
IMG_UINT32 ui32StreamIndex
)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
IMG_UINT8 *slice_mem_temp_p = NULL;
IMG_UINT32 ui32SliceHeight = 0;
IMG_FRAME_TEMPLATE_TYPE slice_temp_type = (IMG_FRAME_TEMPLATE_TYPE)slice_type;
IMG_FRAME_TEMPLATE_TYPE buf_idx = (IMG_FRAME_TEMPLATE_TYPE)slice_buf_idx;
if (ctx->ui8SlicesPerPicture != 0)
ui32SliceHeight = ctx->ui16PictureHeight / ctx->ui8SlicesPerPicture;
else
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s slice height\n", __FUNCTION__);
ui32SliceHeight &= ~15;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG ui8DeblockIDC = %x\n", __FUNCTION__, ctx->ui8DeblockIDC );
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG ui32SliceHeight = %x\n", __FUNCTION__, ui32SliceHeight );
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG bIsInterlaced = %x\n", __FUNCTION__, ctx->bIsInterlaced );
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG iFineYSearchSize = %x\n", __FUNCTION__, ctx->iFineYSearchSize);
tng__prepare_encode_sliceparams(
ctx,
slice_buf_idx,
slice_temp_type,
0, // ui16CurrentRow,
ui32SliceHeight,
ctx->ui8DeblockIDC, // uiDeblockIDC
ctx->bIsInterlaced, // bFieldMode
ctx->iFineYSearchSize,
ui32StreamIndex
);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG bCabacEnabled = %x\n", __FUNCTION__, ctx->bCabacEnabled );
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s PTG ui16MVCViewIdx = %x\n", __FUNCTION__, ctx->ui16MVCViewIdx);
if(ctx->bEnableMVC)
ctx->ui16MVCViewIdx = (IMG_UINT16)ui32StreamIndex;
if (ps_mem->bufs_slice_template.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping slice template\n", __FUNCTION__);
return ;
}
slice_mem_temp_p = (IMG_UINT8*)(ps_mem->bufs_slice_template.virtual_addr + (ctx->ctx_mem_size.slice_template * buf_idx));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: addr 0x%08x, virtual 0x%08x, size = 0x%08x, buf_idx = %x\n",
__FUNCTION__, slice_mem_temp_p, ps_mem->bufs_slice_template.virtual_addr, ctx->ctx_mem_size.slice_template, buf_idx);
/* Prepare Slice Header Template */
switch (ctx->eStandard) {
case IMG_STANDARD_NONE:
case IMG_STANDARD_JPEG:
case IMG_STANDARD_MPEG4:
break;
case IMG_STANDARD_H264:
//H264_NOTFORSIMS_PrepareSliceHeader
tng__H264ES_notforsims_prepare_sliceheader(
slice_mem_temp_p,
slice_temp_type,
ctx->ui8DeblockIDC,
0, // ui32FirstMBAddress
0, // uiMBSkipRun
ctx->bCabacEnabled,
ctx->bIsInterlaced,
ctx->ui16MVCViewIdx, //(IMG_UINT16)(NON_MVC_VIEW);
IMG_FALSE // bIsLongTermRef
);
break;
case IMG_STANDARD_H263:
tng__H263ES_notforsims_prepare_gobsliceheader(slice_mem_temp_p);
break;
case IMG_STANDARD_MPEG2:
tng__MPEG2_prepare_sliceheader(slice_mem_temp_p);
break;
}
psb_buffer_unmap(&(ps_mem->bufs_slice_template));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end \n", __FUNCTION__);
return ;
}
//H264_PrepareTemplates
static VAStatus tng__prepare_templates(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
PIC_PARAMS *psPicParams = &(ctx->sPicParams);
IN_RC_PARAMS* psInParams = &(psPicParams->sInParams);
psPicParams->ui32Flags = 0;
tng__prepare_mv_estimates(ctx, ui32StreamIndex);
switch (ctx->eStandard) {
case IMG_STANDARD_H263:
psPicParams->ui32Flags |= ISH263_FLAGS;
break;
case IMG_STANDARD_MPEG4:
psPicParams->ui32Flags |= ISMPEG4_FLAGS;
break;
case IMG_STANDARD_MPEG2:
psPicParams->ui32Flags |= ISMPEG2_FLAGS;
break;
default:
break;
}
if (psRCParams->eRCMode) {
psPicParams->ui32Flags |= ISRC_FLAGS;
tng__setup_rcdata(ctx);
} else {
psInParams->ui8SeInitQP = psRCParams->ui32InitialQp;
psInParams->ui8MBPerRow = (ctx->ui16Width >> 4);
psInParams->ui16MBPerFrm = (ctx->ui16Width >> 4) * (ctx->ui16PictureHeight >> 4);
psInParams->ui16MBPerBU = psRCParams->ui32BUSize;
psInParams->ui16BUPerFrm = (psInParams->ui16MBPerFrm) / psRCParams->ui32BUSize;
ctx->ui32KickSize = psInParams->ui16MBPerBU;
}
// Prepare Slice header templates
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_IDR, (IMG_UINT32)IMG_FRAME_IDR, ui32StreamIndex);
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTRA, (IMG_UINT32)IMG_FRAME_INTRA, ui32StreamIndex);
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTER_P, (IMG_UINT32)IMG_FRAME_INTER_P, ui32StreamIndex);
switch(ctx->eStandard) {
case IMG_STANDARD_H264:
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTER_B, (IMG_UINT32)IMG_FRAME_INTER_B, ui32StreamIndex);
if (ctx->bEnableMVC)
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTER_P_IDR, (IMG_UINT32)IMG_FRAME_INTER_P_IDR, ui32StreamIndex);
tng__H264ES_send_seq_header(ctx, 0);
tng__H264ES_send_pic_header(ctx, 0);
if (ctx->bInsertHRDParams)
tng__H264ES_send_hrd_header(ctx, 0);
break;
case IMG_STANDARD_H263:
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTER_B, (IMG_UINT32)IMG_FRAME_INTER_B, ui32StreamIndex);
/* Here H263 uses the actual width and height */
tng__h263_generate_pic_hdr_template(ctx, IMG_FRAME_IDR, ctx->h263_actual_width, ctx->h263_actual_height);
tng__h263_generate_pic_hdr_template(ctx, IMG_FRAME_INTRA, ctx->h263_actual_width, ctx->h263_actual_height);
tng__h263_generate_pic_hdr_template(ctx, IMG_FRAME_INTER_P, ctx->h263_actual_width, ctx->h263_actual_height);
break;
case IMG_STANDARD_MPEG4:
tng__generate_slice_params_template(ctx, (IMG_UINT32)IMG_FRAME_INTER_B, (IMG_UINT32)IMG_FRAME_INTER_P, ui32StreamIndex);
tng__mpeg4_generate_pic_hdr_template(ctx, IMG_FRAME_IDR, 4);
tng__mpeg4_generate_pic_hdr_template(ctx, IMG_FRAME_INTRA, 4);
tng__mpeg4_generate_pic_hdr_template(ctx, IMG_FRAME_INTER_P, 4);
tng__mpeg4_generate_pic_hdr_template(ctx, IMG_FRAME_INTER_B, 4);
break;
default:
break;
}
//FIXME: Zhaohan tng__mpeg2/mpeg4_generate_pic_hdr_template(IMG_FRAME_IDR\IMG_FRAME_INTRA\IMG_FRAME_INTER_P\IMG_FRAME_INTER_B);
/*
else {
slice_mem_temp_p = (IMG_UINT8*)cmdbuf->slice_mem_p + (((IMG_UINT32)IMG_FRAME_INTER_P_IDR) * cmdbuf->mem_size);
memset(slice_mem_temp_p, 0, 128);
}
*/
// Prepare Pic Params Templates
tng__adjust_picflags(ctx, psRCParams, IMG_TRUE, &(ctx->ui32FirstPicFlags));
tng__adjust_picflags(ctx, psRCParams, IMG_FALSE, &(ctx->ui32NonFirstPicFlags));
return VA_STATUS_SUCCESS;
}
#if INPUT_SCALER_SUPPORTED
static IMG_FLOAT VIDEO_CalculateBessel0 (IMG_FLOAT fX)
{
IMG_FLOAT fAX, fY;
fAX = (IMG_FLOAT)IMG_FABS(fX);
if (fAX < 3.75) {
fY = (IMG_FLOAT)(fX / 3.75);
fY *= fY;
return (IMG_FLOAT)(1.0 + fY *
(3.5156229 + fY *
(3.0899424 + fY *
(1.2067492 + fY *
(0.2659732 + fY *
(0.360768e-1 + fY * 0.45813e-2))))));
}
fY = (IMG_FLOAT)(3.75 / fAX);
return (IMG_FLOAT)((IMG_EXP(fAX) / IMG_SQRT(fAX)) *
(0.39894228 + fY *
(0.1328592e-1 + fY *
(0.225319e-2 + fY *
(-0.157565e-2 + fY *
(0.916281e-2 + fY *
(-0.2057706e-1 + fY *
(0.2635537e-1 + fY *
(-0.1647633e-1 + fY * 0.392377e-2)))))))));
}
static IMG_FLOAT VIDEO_SincFunc (IMG_FLOAT fInput, IMG_FLOAT fScale)
{
IMG_FLOAT fX;
IMG_FLOAT fKaiser;
/* Kaiser window */
fX = fInput / (4.0f / 2.0f) - 1.0f;
fX = (IMG_FLOAT)IMG_SQRT(1.0f - fX * fX);
fKaiser = VIDEO_CalculateBessel0(2.0f * fX) / VIDEO_CalculateBessel0(2.0f);
/* Sinc function */
fX = 4.0f / 2.0f - fInput;
if (fX == 0) {
return fKaiser;
}
fX *= 0.9f * fScale * 3.1415926535897f;
return fKaiser * (IMG_FLOAT)(IMG_SIN(fX) / fX);
}
static void VIDEO_CalcCoefs_FromPitch (IMG_FLOAT fPitch, IMG_UINT8 aui8Table[4][16])
{
/* Based on sim code */
/* The function is symmetrical, so we only need to calculate the first half of the taps, and the middle value. */
IMG_FLOAT fScale;
IMG_UINT32 ui32I, ui32Tap;
IMG_FLOAT afTable[4][16];
IMG_INT32 i32Total;
IMG_FLOAT fTotal;
IMG_INT32 i32MiddleTap, i32MiddleI; /* Mirrored / middle Values for I and T */
if (fPitch < 1.0f) {
fScale = 1.0f;
} else {
fScale = 1.0f / fPitch;
}
for (ui32I = 0; ui32I < 16; ui32I++) {
for (ui32Tap = 0; ui32Tap < 4; ui32Tap++) {
afTable[ui32Tap][ui32I] = VIDEO_SincFunc(((IMG_FLOAT)ui32Tap) + ((IMG_FLOAT)ui32I) / 16.0f, fScale);
}
}
for (ui32Tap = 0; ui32Tap < 2; ui32Tap++) {
for (ui32I = 0; ui32I < 16; ui32I++) {
/* Copy the table around the centre point */
i32MiddleTap = (3 - ui32Tap) + (16 - ui32I) / 16;
i32MiddleI = (16 - ui32I) & 15;
if ((IMG_UINT32)i32MiddleTap < 4) {
afTable[i32MiddleTap][i32MiddleI] = afTable[ui32Tap][ui32I];
}
}
}
/* The middle value */
afTable[2][0] = VIDEO_SincFunc(2.0f, fScale);
/* Normalize this interpolation point, and convert to 2.6 format, truncating the result */
for (ui32I = 0; ui32I < 16; ui32I++) {
fTotal = 0.0f;
i32Total = 0;
for (ui32Tap = 0; ui32Tap < 4; ui32Tap++) {
fTotal += afTable[ui32Tap][ui32I];
}
for (ui32Tap = 0; ui32Tap < 4; ui32Tap++) {
aui8Table[ui32Tap][ui32I] = (IMG_UINT8)((afTable[ui32Tap][ui32I] * 64.0f) / fTotal);
i32Total += aui8Table[ui32Tap][ui32I];
}
if (ui32I <= 8) { /* normalize any floating point errors */
i32Total -= 64;
if (ui32I == 8) {
i32Total /= 2;
}
/* Subtract the error from the I Point in the first tap ( this will not get
mirrored, as it would go off the end). */
aui8Table[0][ui32I] = (IMG_UINT8)(aui8Table[0][ui32I] - (IMG_UINT8)i32Total);
}
}
/* Copy the normalised table around the centre point */
for (ui32Tap = 0; ui32Tap < 2; ui32Tap++) {
for (ui32I = 0; ui32I < 16; ui32I++) {
i32MiddleTap = (3 - ui32Tap) + (16 - ui32I) / 16;
i32MiddleI = (16 - ui32I) & 15;
if ((IMG_UINT32)i32MiddleTap < 4) {
aui8Table[i32MiddleTap][i32MiddleI] = aui8Table[ui32Tap][ui32I];
}
}
}
return ;
}
#endif
static void tng__setvideo_params(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
IMG_MTX_VIDEO_CONTEXT* psMtxEncContext = NULL;
IMG_RC_PARAMS * psRCParams = &(ctx->sRCParams);
//IMG_UINT16 ui16WidthInMbs = (ctx->ui16Width + 15) >> 4;
//IMG_UINT16 ui16FrameHeightInMbs = (ctx->ui16FrameHeight + 15) >> 4;
IMG_INT nIndex;
IMG_UINT8 ui8Flag;
#ifndef EXCLUDE_ADAPTIVE_ROUNDING
IMG_INT32 i, j;
#endif
psb_buffer_map(&(ps_mem->bufs_mtx_context), &(ps_mem->bufs_mtx_context.virtual_addr));
if (ps_mem->bufs_mtx_context.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping slice template\n", __FUNCTION__);
return ;
}
psMtxEncContext = (IMG_MTX_VIDEO_CONTEXT*)(ps_mem->bufs_mtx_context.virtual_addr);
ctx->i32PicNodes = (psRCParams->b16Hierarchical ? MAX_REF_B_LEVELS : 0) + ctx->ui8RefSpacing + 4;
ctx->i32MVStores = (ctx->i32PicNodes * 2);
ctx->ui8SlotsInUse = psRCParams->ui16BFrames + 2;
psMtxEncContext->ui32InitialQp = ctx->sRCParams.ui32InitialQp;
psMtxEncContext->ui32BUSize = ctx->sRCParams.ui32BUSize;
psMtxEncContext->ui16CQPOffset = (ctx->sRCParams.i8QCPOffset & 0x1f) | ((ctx->sRCParams.i8QCPOffset & 0x1f) << 8);
psMtxEncContext->eStandard = ctx->eStandard;
psMtxEncContext->ui32WidthInMbs = ctx->ui16Width >> 4;
psMtxEncContext->ui32PictureHeightInMbs = ctx->ui16PictureHeight >> 4;
psMtxEncContext->bOutputReconstructed = (ps_buf->rec_surface != NULL) ? IMG_TRUE : IMG_FALSE;
psMtxEncContext->ui32VopTimeResolution = ctx->ui32VopTimeResolution;
psMtxEncContext->ui8MaxSlicesPerPicture = ctx->ui8SlicesPerPicture;
psMtxEncContext->ui8NumPipes = ctx->ui8PipesToUse;
psMtxEncContext->eFormat = ctx->eFormat;
psMtxEncContext->b8IsInterlaced = ctx->bIsInterlaced;
psMtxEncContext->b8TopFieldFirst = ctx->bTopFieldFirst;
psMtxEncContext->b8ArbitrarySO = ctx->bArbitrarySO;
psMtxEncContext->ui32IdrPeriod = ctx->ui32IdrPeriod * ctx->ui32IntraCnt;
psMtxEncContext->ui32BFrameCount = ctx->sRCParams.ui16BFrames;
psMtxEncContext->b8Hierarchical = (IMG_BOOL8) ctx->sRCParams.b16Hierarchical;
psMtxEncContext->ui32IntraLoopCnt = ctx->ui32IntraCnt;
psMtxEncContext->ui8RefSpacing = ctx->ui8RefSpacing;
psMtxEncContext->ui32DebugCRCs = ctx->ui32DebugCRCs;
psMtxEncContext->ui8FirstPipe = ctx->ui8BasePipe;
psMtxEncContext->ui8LastPipe = ctx->ui8BasePipe + ctx->ui8PipesToUse - 1;
psMtxEncContext->ui8PipesToUseFlags = 0;
ui8Flag = 0x1 << psMtxEncContext->ui8FirstPipe;
for (nIndex = 0; nIndex < psMtxEncContext->ui8NumPipes; nIndex++, ui8Flag<<=1)
psMtxEncContext->ui8PipesToUseFlags |= ui8Flag; //Pipes used MUST be contiguous from the BasePipe offset
// Only used in MPEG2, 2 bit field (0 = 8 bit, 1 = 9 bit, 2 = 10 bit and 3=11 bit precision)
if (ctx->eStandard == IMG_STANDARD_MPEG2)
psMtxEncContext->ui8MPEG2IntraDCPrecision = ctx->ui8MPEG2IntraDCPrecision;
psMtxEncContext->b16EnableMvc = ctx->bEnableMVC;
psMtxEncContext->ui16MvcViewIdx = ctx->ui16MVCViewIdx;
if (ctx->eStandard == IMG_STANDARD_H264)
psMtxEncContext->b16NoSequenceHeaders = ctx->bNoSequenceHeaders;
{
IMG_UINT16 ui16SrcYStride = 0, ui16SrcUVStride = 0;
// 3 Components: Y, U, V
ctx->ui16BufferStride = ps_buf->src_surface->psb_surface->stride;
ui16SrcUVStride = ui16SrcYStride = ctx->ui16BufferStride;
ctx->ui16BufferHeight = ctx->ui16FrameHeight;
switch (ctx->eFormat) {
case IMG_CODEC_YUV:
case IMG_CODEC_PL8:
case IMG_CODEC_YV12:
ui16SrcUVStride = ui16SrcYStride / 2;
break;
case IMG_CODEC_PL12: // Interleaved chroma pixels
case IMG_CODEC_IMC2: // Interleaved chroma rows
case IMG_CODEC_422_YUV: // Odd-numbered chroma rows unused
case IMG_CODEC_422_YV12: // Odd-numbered chroma rows unused
case IMG_CODEC_422_PL8: // Odd-numbered chroma rows unused
case IMG_CODEC_Y0UY1V_8888: // Interleaved luma and chroma pixels
case IMG_CODEC_Y0VY1U_8888: // Interleaved luma and chroma pixels
case IMG_CODEC_UY0VY1_8888: // Interleaved luma and chroma pixels
case IMG_CODEC_VY0UY1_8888: // Interleaved luma and chroma pixels
ui16SrcUVStride = ui16SrcYStride;
break;
case IMG_CODEC_422_IMC2: // Interleaved chroma pixels and unused odd-numbered chroma rows
case IMG_CODEC_422_PL12: // Interleaved chroma rows and unused odd-numbered chroma rows
ui16SrcUVStride = ui16SrcYStride * 2;
break;
default:
break;
}
if ((ctx->bIsInterlaced) && (ctx->bIsInterleaved)) {
ui16SrcYStride *= 2; // ui16SrcYStride
ui16SrcUVStride *= 2; // ui16SrcUStride
}
psMtxEncContext->ui32PicRowStride = F_ENCODE(ui16SrcYStride >> 6, TOPAZHP_CR_CUR_PIC_LUMA_STRIDE) |
F_ENCODE(ui16SrcUVStride >> 6, TOPAZHP_CR_CUR_PIC_CHROMA_STRIDE);
}
psMtxEncContext->eRCMode = ctx->sRCParams.eRCMode;
psMtxEncContext->b8DisableBitStuffing = ctx->sRCParams.bDisableBitStuffing;
psMtxEncContext->b8FirstPic = IMG_TRUE;
/*Contents Adaptive Rate Control Parameters*/
psMtxEncContext->bCARC = ctx->sCARCParams.bCARC;
psMtxEncContext->iCARCBaseline = ctx->sCARCParams.i32CARCBaseline;
psMtxEncContext->uCARCThreshold = ctx->sCARCParams.ui32CARCThreshold;
psMtxEncContext->uCARCCutoff = ctx->sCARCParams.ui32CARCCutoff;
psMtxEncContext->uCARCNegRange = ctx->sCARCParams.ui32CARCNegRange;
psMtxEncContext->uCARCNegScale = ctx->sCARCParams.ui32CARCNegScale;
psMtxEncContext->uCARCPosRange = ctx->sCARCParams.ui32CARCPosRange;
psMtxEncContext->uCARCPosScale = ctx->sCARCParams.ui32CARCPosScale;
psMtxEncContext->uCARCShift = ctx->sCARCParams.ui32CARCShift;
psMtxEncContext->ui32MVClip_Config = F_ENCODE(ctx->bNoOffscreenMv, TOPAZHP_CR_MVCALC_RESTRICT_PICTURE);
psMtxEncContext->ui32LRITC_Tile_Use_Config = 0;
psMtxEncContext->ui32LRITC_Cache_Chunk_Config = 0;
psMtxEncContext->ui32IPCM_0_Config = F_ENCODE(ctx->ui32CabacBinFlex, TOPAZ_VLC_CR_CABAC_BIN_FLEX) |
F_ENCODE(DEFAULT_CABAC_DB_MARGIN, TOPAZ_VLC_CR_CABAC_DB_MARGIN);
psMtxEncContext->ui32IPCM_1_Config = F_ENCODE(3200, TOPAZ_VLC_CR_IPCM_THRESHOLD) |
F_ENCODE(ctx->ui32CabacBinLimit, TOPAZ_VLC_CR_CABAC_BIN_LIMIT);
// leave alone until high profile and constrained modes are defined.
psMtxEncContext->ui32H264CompControl = F_ENCODE((ctx->bCabacEnabled ? 0 : 1), TOPAZHP_CR_H264COMP_8X8_CAVLC);
psMtxEncContext->ui32H264CompControl |= F_ENCODE(ctx->bUseDefaultScalingList ? 1 : 0, TOPAZHP_CR_H264COMP_DEFAULT_SCALING_LIST);
psMtxEncContext->ui32H264CompControl |= F_ENCODE(ctx->bH2648x8Transform ? 1 : 0, TOPAZHP_CR_H264COMP_8X8_TRANSFORM);
psMtxEncContext->ui32H264CompControl |= F_ENCODE(ctx->bH264IntraConstrained ? 1 : 0, TOPAZHP_CR_H264COMP_CONSTRAINED_INTRA);
#ifndef EXCLUDE_ADAPTIVE_ROUNDING
psMtxEncContext->bMCAdaptiveRoundingDisable = ctx->bVPAdaptiveRoundingDisable;
psMtxEncContext->ui32H264CompControl |= F_ENCODE(psMtxEncContext->bMCAdaptiveRoundingDisable ? 0 : 1, TOPAZHP_CR_H264COMP_ADAPT_ROUND_ENABLE);
if (!psMtxEncContext->bMCAdaptiveRoundingDisable)
for (i = 0; i < 4; i++)
for (j = 0; j < 18; j++)
psMtxEncContext->ui16MCAdaptiveRoundingOffsets[j][i] = H264_ROUNDING_OFFSETS[j][i];
#endif
if ((ctx->eStandard == IMG_STANDARD_H264) && (ctx->ui32CoreRev >= MIN_34_REV)) {
psMtxEncContext->ui32H264CompControl |= F_ENCODE(USE_VCM_HW_SUPPORT, TOPAZHP_CR_H264COMP_VIDEO_CONF_ENABLE);
}
psMtxEncContext->ui32H264CompControl |=
F_ENCODE(ctx->ui16UseCustomScalingLists & 0x01 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_LUMA_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x02 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CB_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x04 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTRA_CR_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x08 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_LUMA_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x10 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CB_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x20 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_4X4_INTER_CR_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x40 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTRA_LUMA_ENABLE)
| F_ENCODE(ctx->ui16UseCustomScalingLists & 0x80 ? 1 : 0, TOPAZHP_CR_H264COMP_CUSTOM_QUANT_8X8_INTER_LUMA_ENABLE);
psMtxEncContext->ui32H264CompControl |=
F_ENCODE(ctx->bEnableLossless ? 1 : 0, INTEL_H264_LL)
| F_ENCODE(ctx->bLossless8x8Prefilter ? 1 : 0, INTEL_H264_LL8X8P);
psMtxEncContext->ui32H264CompIntraPredModes = 0x3ffff;// leave at default for now.
psMtxEncContext->ui32PredCombControl = ctx->ui32PredCombControl;
psMtxEncContext->ui32SkipCodedInterIntra = F_ENCODE(ctx->ui8InterIntraIndex, TOPAZHP_CR_INTER_INTRA_SCALE_IDX)
|F_ENCODE(ctx->ui8CodedSkippedIndex, TOPAZHP_CR_SKIPPED_CODED_SCALE_IDX);
if (ctx->bEnableInpCtrl) {
psMtxEncContext->ui32MBHostCtrl = F_ENCODE(ctx->bEnableHostQP, TOPAZHP_CR_MB_HOST_QP)
|F_ENCODE(ctx->bEnableHostBias, TOPAZHP_CR_MB_HOST_SKIPPED_CODED_SCALE)
|F_ENCODE(ctx->bEnableHostBias, TOPAZHP_CR_MB_HOST_INTER_INTRA_SCALE);
psMtxEncContext->ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE)
|F_ENCODE(1, TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE);
}
if (ctx->bEnableCumulativeBiases)
psMtxEncContext->ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_CUMULATIVE_BIASES_ENABLE);
psMtxEncContext->ui32PredCombControl |=
F_ENCODE((((ctx->ui8InterIntraIndex == 3) && (ctx->ui8CodedSkippedIndex == 3)) ? 0 : 1), TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE) |
F_ENCODE((ctx->ui8CodedSkippedIndex == 3 ? 0 : 1), TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE);
// workaround for BRN 33252, if the Skip coded scale is set then we also have to set the inter/inter enable. We set it enabled and rely on the default value of 3 (unbiased) to keep things behaving.
// psMtxEncContext->ui32PredCombControl |= F_ENCODE((ctx->ui8InterIntraIndex==3?0:1), TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE) | F_ENCODE((ctx->ui8CodedSkippedIndex==3?0:1), TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE);
//psMtxEncContext->ui32PredCombControl |= F_ENCODE(1, TOPAZHP_CR_INTER_INTRA_SCALE_ENABLE) | F_ENCODE(1, TOPAZHP_CR_SKIPPED_CODED_SCALE_ENABLE);
psMtxEncContext->ui32DeblockCtrl = F_ENCODE(ctx->ui8DeblockIDC, TOPAZ_DB_CR_DISABLE_DEBLOCK_IDC);
psMtxEncContext->ui32VLCControl = 0;
switch (ctx->eStandard) {
case IMG_STANDARD_H264:
psMtxEncContext->ui32VLCControl |= F_ENCODE(1, TOPAZ_VLC_CR_CODEC); // 1 for H.264 note this is inconsistant with the sequencer value
psMtxEncContext->ui32VLCControl |= F_ENCODE(0, TOPAZ_VLC_CR_CODEC_EXTEND);
break;
case IMG_STANDARD_H263:
psMtxEncContext->ui32VLCControl |= F_ENCODE(3, TOPAZ_VLC_CR_CODEC); // 3 for H.263 note this is inconsistant with the sequencer value
psMtxEncContext->ui32VLCControl |= F_ENCODE(0, TOPAZ_VLC_CR_CODEC_EXTEND);
break;
case IMG_STANDARD_MPEG4:
psMtxEncContext->ui32VLCControl |= F_ENCODE(2, TOPAZ_VLC_CR_CODEC); // 2 for Mpeg4 note this is inconsistant with the sequencer value
psMtxEncContext->ui32VLCControl |= F_ENCODE(0, TOPAZ_VLC_CR_CODEC_EXTEND);
break;
case IMG_STANDARD_MPEG2:
psMtxEncContext->ui32VLCControl |= F_ENCODE(0, TOPAZ_VLC_CR_CODEC);
psMtxEncContext->ui32VLCControl |= F_ENCODE(1, TOPAZ_VLC_CR_CODEC_EXTEND);
break;
default:
break;
}
if (ctx->bCabacEnabled) {
psMtxEncContext->ui32VLCControl |= F_ENCODE(1, TOPAZ_VLC_CR_CABAC_ENABLE); // 2 for Mpeg4 note this is inconsistant with the sequencer value
}
psMtxEncContext->ui32VLCControl |= F_ENCODE(ctx->bIsInterlaced ? 1 : 0, TOPAZ_VLC_CR_VLC_FIELD_CODED);
psMtxEncContext->ui32VLCControl |= F_ENCODE(ctx->bH2648x8Transform ? 1 : 0, TOPAZ_VLC_CR_VLC_8X8_TRANSFORM);
psMtxEncContext->ui32VLCControl |= F_ENCODE(ctx->bH264IntraConstrained ? 1 : 0, TOPAZ_VLC_CR_VLC_CONSTRAINED_INTRA);
psMtxEncContext->ui32VLCSliceControl = F_ENCODE(ctx->sRCParams.ui32SliceByteLimit, TOPAZ_VLC_CR_SLICE_SIZE_LIMIT);
psMtxEncContext->ui32VLCSliceMBControl = F_ENCODE(ctx->sRCParams.ui32SliceMBLimit, TOPAZ_VLC_CR_SLICE_MBS_LIMIT);
switch (ctx->eStandard) {
case IMG_STANDARD_H264: {
IMG_UINT32 ui32VertMVLimit = 255; // default to no clipping
if (ctx->ui32VertMVLimit)
ui32VertMVLimit = ctx->ui32VertMVLimit;
// as topaz can only cope with at most 255 (in the register field)
ui32VertMVLimit = tng__min(255,ui32VertMVLimit);
// workaround for BRN 29973 and 30032
{
#if defined(BRN_29973) || defined(BRN_30032)
if (ctx->ui32CoreRev <= 0x30006) {
if ((ctx->ui16Width / 16) & 1) // BRN 30032, if odd number of macroblocks we need to limit vector to +-112
psMtxEncContext->ui32IPEVectorClipping = F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED)
|F_ENCODE(112, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X)
|F_ENCODE(ui32VertMVLimit, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
else // for 29973 we need to limit vector to +-120
if (ctx->ui16Width >= 1920)
psMtxEncContext->ui32IPEVectorClipping = F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED)
|F_ENCODE(120, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X)
|F_ENCODE(ui32VertMVLimit, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
else
psMtxEncContext->ui32IPEVectorClipping = F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED)
|F_ENCODE(255, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X)
|F_ENCODE(ui32VertMVLimit, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
} else
#endif
{
psMtxEncContext->ui32IPEVectorClipping =
F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED) |
F_ENCODE(255, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X) |
F_ENCODE(ui32VertMVLimit, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
}
}
psMtxEncContext->ui32SPEMvdClipRange = F_ENCODE(0, TOPAZHP_CR_SPE_MVD_CLIP_ENABLE);
}
break;
case IMG_STANDARD_H263:
{
psMtxEncContext->ui32IPEVectorClipping = F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED)
| F_ENCODE(16 - 1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X)
| F_ENCODE(16 - 1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
psMtxEncContext->ui32SPEMvdClipRange = F_ENCODE(1, TOPAZHP_CR_SPE_MVD_CLIP_ENABLE)
| F_ENCODE( 62, TOPAZHP_CR_SPE_MVD_POS_CLIP)
| F_ENCODE((uint32_t)(-64), TOPAZHP_CR_SPE_MVD_NEG_CLIP);
}
break;
case IMG_STANDARD_MPEG4:
case IMG_STANDARD_MPEG2:
{
IMG_UINT8 uX, uY, uResidualSize;
//The maximum MPEG4 and MPEG2 motion vector differential in 1/2 pixels is
//calculated as 1 << (fcode - 1) * 32 or *16 in MPEG2
uResidualSize=(ctx->eStandard == IMG_STANDARD_MPEG4 ? 32 : 16);
uX = tng__min(128 - 1, (((1<<(ctx->sBiasTables.ui32FCode - 1)) * uResidualSize)/4) - 1);
uY = tng__min(104 - 1, (((1<<(ctx->sBiasTables.ui32FCode - 1)) * uResidualSize)/4) - 1);
//Write to register
psMtxEncContext->ui32IPEVectorClipping = F_ENCODE(1, TOPAZHP_CR_IPE_VECTOR_CLIPPING_ENABLED)
| F_ENCODE(uX, TOPAZHP_CR_IPE_VECTOR_CLIPPING_X)
| F_ENCODE(uY, TOPAZHP_CR_IPE_VECTOR_CLIPPING_Y);
psMtxEncContext->ui32SPEMvdClipRange = F_ENCODE(0, TOPAZHP_CR_SPE_MVD_CLIP_ENABLE);
}
break;
case IMG_STANDARD_JPEG:
case IMG_STANDARD_NONE:
default:
break;
}
#ifdef FIRMWARE_BIAS
//copy the bias tables
{
int n;
for (n = 52; n >= 0; n -= 2) {
psMtxEncContext->aui32DirectBias_P[n >> 1] = ctx->sBiasTables.aui32DirectBias_P[n];
psMtxEncContext->aui32InterBias_P[n >> 1] = ctx->sBiasTables.aui32InterBias_P[n];
psMtxEncContext->aui32DirectBias_B[n >> 1] = ctx->sBiasTables.aui32DirectBias_B[n];
psMtxEncContext->aui32InterBias_B[n >> 1] = ctx->sBiasTables.aui32InterBias_B[n];
}
}
#endif
//copy the scale-tables
tng__generate_scale_tables(psMtxEncContext);
// memcpy(psMtxEncContext->ui32InterIntraScale, ctx->ui32InterIntraScale, sizeof(IMG_UINT32)*SCALE_TBL_SZ);
// memcpy(psMtxEncContext->ui32SkippedCodedScale, ctx->ui32SkippedCodedScale, sizeof(IMG_UINT32)*SCALE_TBL_SZ);
// WEIGHTED PREDICTION
psMtxEncContext->b8WeightedPredictionEnabled = ctx->bWeightedPrediction;
psMtxEncContext->ui8MTXWeightedImplicitBiPred = ctx->ui8VPWeightedImplicitBiPred;
// SEI_INSERTION
psMtxEncContext->b8InsertHRDparams = ctx->bInsertHRDParams;
if (psMtxEncContext->b8InsertHRDparams & !ctx->sRCParams.ui32BitsPerSecond) { //ctx->uBitRate
/* HRD parameters are meaningless without a bitrate */
psMtxEncContext->b8InsertHRDparams = IMG_FALSE;
}
if (psMtxEncContext->b8InsertHRDparams) {
psMtxEncContext->ui64ClockDivBitrate = (90000 * 0x100000000LL);
psMtxEncContext->ui64ClockDivBitrate /= ctx->sRCParams.ui32BitsPerSecond; //ctx->uBitRate;
psMtxEncContext->ui32MaxBufferMultClockDivBitrate = (IMG_UINT32)(((IMG_UINT64)(ctx->sRCParams.ui32BufferSize) *
(IMG_UINT64) 90000) / (IMG_UINT64) ctx->sRCParams.ui32BitsPerSecond);
}
memcpy(&psMtxEncContext->sInParams, &ctx->sPicParams.sInParams, sizeof(IN_RC_PARAMS));
// Update MV Scaling settings
// IDR
// memcpy(&psMtxEncContext->sMVSettingsIdr, &ctx->sMVSettingsIdr, sizeof(IMG_MV_SETTINGS));
// NonB (I or P)
// for (i = 0; i <= MAX_BFRAMES; i++)
// memcpy(&psMtxEncContext->sMVSettingsNonB[i], &ctx->sMVSettingsNonB[i], sizeof(IMG_MV_SETTINGS));
psMtxEncContext->ui32LRITC_Cache_Chunk_Config =
F_ENCODE(ctx->uChunksPerMb, INTEL_CH_PM) |
F_ENCODE(ctx->uMaxChunks, INTEL_CH_MX) |
F_ENCODE(ctx->uMaxChunks - ctx->uPriorityChunks, INTEL_CH_PY);
//they would be set in function tng__prepare_templates()
psMtxEncContext->ui32FirstPicFlags = ctx->ui32FirstPicFlags;
psMtxEncContext->ui32NonFirstPicFlags = ctx->ui32NonFirstPicFlags;
#ifdef LTREFHEADER
psMtxEncContext->i8SliceHeaderSlotNum = -1;
#endif
{
memset(psMtxEncContext->aui8PicOnLevel, 0, sizeof(psMtxEncContext->aui8PicOnLevel));
psb_buffer_map(&(ps_mem->bufs_flat_gop), &(ps_mem->bufs_flat_gop.virtual_addr));
if (ps_mem->bufs_flat_gop.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping flat gop\n", __FUNCTION__);
return ;
}
tng__minigop_generate_flat(ps_mem->bufs_flat_gop.virtual_addr, psMtxEncContext->ui32BFrameCount,
psMtxEncContext->ui8RefSpacing, psMtxEncContext->aui8PicOnLevel);
psb_buffer_unmap(&(ps_mem->bufs_flat_gop));
if (ctx->sRCParams.b16Hierarchical) {
memset(psMtxEncContext->aui8PicOnLevel, 0, sizeof(psMtxEncContext->aui8PicOnLevel));
psb_buffer_map(&(ps_mem->bufs_hierar_gop), &(ps_mem->bufs_hierar_gop.virtual_addr));
if (ps_mem->bufs_hierar_gop.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping sei header\n", __FUNCTION__);
return ;
}
tng_minigop_generate_hierarchical(ps_mem->bufs_hierar_gop.virtual_addr, psMtxEncContext->ui32BFrameCount,
psMtxEncContext->ui8RefSpacing, psMtxEncContext->aui8PicOnLevel);
psb_buffer_unmap(&(ps_mem->bufs_hierar_gop));
}
}
#if INPUT_SCALER_SUPPORTED
if (ctx->bEnableScaler) {
IMG_UINT8 sccCoeffs[4][16];
IMG_UINT32 ui32PitchX, ui32PitchY;
IMG_INT32 i32Phase, i32Tap;
ui32PitchX = (((IMG_UINT32)(psVideoParams->ui16SourceWidth - psVideoParams->ui8CropLeft - psVideoParams->ui8CropRight)) << 12) / psVideoParams->ui16Width;
ui32PitchY = (((IMG_UINT32)(psVideoParams->ui16SourceFrameHeight - psVideoParams->ui8CropTop - psVideoParams->ui8CropBottom)) << 12) / psVideoParams->ui16FrameHeight;
// Input size
psMtxEncContext->ui32ScalerInputSizeReg = F_ENCODE(psVideoParams->ui16SourceWidth - 1, TOPAZHP_EXT_CR_SCALER_INPUT_WIDTH_MIN1) |
F_ENCODE((psVideoParams->ui16SourceFrameHeight >> (psVideo->bIsInterlaced ? 1 : 0)) - 1, TOPAZHP_EXT_CR_SCALER_INPUT_HEIGHT_MIN1);
psMtxEncContext->ui32ScalerCropReg = F_ENCODE(psVideoParams->ui8CropLeft, TOPAZHP_EXT_CR_SCALER_INPUT_CROP_HOR) |
F_ENCODE(psVideoParams->ui8CropTop, TOPAZHP_EXT_CR_SCALER_INPUT_CROP_VER);
// Scale factors
psMtxEncContext->ui32ScalerPitchReg = 0;
if (ui32PitchX > 0x3FFF) {
psMtxEncContext->ui32ScalerPitchReg |= F_ENCODE(1, TOPAZHP_EXT_CR_SCALER_HOR_BILINEAR_FILTER);
ui32PitchX >>= 1;
}
if (ui32PitchX > 0x3FFF) {
ui32PitchX = 0x3FFF;
}
if (ui32PitchY > 0x3FFF) {
psMtxEncContext->ui32ScalerPitchReg |= F_ENCODE(1, TOPAZHP_EXT_CR_SCALER_VER_BILINEAR_FILTER);
ui32PitchY >>= 1;
}
if (ui32PitchY > 0x3FFF) {
ui32PitchY = 0x3FFF;
}
psMtxEncContext->ui32ScalerPitchReg |= F_ENCODE(ui32PitchX, TOPAZHP_EXT_CR_SCALER_INPUT_HOR_PITCH) |
F_ENCODE(ui32PitchY, TOPAZHP_EXT_CR_SCALER_INPUT_VER_PITCH);
// Coefficients
VIDEO_CalcCoefs_FromPitch(((IMG_FLOAT)ui32PitchX) / 4096.0f, sccCoeffs);
for (i32Phase = 0; i32Phase < 4; i32Phase++) {
psMtxEncContext->asHorScalerCoeffRegs[i32Phase] = 0;
for (i32Tap = 0; i32Tap < 4; i32Tap++) {
psMtxEncContext->asHorScalerCoeffRegs[i32Phase] |= F_ENCODE(sccCoeffs[3 - i32Tap][(i32Phase * 2) + 1], TOPAZHP_EXT_CR_SCALER_HOR_LUMA_COEFF(i32Tap));
}
}
VIDEO_CalcCoefs_FromPitch(((IMG_FLOAT)ui32PitchY) / 4096.0f, sccCoeffs);
for (i32Phase = 0; i32Phase < 4; i32Phase++) {
psMtxEncContext->asVerScalerCoeffRegs[i32Phase] = 0;
for (i32Tap = 0; i32Tap < 4; i32Tap++) {
psMtxEncContext->asVerScalerCoeffRegs[i32Phase] |= F_ENCODE(sccCoeffs[3 - i32Tap][(i32Phase * 2) + 1], TOPAZHP_EXT_CR_SCALER_VER_LUMA_COEFF(i32Tap));
}
}
} else {
// Disable scaling
psMtxEncContext->ui32ScalerInputSizeReg = 0;
}
#endif // INPUT_SCALER_SUPPORTED
psb_buffer_unmap(&(ps_mem->bufs_mtx_context));
return ;
}
static void tng__setvideo_cmdbuf(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
context_ENC_mem_size *ps_mem_size = &(ctx->ctx_mem_size);
#ifndef _TNG_FRAMES_
context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
#endif
IMG_MTX_VIDEO_CONTEXT* psMtxEncContext = NULL;
IMG_INT32 i;
psb_buffer_map(&(ps_mem->bufs_mtx_context), &(ps_mem->bufs_mtx_context.virtual_addr));
if (ps_mem->bufs_mtx_context.virtual_addr == NULL) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s error: mapping sei header\n", __FUNCTION__);
return ;
}
psMtxEncContext = (IMG_MTX_VIDEO_CONTEXT*)(ps_mem->bufs_mtx_context.virtual_addr);
tng_cmdbuf_set_phys(&(psMtxEncContext->ui32MVSettingsBTable), 0,
&(ps_mem->bufs_mv_setting_btable), 0, 0);
if (ctx->sRCParams.b16Hierarchical)
tng_cmdbuf_set_phys(&psMtxEncContext->ui32MVSettingsHierarchical, 0,
&(ps_mem->bufs_mv_setting_hierar), 0, 0);
#ifdef _TNG_FRAMES_
tng_cmdbuf_set_phys(psMtxEncContext->apReconstructured, ctx->i32PicNodes,
&(ps_mem->bufs_recon_pictures), 0, ps_mem_size->recon_pictures);
#else
for (i = 0; i < ctx->i32PicNodes; i++) {
tng_cmdbuf_set_phys(&(psMtxEncContext->apReconstructured[i]), 0,
&(ps_buf->ref_surface[i]->psb_surface->buf), 0, 0);
}
#endif
tng_cmdbuf_set_phys(psMtxEncContext->apColocated, ctx->i32PicNodes,
&(ps_mem->bufs_colocated), 0, ps_mem_size->colocated);
tng_cmdbuf_set_phys(psMtxEncContext->apMV, ctx->i32MVStores,
&(ps_mem->bufs_mv), 0, ps_mem_size->mv);
if (ctx->bEnableMVC) {
tng_cmdbuf_set_phys(psMtxEncContext->apInterViewMV, 2,
&(ps_mem->bufs_interview_mv), 0, ps_mem_size->interview_mv);
}
tng_cmdbuf_set_phys(psMtxEncContext->apWritebackRegions, WB_FIFO_SIZE,
&(ctx->bufs_writeback), 0, ps_mem_size->writeback);
tng_cmdbuf_set_phys(psMtxEncContext->apAboveParams, (IMG_UINT32)(ctx->ui8PipesToUse),
&(ps_mem->bufs_above_params), 0, ps_mem_size->above_params);
// SEI_INSERTION
if (ctx->bInsertHRDParams) {
tng_cmdbuf_set_phys(&psMtxEncContext->pSEIBufferingPeriodTemplate, 0,
&(ps_mem->bufs_sei_header), ps_mem_size->sei_header, ps_mem_size->sei_header);
tng_cmdbuf_set_phys(&psMtxEncContext->pSEIPictureTimingTemplate, 0,
&(ps_mem->bufs_sei_header), ps_mem_size->sei_header * 2, ps_mem_size->sei_header);
}
tng_cmdbuf_set_phys(psMtxEncContext->apSliceParamsTemplates, NUM_SLICE_TYPES,
&(ps_mem->bufs_slice_template), 0, ps_mem_size->slice_template);
tng_cmdbuf_set_phys(psMtxEncContext->aui32SliceMap, ctx->ui8SlotsInUse,
&(ps_mem->bufs_slice_map), 0, ps_mem_size->slice_map);
// WEIGHTED PREDICTION
if (ctx->bWeightedPrediction || (ctx->ui8VPWeightedImplicitBiPred == WBI_EXPLICIT)) {
tng_cmdbuf_set_phys(psMtxEncContext->aui32WeightedPredictionVirtAddr, ctx->ui8SlotsInUse,
&(ps_mem->bufs_weighted_prediction), 0, ps_mem_size->weighted_prediction);
}
tng_cmdbuf_set_phys(&psMtxEncContext->ui32FlatGopStruct, 0, &(ps_mem->bufs_flat_gop), 0, 0);
if (psMtxEncContext->b8Hierarchical)
tng_cmdbuf_set_phys(&psMtxEncContext->ui32HierarGopStruct, 0, &(ps_mem->bufs_hierar_gop), 0, 0);
#ifdef LTREFHEADER
tng_cmdbuf_set_phys(psMtxEncContext->aui32LTRefHeader, ctx->ui8SlotsInUse,
&(ps_mem->bufs_lt_ref_header), 0, ps_mem_size->lt_ref_header);
#endif
tng_cmdbuf_set_phys(psMtxEncContext->apPicHdrTemplates, 4,
&(ps_mem->bufs_pic_template), 0, ps_mem_size->pic_template);
if (ctx->eStandard == IMG_STANDARD_H264) {
tng_cmdbuf_set_phys(&(psMtxEncContext->apSeqHeader), 0,
&(ps_mem->bufs_seq_header), 0, ps_mem_size->seq_header);
if (ctx->bEnableMVC)
tng_cmdbuf_set_phys(&(psMtxEncContext->apSubSetSeqHeader), 0,
&(ps_mem->bufs_sub_seq_header), 0, ps_mem_size->seq_header);
}
if (ctx->ui8EnableSelStatsFlags & ESF_FIRST_STAGE_STATS) {
tng_cmdbuf_set_phys(psMtxEncContext->pFirstPassOutParamAddr, ctx->ui8SlotsInUse,
&(ps_mem->bufs_first_pass_out_params), 0, ps_mem_size->first_pass_out_params);
}
#ifndef EXCLUDE_BEST_MP_DECISION_DATA
// Store the feedback memory address for all "5" slots in the context
if (ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MB_DECISION_STATS
|| ctx->ui8EnableSelStatsFlags & ESF_MP_BEST_MOTION_VECTOR_STATS) {
tng_cmdbuf_set_phys(psMtxEncContext->pFirstPassOutBestMultipassParamAddr, ctx->ui8SlotsInUse,
&(ps_mem->bufs_first_pass_out_best_multipass_param), 0, ps_mem_size->first_pass_out_best_multipass_param);
}
#endif
//Store the MB-Input control parameter memory for all the 5-slots in the context
if (ctx->bEnableInpCtrl) {
tng_cmdbuf_set_phys(psMtxEncContext->pMBCtrlInParamsAddr, ctx->ui8SlotsInUse,
&(ps_mem->bufs_mb_ctrl_in_params), 0, ps_mem_size->mb_ctrl_in_params);
}
psb_buffer_unmap(&(ps_mem->bufs_mtx_context));
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s end\n", __FUNCTION__);
return ;
}
static VAStatus tng__validate_params(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT16 ui16WidthInMbs = (ctx->ui16Width + 15) >> 4;
IMG_UINT16 ui16PictureHeight = ((ctx->ui16FrameHeight >> (ctx->bIsInterlaced ? 1 : 0)) + 15) & ~15;
IMG_UINT16 ui16FrameHeightInMbs = (ctx->ui16FrameHeight + 15) >> 4;
if ((ctx->ui16Width & 0xf) != 0) {
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if ((ctx->ui16FrameHeight & 0xf) != 0) {
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
ctx->uMBspS = ui16WidthInMbs * ui16FrameHeightInMbs * ctx->sRCParams.ui32FrameRate;
if (ctx->ui32CoreRev >= MIN_36_REV) {
if ((ctx->ui16Width > 4096) || (ctx->ui16PictureHeight > 4096)) {
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if ((ui16WidthInMbs << 4) * ui16PictureHeight > 2048 * 2048) {
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
} else {
if ((ctx->ui16Width > 2048) || (ui16PictureHeight > 2048)) {
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
if (ctx->eStandard == IMG_STANDARD_H264) {
if ((ctx->ui8DeblockIDC == 0) && (ctx->bArbitrarySO))
ctx->ui8DeblockIDC = 2;
if ((ctx->ui8DeblockIDC == 0) && ((IMG_UINT32)(ctx->ui8PipesToUse) > 1) && (ctx->ui8SlicesPerPicture > 1)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "WARNING: Full deblocking with multiple pipes will cause a mismatch between reconstructed and encoded video\n");
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Consider using -deblockIDC 2 or -deblockIDC 1 instead if matching reconstructed video is required.\n");
drv_debug_msg(VIDEO_DEBUG_GENERAL, "WARNING: Forcing -deblockIDC = 2 for HW verification.\n");
ctx->ui8DeblockIDC = 2;
}
} else if (ctx->eStandard == IMG_STANDARD_H263) {
ctx->bArbitrarySO = IMG_FALSE;
ctx->ui8DeblockIDC = 1;
} else {
ctx->ui8DeblockIDC = 1;
}
//ctx->sRCParams.ui32SliceByteLimit = 0;
ctx->sRCParams.ui32SliceMBLimit = 0;
//slice params
if (ctx->ui8SlicesPerPicture == 0)
ctx->ui8SlicesPerPicture = ctx->sCapsParams.ui16RecommendedSlices;
else {
if (ctx->ui8SlicesPerPicture > ctx->sCapsParams.ui16MaxSlices)
ctx->ui8SlicesPerPicture = ctx->sCapsParams.ui16MaxSlices;
else if (ctx->ui8SlicesPerPicture < ctx->sCapsParams.ui16MinSlices)
ctx->ui8SlicesPerPicture = ctx->sCapsParams.ui16MinSlices;
}
if (ctx->ui32pseudo_rand_seed == UNINIT_PARAM) {
// When -randseed is uninitialised, initialise seed using other commandline values
ctx->ui32pseudo_rand_seed = (IMG_UINT32) ((ctx->sRCParams.ui32InitialQp +
ctx->ui16PictureHeight + ctx->ui16Width + ctx->sRCParams.ui32BitsPerSecond) & 0xffffffff);
// iQP_Luma + pParams->uHeight + pParams->uWidth + pParams->uBitRate) & 0xffffffff);
}
if (ctx->eStandard == IMG_STANDARD_H264) {
ctx->ui8PipesToUse = tng__min(ctx->ui8PipesToUse, ctx->ui8SlicesPerPicture);
} else {
ctx->ui8PipesToUse = 1;
}
return vaStatus;
}
static VAStatus tng__validate_busize(context_ENC_p ctx)
{
//IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
// if no BU size is given then pick one ourselves, if doing arbitrary slice order then make BU = width in bu's
// forces slice boundaries to no be mid-row
if (ctx->bArbitrarySO || (ctx->ui32BasicUnit == 0)) {
ctx->ui32BasicUnit = (ctx->ui16Width / 16);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Patched Basic unit to %d\n", ctx->ui32BasicUnit);
} else {
IMG_UINT32 ui32MBs, ui32MBsperSlice, ui32MBsLastSlice;
IMG_UINT32 ui32BUs;
IMG_INT32 i32SliceHeight;
IMG_UINT32 ui32MaxSlicesPerPipe, ui32MaxMBsPerPipe, ui32MaxBUsPerPipe;
ui32MBs = ctx->ui16PictureHeight * ctx->ui16Width / (16 * 16);
i32SliceHeight = ctx->ui16PictureHeight / ctx->ui8SlicesPerPicture;
i32SliceHeight &= ~15;
ui32MBsperSlice = (i32SliceHeight * ctx->ui16Width) / (16 * 16);
ui32MBsLastSlice = ui32MBs - (ui32MBsperSlice * (ctx->ui8SlicesPerPicture - 1));
// they have given us a basic unit so validate it
if (ctx->ui32BasicUnit < 6) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size too small, must be greater than 6\n");
return VA_STATUS_ERROR_UNKNOWN;
}
if (ctx->ui32BasicUnit > ui32MBsperSlice) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size(%d) too large", ctx->ui32BasicUnit);
drv_debug_msg(VIDEO_DEBUG_GENERAL, " must not be greater than the number of macroblocks in a slice (%d)\n", ui32MBsperSlice);
return VA_STATUS_ERROR_UNKNOWN;
}
if (ctx->ui32BasicUnit > ui32MBsLastSlice) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size(%d) too large", ctx->ui32BasicUnit);
drv_debug_msg(VIDEO_DEBUG_GENERAL, " must not be greater than the number of macroblocks in a slice (%d)\n", ui32MBsLastSlice);
return VA_STATUS_ERROR_UNKNOWN;
}
ui32BUs = ui32MBsperSlice / ctx->ui32BasicUnit;
if ((ui32BUs * ctx->ui32BasicUnit) != ui32MBsperSlice) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size(%d) not an integer divisor of MB's in a slice(%d)",
ctx->ui32BasicUnit, ui32MBsperSlice);
return VA_STATUS_ERROR_UNKNOWN;
}
ui32BUs = ui32MBsLastSlice / ctx->ui32BasicUnit;
if ((ui32BUs * ctx->ui32BasicUnit) != ui32MBsLastSlice) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size(%d) not an integer divisor of MB's in the last slice(%d)",
ctx->ui32BasicUnit, ui32MBsLastSlice);
return VA_STATUS_ERROR_UNKNOWN;
}
// check if the number of BUs per pipe is greater than 200
ui32MaxSlicesPerPipe = (IMG_UINT32)(ctx->ui8SlicesPerPicture + ctx->ui8PipesToUse - 1) / (IMG_UINT32)(ctx->ui8PipesToUse);
ui32MaxMBsPerPipe = (ui32MBsperSlice * (ui32MaxSlicesPerPipe - 1)) + ui32MBsLastSlice;
ui32MaxBUsPerPipe = (ui32MaxMBsPerPipe + ctx->ui32BasicUnit - 1) / ctx->ui32BasicUnit;
if (ui32MaxBUsPerPipe > 200) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "\nERROR: Basic unit size too small. There must be less than 201 basic units per slice");
return VA_STATUS_ERROR_UNKNOWN;
}
}
ctx->sRCParams.ui32BUSize = ctx->ui32BasicUnit;
return VA_STATUS_SUCCESS;
}
static VAStatus tng__cmdbuf_new_codec(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
psb_driver_data_p driver_data = ctx->obj_context->driver_data;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[0]);
*cmdbuf->cmd_idx++ =
((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
((ctx->eCodec & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT) |
(((driver_data->context_id & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
// (((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
tng_cmdbuf_insert_command_param((ctx->ui16Width << 16) | ctx->ui16PictureHeight);
return vaStatus;
}
static VAStatus tng__cmdbuf_doheader(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
cmdbuf->cmd_idx_saved[TNG_CMDBUF_PIC_HEADER_IDX] = cmdbuf->cmd_idx;
tng_cmdbuf_insert_command(ctx->obj_context, 0,
MTX_CMDID_DO_HEADER,
0,
&(ps_mem->bufs_seq_header),
0);
return vaStatus;
}
static VAStatus tng__cmdbuf_lowpower(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
psb_driver_data_p driver_data = ctx->obj_context->driver_data;
*cmdbuf->cmd_idx++ =
((MTX_CMDID_SW_LEAVE_LOWPOWER & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
(((ctx->ui32RawFrameCount == 0 ? 1 : 0) & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT) |
(((driver_data->context_id & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
tng_cmdbuf_insert_command_param(ctx->eCodec);
return vaStatus;
}
static VAStatus tng__cmdbuf_load_bias(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
//init bias parameters
tng_init_bias_params(ctx);
vaStatus = tng__generate_bias(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: generate bias params\n", __FUNCTION__, vaStatus);
}
vaStatus = tng_load_bias(ctx, IMG_INTER_P);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: load bias params\n", __FUNCTION__, vaStatus);
}
return vaStatus;
}
static VAStatus tng__cmdbuf_setvideo(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[ui32StreamIndex]);
tng__setvideo_params(ctx, ui32StreamIndex);
tng__setvideo_cmdbuf(ctx, ui32StreamIndex);
tng_cmdbuf_insert_command(ctx->obj_context, ctx->ui32StreamID,
MTX_CMDID_SETVIDEO, 0, &(ps_mem->bufs_mtx_context), 0);
return vaStatus;
}
static void tng__rc_update(
context_ENC_p ctx,
IMG_UINT32 ui32NewBitrate,
IMG_UINT8 ui8NewFrameQP,
IMG_UINT8 ui8NewFrameMinQP,
IMG_UINT8 ui8NewFrameMaxQP,
IMG_UINT16 ui16NewIntraPeriod)
{
psb_buffer_p buf = (psb_buffer_p)(F_ENCODE(ui8NewFrameMinQP, MTX_MSG_RC_UPDATE_MIN_QP) |
F_ENCODE(ui8NewFrameMaxQP, MTX_MSG_RC_UPDATE_MAX_QP) |
F_ENCODE(ui16NewIntraPeriod, MTX_MSG_RC_UPDATE_INTRA));
tng_cmdbuf_insert_command(
ctx->obj_context,
ctx->ui32StreamID,
MTX_CMDID_RC_UPDATE,
F_ENCODE(ui8NewFrameQP, MTX_MSG_RC_UPDATE_QP) |
F_ENCODE(ui32NewBitrate, MTX_MSG_RC_UPDATE_BITRATE),
buf,
0);
}
static VAStatus tng__update_ratecontrol(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
IMG_UINT32 ui32CmdData = 0;
IMG_UINT32 ui32NewBitsPerFrame = 0;
IMG_UINT8 ui8NewVCMIFrameQP = 0;
if (!(ctx->rc_update_flag))
return vaStatus;
tng__setup_rcdata(ctx);
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: frame[%d] bits_per_second = %d, min_qp = %d, max_qp = %d, initial_qp = %d\n",
__FUNCTION__, ctx->ui32FrameCount[ui32StreamIndex], psRCParams->ui32BitsPerSecond,
psRCParams->iMinQP, ctx->max_qp, psRCParams->ui32InitialQp);
if (ctx->rc_update_flag & RC_MASK_frame_rate) {
tng__rc_update(ctx, psRCParams->ui32BitsPerSecond, -1, -1, -1, -1);
ctx->rc_update_flag &= ~RC_MASK_frame_rate;
}
if (ctx->rc_update_flag & RC_MASK_bits_per_second) {
tng__rc_update(ctx, psRCParams->ui32BitsPerSecond, -1, -1, -1, -1);
ctx->rc_update_flag &= ~RC_MASK_bits_per_second;
}
if (ctx->rc_update_flag & RC_MASK_min_qp) {
tng__rc_update(ctx, -1, -1, psRCParams->iMinQP, -1, -1);
ctx->rc_update_flag &= ~RC_MASK_min_qp;
}
if (ctx->rc_update_flag & RC_MASK_max_qp) {
tng__rc_update(ctx, -1, -1, -1, ctx->max_qp, -1);
ctx->rc_update_flag &= ~RC_MASK_max_qp;
}
if (ctx->rc_update_flag & RC_MASK_initial_qp) {
tng__rc_update(ctx, -1, psRCParams->ui32InitialQp, -1, -1, -1);
ctx->rc_update_flag &= ~RC_MASK_initial_qp;
}
if (ctx->rc_update_flag & RC_MASK_intra_period) {
tng__rc_update(ctx, -1, -1, -1, -1, ctx->ui32IntraCnt);
ctx->rc_update_flag &= ~RC_MASK_intra_period;
}
return vaStatus;
}
static VAStatus tng__update_frametype(context_ENC_p ctx, IMG_FRAME_TYPE eFrameType)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT32 ui32CmdData = 0;
ui32CmdData = F_ENCODE(IMG_PICMGMT_REF_TYPE, MTX_MSG_PICMGMT_SUBTYPE) |
F_ENCODE(eFrameType, MTX_MSG_PICMGMT_DATA);
tng_cmdbuf_insert_command(ctx->obj_context, ctx->ui32StreamID,
MTX_CMDID_PICMGMT ,
ui32CmdData, 0, 0);
return vaStatus;
}
static VAStatus tng__cmdbuf_send_picmgmt(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
if (!(ctx->rc_update_flag))
return vaStatus;
//tng__setup_rcdata(ctx);
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: ui32BitsPerSecond = %d, ui32FrameRate = %d, ui32InitialQp = %d\n",
__FUNCTION__, psRCParams->ui32BitsPerSecond,
psRCParams->ui32FrameRate, psRCParams->ui32InitialQp);
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: frame_count[%d] = %d\n", __FUNCTION__,
ui32StreamIndex, ctx->ui32FrameCount[ui32StreamIndex]);
return vaStatus;
}
static VAStatus tng__cmdbuf_provide_buffer(context_ENC_p ctx, IMG_UINT32 ui32StreamIndex)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
if (ctx->ui8PipesToUse == 1) {
tng_send_codedbuf(ctx, ctx->ui8SlotsCoded);
} else {
/*Make sure DMA start is 128bits alignment*/
tng_send_codedbuf(ctx, ctx->ui8SlotsCoded * 2);
tng_send_codedbuf(ctx, ctx->ui8SlotsCoded * 2 + 1);
}
if (ctx->sRCParams.ui16BFrames > 0)
tng__provide_buffer_BFrames(ctx, ui32StreamIndex);
else
tng__provide_buffer_PFrames(ctx, ui32StreamIndex);
/*
if (ctx->ui32LastPicture != 0) {
drv_debug_msg(VIDEO_DEBUG_GENERAL,
"%s: frame_count[%d] = %d\n", __FUNCTION__,
ui32StreamIndex, ctx->ui32FrameCount[ui32StreamIndex]);
tng_picmgmt_update(ctx,IMG_PICMGMT_EOS, ctx->ui32LastPicture);
}
*/
#ifdef _TOPAZHP_REC_
tng_send_rec_frames(ctx, -1, 0);
tng_send_ref_frames(ctx, 0, 0);
tng_send_ref_frames(ctx, 1, 0);
#endif
ctx->ui8SlotsCoded = (ctx->ui8SlotsCoded + 1) & 1;
return vaStatus;
}
VAStatus tng__set_ctx_buf(context_ENC_p ctx, IMG_UINT32 __maybe_unused ui32StreamID)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT8 ui8IsJpeg;
vaStatus = tng__validate_params(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "validate params");
}
vaStatus = tng__validate_busize(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "validate busize");
}
ctx->ctx_cmdbuf[0].ui32LowCmdCount = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT;
ctx->ctx_cmdbuf[0].ui32HighCmdCount = 0;
ctx->ctx_cmdbuf[0].ui32HighWBReceived = 0;
ui8IsJpeg = (ctx->eStandard == IMG_STANDARD_JPEG) ? 1 : 0;
vaStatus = tng__alloc_context_buffer(ctx, ui8IsJpeg, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "setup enc profile");
}
return vaStatus;
}
static VAStatus tng__set_headers (context_ENC_p ctx, IMG_UINT32 __maybe_unused ui32StreamID)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT8 ui8SlotIdx = 0;
vaStatus = tng__prepare_templates(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "prepare_templates\n");
}
for (ui8SlotIdx = 0; ui8SlotIdx < ctx->ui8SlotsInUse; ui8SlotIdx++)
tng_fill_slice_map(ctx, (IMG_UINT32)ui8SlotIdx, 0);
return vaStatus;
}
static VAStatus tng__set_cmd_buf(context_ENC_p ctx, IMG_UINT32 __maybe_unused ui32StreamID)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
vaStatus = tng__cmdbuf_new_codec(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf new codec\n");
}
vaStatus = tng__cmdbuf_lowpower(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf lowpower\n");
}
vaStatus = tng__cmdbuf_load_bias(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf load bias\n");
}
vaStatus = tng__cmdbuf_setvideo(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf setvideo\n");
}
return vaStatus;
}
VAStatus tng__end_one_frame(context_ENC_p ctx, IMG_UINT32 ui32StreamID)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32StreamID is %d.\n", ui32StreamID);
/* save current settings */
ps_buf->previous_src_surface = ps_buf->src_surface;
#ifdef _TNG_FRAMES_
ps_buf->previous_ref_surface = ps_buf->ref_surface;
#else
ps_buf->previous_ref_surface = ps_buf->ref_surface[0];
#endif
/*Frame Skip flag in Coded Buffer of frame N determines if frame N+2
* should be skipped, which means sending encoding commands of frame N+1 doesn't
* have to wait until frame N is completed encoded. It reduces the precision of
* rate control but improves HD encoding performance a lot.*/
ps_buf->pprevious_coded_buf = ps_buf->previous_coded_buf;
ps_buf->previous_coded_buf = ps_buf->coded_buf;
ctx->ePreFrameType = ctx->eFrameType;
return vaStatus;
}
VAStatus tng_EndPicture(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
context_ENC_mem *ps_mem = &(ctx->ctx_mem[0]);
unsigned int offset;
int value;
drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: ctx->ui8SlicesPerPicture = %d, ctx->ui32FrameCount[0] = %d\n",
__FUNCTION__, ctx->ui8SlicesPerPicture, ctx->ui32FrameCount[0]);
if (ctx->ui32FrameCount[0] == 0) {
vaStatus = tng__set_ctx_buf(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "set ctx buf \n");
}
vaStatus = tng__set_headers(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "set headers \n");
}
vaStatus = tng__set_cmd_buf(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "set cmd buf \n");
}
#ifdef _TOPAZHP_PDUMP_
tng_trace_setvideo(ctx, 0);
#endif
} else {
vaStatus = tng__cmdbuf_lowpower(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf lowpower\n");
}
}
if (ctx->sRCParams.eRCMode != IMG_RCMODE_NONE ||
ctx->rc_update_flag) {
vaStatus = tng__update_ratecontrol(ctx, ctx->ui32StreamID);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "send picmgmt");
}
}
if ((ctx->idr_force_flag == 1) && (ctx->sRCParams.ui16BFrames == 0)){
vaStatus = tng__update_frametype(ctx, IMG_FRAME_IDR);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "send picmgmt IDR");
}
ctx->idr_force_flag =0;
}
vaStatus = tng__cmdbuf_provide_buffer(ctx, ctx->ui32StreamID);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "provide buffer");
}
if (ctx->bEnableAIR == IMG_TRUE ||
ctx->bEnableCIR == IMG_TRUE) {
tng_air_set_input_control(ctx, 0);
if (ctx->bEnableAIR == IMG_TRUE)
tng_air_set_output_control(ctx, 0);
}
if (ctx->eStandard == IMG_STANDARD_MPEG4) {
if (ctx->ui32FrameCount[0] == 0) {
vaStatus = tng__cmdbuf_doheader(ctx);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf doheader\n");
}
}
tng__MPEG4ES_send_seq_header(ctx, ctx->ui32StreamID);
}
if (ctx->bInsertHRDParams)
tng_cmdbuf_insert_command(ctx->obj_context, ctx->ui32StreamID,
MTX_CMDID_DO_HEADER, 0, &(ps_mem->bufs_sei_header), 0);
tng_cmdbuf_insert_command(ctx->obj_context, ctx->ui32StreamID,
MTX_CMDID_ENCODE_FRAME, 0, 0, 0);
#ifdef _TOPAZHP_CMDBUF_
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s addr = 0x%08x \n", __FUNCTION__, cmdbuf);
tng__trace_cmdbuf_words(cmdbuf);
tng__trace_cmdbuf(cmdbuf, ctx->ui32StreamID);
#endif
// tng_buffer_unmap(ctx, ctx->ui32StreamID);
tng_cmdbuf_mem_unmap(cmdbuf);
vaStatus = tng__end_one_frame(ctx, 0);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "setting when one frame ends\n");
}
if (tng_context_flush_cmdbuf(ctx->obj_context)) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
}
++(ctx->ui32FrameCount[ctx->ui32StreamID]);
++(ctx->ui32RawFrameCount);
return vaStatus;
}