/* * 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; }