blob: b47883184cc95d69022fd165e87c66cb44bf206a [file] [log] [blame]
/*
* 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:
* Zeng Li <zeng.li@intel.com>
* Shengquan Yuan <shengquan.yuan@intel.com>
* Binglin Chen <binglin.chen@intel.com>
*
*/
#include "psb_drv_video.h"
#include "lnc_hostcode.h"
#include "hwdefs/topaz_defs.h"
#include "psb_def.h"
#include "psb_cmdbuf.h"
#include <stdio.h>
#include "psb_output.h"
#include <wsbm/wsbm_manager.h>
#include "lnc_hostheader.h"
#include "psb_drv_debug.h"
#define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1))
#define PAGE_ALIGN(value) ALIGN_TO(value, 4096)
static VAStatus lnc__alloc_context_buffer(context_ENC_p ctx)
{
int width, height;
VAStatus vaStatus = VA_STATUS_SUCCESS;
/* width and height should be source surface's w and h or ?? */
width = ctx->obj_context->picture_width;
height = ctx->obj_context->picture_height;
ctx->pic_params_size = 256;
ctx->header_buffer_size = 4 * HEADER_SIZE + MAX_SLICES_PER_PICTURE * HEADER_SIZE;
ctx->seq_header_ofs = 0;
ctx->pic_header_ofs = HEADER_SIZE;
ctx->eoseq_header_ofs = 2 * HEADER_SIZE;
ctx->eostream_header_ofs = 3 * HEADER_SIZE;
ctx->slice_header_ofs = 4 * HEADER_SIZE;
ctx->sliceparam_buffer_size = ((sizeof(SLICE_PARAMS) + 15) & 0xfff0) * MAX_SLICES_PER_PICTURE;
/* All frame share same MTX_CURRENT_IN_PARAMS and above/bellow param
* create MTX_CURRENT_IN_PARAMS buffer seperately
* every MB has one MTX_CURRENT_IN_PARAMS structure, and the (N+1) frame can
* reuse (N) frame's structure
*/
ctx->in_params_size = (10 + width * height / (16 * 16)) * sizeof(MTX_CURRENT_IN_PARAMS);
ctx->bellow_params_size = BELOW_PARAMS_SIZE * width * height / (16 * 16) * 16;
ctx->above_params_size = (width * height / 16) * 128 + 15;
ctx->topaz_buffer_size = ctx->in_params_size + /* MTX_CURRENT_IN_PARAMS size */
ctx->bellow_params_size + /* above_params */
ctx->above_params_size; /* above_params */
vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_I);
vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_P);
vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->above_params_size + ctx->bellow_params_size, psb_bt_cpu_vpu, &ctx->topaz_above_bellow_params);
ctx->in_params_ofs = 0;
ctx->bellow_params_ofs = 0;
ctx->above_params_ofs = ctx->bellow_params_ofs + ctx->bellow_params_size;
return vaStatus;
}
unsigned int lnc__get_ipe_control(enum drm_lnc_topaz_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 lnc_DestroyContext(object_context_p obj_context)
{
context_ENC_p ctx;
ctx = (context_ENC_p)obj_context->format_data;
if (NULL != ctx->slice_param_cache)
free(ctx->slice_param_cache);
if (NULL == ctx->save_seq_header_p)
free(ctx->save_seq_header_p);
free(obj_context->format_data);
obj_context->format_data = NULL;
}
VAStatus lnc_CreateContext(
object_context_p obj_context,
object_config_p obj_config)
{
int width, height;
context_ENC_p ctx;
VAStatus vaStatus;
width = obj_context->picture_width;
height = 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;
}
obj_context->format_data = (void*) ctx;
ctx->obj_context = obj_context;
ctx->RawWidth = (unsigned short) width;
ctx->RawHeight = (unsigned short) height;
ctx->Width = (unsigned short)(~0xf & (width + 0xf));
ctx->Height = (unsigned short)(~0xf & (height + 0xf));
ctx->HeightMinus16MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 16);
ctx->HeightMinus32MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 32);
ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16 = ctx->Height - (MVEA_LRB_TOP_OFFSET + MVEA_LRB_TOP_OFFSET + 16);
ctx->HeightMinusLRBSearchHeight = ctx->Height - MVEA_LRB_SEARCH_HEIGHT;
ctx->FCode = 0;
ctx->sRCParams.VCMBitrateMargin = 0;
ctx->sRCParams.BufferSize = 0;
ctx->sRCParams.InitialQp = 0;
ctx->sRCParams.MinQP = 0;
vaStatus = lnc__alloc_context_buffer(ctx);
return vaStatus;
}
VAStatus lnc_BeginPicture(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
lnc_cmdbuf_p cmdbuf;
int ret;
ctx->src_surface = ctx->obj_context->current_render_target;
/* clear frameskip flag to 0 */
CLEAR_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface);
/* Initialise the command buffer */
ret = lnc_context_get_next_cmdbuf(ctx->obj_context);
if (ret) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
vaStatus = VA_STATUS_ERROR_UNKNOWN;
return vaStatus;
}
cmdbuf = ctx->obj_context->lnc_cmdbuf;
/* map start_pic param */
vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
if (vaStatus) {
return vaStatus;
}
vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
if (vaStatus) {
psb_buffer_unmap(&cmdbuf->pic_params);
return vaStatus;
}
vaStatus = psb_buffer_map(&cmdbuf->slice_params, &cmdbuf->slice_params_p);
if (vaStatus) {
psb_buffer_unmap(&cmdbuf->pic_params);
psb_buffer_unmap(&cmdbuf->header_mem);
return vaStatus;
}
/* only map topaz param when necessary */
cmdbuf->topaz_in_params_I_p = NULL;
cmdbuf->topaz_in_params_P_p = NULL;
cmdbuf->topaz_above_bellow_params_p = NULL;
if (ctx->obj_context->frame_count == 0) { /* first picture */
psb_driver_data_p driver_data = ctx->obj_context->driver_data;
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_SW_NEW_CODEC, 3, driver_data->drm_context);
lnc_cmdbuf_insert_command_param(cmdbuf, ctx->eCodec);
lnc_cmdbuf_insert_command_param(cmdbuf, (ctx->Width << 16) | ctx->Height);
}
/* insert START_PIC command */
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_START_PIC, 3, ctx->obj_context->frame_count);
/* write the address of structure PIC_PARAMS following command MTX_CMDID_START_PIC
* the content of PIC_PARAMS is filled when RenderPicture(...,VAEncPictureParameterBufferXXX)
*/
RELOC_CMDBUF(cmdbuf->cmd_idx, 0, &cmdbuf->pic_params);
cmdbuf->cmd_idx++;
ctx->initial_qp_in_cmdbuf = cmdbuf->cmd_idx; /* remember the place */
cmdbuf->cmd_idx++;
ctx->obj_context->slice_count = 0;
/* no RC paramter provided in vaBeginPicture
* so delay RC param setup into vaRenderPicture(SequenceHeader...)
*/
return vaStatus;
}
VAStatus lnc_RenderPictureParameter(context_ENC_p ctx)
{
PIC_PARAMS *psPicParams; /* PIC_PARAMS has been put in lnc_hostcode.h */
object_surface_p src_surface;
unsigned int srf_buf_offset;
object_surface_p rec_surface;
object_surface_p ref_surface;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
/* second frame will reuse some rate control parameters (IN_PARAMS_MP4)
* so only memset picture parames except IN_PARAMS
* BUT now IN_RC_PARAMS was reload from the cache, so it now can
* memset entirE PIC_PARAMS
*/
memset(psPicParams, 0, (int)((unsigned char *)&psPicParams->sInParams - (unsigned char *)psPicParams));
src_surface = ctx->src_surface;
if (NULL == src_surface) {
vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
rec_surface = ctx->dest_surface;
if (NULL == rec_surface) {
vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
/*The fisrt frame always is I frame and the content of reference frame wouldn't be used.
* But the heights of ref and dest frame should be the same.
* That allows Topaz to keep its motion vectors up to date, which helps maintain performance */
if (ctx->obj_context->frame_count == 0)
ctx->ref_surface = ctx->dest_surface;
ref_surface = ctx->ref_surface;
if (NULL == ref_surface) {
vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
/* clear frameskip flag */
CLEAR_SURFACE_INFO_skipped_flag(rec_surface->psb_surface);
CLEAR_SURFACE_INFO_skipped_flag(ref_surface->psb_surface);
/* Write video data byte offset into Coded buffer
* If it is here, it will be a SYNC point, which have performance impact
* Move to psb__CreateBuffer
vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, &pBuffer);
if(vaStatus) {
DEBUG_FAILURE;
return vaStatus;
}
*(IMG_UINT32 *)(pBuffer+8) = 16;
psb_buffer_unmap(ctx->coded_buf->psb_buffer);
*/
psPicParams->SrcYStride = src_surface->psb_surface->stride;
switch (ctx->eFormat) {
case IMG_CODEC_IYUV: /* IYUV */
case IMG_CODEC_PL8:
psPicParams->SrcUVStride = src_surface->psb_surface->stride / 2;
psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2;
break;
case IMG_CODEC_IMC2: /* IMC2 */
case IMG_CODEC_PL12:
psPicParams->SrcUVStride = src_surface->psb_surface->stride;
psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16;
break;
default:
break;
}
psPicParams->SrcYRowStride = src_surface->psb_surface->stride * 16;
/* psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2; */
/* Dest(rec) stride
* The are now literally Dst stride (not equivalent to 'offset to next row')
*/
#ifdef VA_EMULATOR
/* only for simulator, va-emulator needs the actually stride for
* reconstructed frame transfer (va-emulator->driver)
*/
psPicParams->DstYStride = rec_surface->psb_surface->stride;
psPicParams->DstUVStride = rec_surface->psb_surface->stride;
psPicParams->DstYRowStride = rec_surface->psb_surface->stride * 16;
psPicParams->DstUVRowStride = rec_surface->psb_surface->stride * 16 / 2;
#else
psPicParams->DstYStride = rec_surface->height * 16;
psPicParams->DstUVStride = rec_surface->height * 16 / 2;
psPicParams->DstYRowStride = psPicParams->DstYStride;
psPicParams->DstUVRowStride = psPicParams->DstUVStride;
#endif
psPicParams->InParamsRowStride = (ctx->obj_context->picture_width / 16) * 256;
psPicParams->BelowParamRowStride = (ctx->obj_context->picture_width / 16) * 32;
psPicParams->Width = ctx->Width;
psPicParams->Height = ctx->Height;
/* not sure why we are setting this up here... */
psPicParams->Flags = 0;
switch (ctx->eCodec) {
case IMG_CODEC_H264_NO_RC:
case IMG_CODEC_H264_VBR:
case IMG_CODEC_H264_CBR:
case IMG_CODEC_H264_VCM:
psPicParams->Flags |= ISH264_FLAGS;
break;
case IMG_CODEC_H263_VBR:
case IMG_CODEC_H263_CBR:
case IMG_CODEC_H263_NO_RC:
psPicParams->Flags |= ISH263_FLAGS;
break;
case IMG_CODEC_MPEG4_NO_RC:
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_MPEG4_CBR:
psPicParams->Flags |= ISMPEG4_FLAGS;
break;
default:
return VA_STATUS_ERROR_UNKNOWN;
}
switch (ctx->eCodec) {
case IMG_CODEC_H264_VBR:
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_H263_VBR:
psPicParams->Flags |= ISVBR_FLAGS;
break;
case IMG_CODEC_H264_VCM:
psPicParams->Flags |= ISVCM_FLAGS;
/* drop through to CBR case */
case IMG_CODEC_H263_CBR:
case IMG_CODEC_H264_CBR:
case IMG_CODEC_MPEG4_CBR:
psPicParams->Flags |= ISCBR_FLAGS;
break;
case IMG_CODEC_MPEG4_NO_RC:
case IMG_CODEC_H263_NO_RC:
case IMG_CODEC_H264_NO_RC:
break;
default:
return VA_STATUS_ERROR_UNKNOWN;
}
if (ctx->sRCParams.RCEnable) {
/* for the first frame, will setup RC params in EndPicture */
if (ctx->obj_context->frame_count > 0) { /* reuse in_params parameter */
/* reload IN_RC_PARAMS from cache */
memcpy(&psPicParams->sInParams, &ctx->in_params_cache, sizeof(IN_RC_PARAMS));
/* delay these into END_PICTURE timeframe */
/*
psPicParams->sInParams.BitsTransmitted = ctx->sRCParams.BitsTransmitted;
*/
}
} else
psPicParams->sInParams.SeInitQP = ctx->sRCParams.InitialQp;
/* some relocations have to been done here */
srf_buf_offset = src_surface->psb_surface->buf.buffer_ofs;
if (src_surface->psb_surface->buf.type == psb_bt_camera)
drv_debug_msg(VIDEO_DEBUG_GENERAL, "src surface GPU offset 0x%08x, luma offset 0x%08x\n",
wsbmBOOffsetHint(src_surface->psb_surface->buf.drm_buf), srf_buf_offset);
RELOC_PIC_PARAMS(&psPicParams->SrcYBase, srf_buf_offset, &src_surface->psb_surface->buf);
switch (ctx->eFormat) {
case IMG_CODEC_IYUV:
case IMG_CODEC_PL8:
case IMG_CODEC_PL12:
RELOC_PIC_PARAMS(&psPicParams->SrcUBase,
srf_buf_offset + src_surface->psb_surface->chroma_offset,
&src_surface->psb_surface->buf);
RELOC_PIC_PARAMS(&psPicParams->SrcVBase,
srf_buf_offset + src_surface->psb_surface->chroma_offset,
&src_surface->psb_surface->buf);
break;
case IMG_CODEC_IMC2:
case IMG_CODEC_NV12:
break;
}
/*
* Do not forget this!
* MTXWriteMem(MTXData.ui32CCBCtrlAddr + MTX_CCBCTRL_QP, sRCParams.ui32InitialQp);
*/
/* following START_PIC, insert initial QP */
*ctx->initial_qp_in_cmdbuf = ctx->sRCParams.InitialQp;
RELOC_PIC_PARAMS(&psPicParams->DstYBase, 0, &rec_surface->psb_surface->buf);
RELOC_PIC_PARAMS(&psPicParams->DstUVBase,
rec_surface->psb_surface->stride * rec_surface->height,
&rec_surface->psb_surface->buf);
RELOC_PIC_PARAMS(&psPicParams->CodedBase, 0, ctx->coded_buf->psb_buffer);
/* MTX_CURRENT_IN_PARAMS buffer is seperate buffer now */
/*The type of frame will decide psPicParams->InParamsBase should
* use cmdbuf->topaz_in_params_P or cmdbuf->topaz_in_params_I*/
/*RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_P);*/
RELOC_PIC_PARAMS(&psPicParams->BelowParamsBase, ctx->bellow_params_ofs, cmdbuf->topaz_above_bellow_params);
RELOC_PIC_PARAMS(&psPicParams->AboveParamsBase, ctx->above_params_ofs, cmdbuf->topaz_above_bellow_params);
return VA_STATUS_SUCCESS;
}
static VAStatus lnc__PatchBitsConsumedInRCParam(context_ENC_p ctx)
{
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
/* PIC_PARAMS *psPicParams = cmdbuf->pic_params_p; */
VAStatus vaStatus;
(void)cmdbuf;
/* it will wait until last encode session is done */
/* now it just wait the last session is done and the frame skip
* is */
drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch bits consumed for rc\n");
if (ctx->pprevious_coded_buf) {
vaStatus = psb_buffer_sync(ctx->pprevious_coded_buf->psb_buffer);
if (vaStatus)
return vaStatus;
}
return VA_STATUS_SUCCESS;
}
static VAStatus lnc_RedoRenderPictureSkippedFrame(context_ENC_p ctx)
{
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i = 0;
/* reset cmdbuf to skip existing picture/slice DO_HEAD commands */
cmdbuf->cmd_idx = cmdbuf->cmd_idx_saved_frameskip;
switch (ctx->eCodec) {
case IMG_CODEC_H263_CBR: /* H263 don't need picture header/slice header, only reset command buf */
case IMG_CODEC_H263_VBR:
break;
case IMG_CODEC_H264_VBR:
case IMG_CODEC_H264_CBR: /* slice header needs redo */
case IMG_CODEC_H264_VCM: {
/* only need one slice header here */
VAEncSliceParameterBuffer *pBuffer = &ctx->slice_param_cache[i];
unsigned int MBSkipRun, FirstMBAddress;
int deblock_on;
if ((pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 0)
|| (pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 2))
deblock_on = IMG_TRUE;
else
deblock_on = IMG_FALSE;
if (1 /* ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip */) /* we know it is true */
MBSkipRun = (ctx->Width * ctx->Height) / 256;
else
MBSkipRun = 0;
FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
/* Insert Do Header command, relocation is needed */
lnc__H264_prepare_slice_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->slice_header_ofs + i * HEADER_SIZE),
0, /*pBuffer->slice_flags.bits.is_intra*/
pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
ctx->obj_context->frame_count,
FirstMBAddress,
MBSkipRun,
(ctx->obj_context->frame_count == 0),
pBuffer->slice_flags.bits.uses_long_term_ref,
pBuffer->slice_flags.bits.is_long_term_ref,
ctx->idr_pic_id);
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, (i << 2) | 2);
RELOC_CMDBUF(cmdbuf->cmd_idx++,
ctx->slice_header_ofs + i * HEADER_SIZE,
&cmdbuf->header_mem);
}
break;
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_MPEG4_CBR: /* only picture header need redo */
lnc__MPEG4_prepare_vop_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->pic_header_ofs),
IMG_FALSE /* bIsVOPCoded is false now */,
ctx->MPEG4_vop_time_increment_frameskip, /* In testbench, this should be FrameNum */
4,/* default value is 4,search range */
ctx->MPEG4_picture_type_frameskip,
ctx->MPEG4_vop_time_increment_resolution/* defaule value */);
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 1);
RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_header_ofs, &cmdbuf->header_mem);
vaStatus = lnc_RenderPictureParameter(ctx);
break;
default:
drv_debug_msg(VIDEO_DEBUG_ERROR, "Non-RC mode should be here for FrameSkip handling\n");
ASSERT(0);
}
return vaStatus;
}
static VAStatus lnc_SetupRCParam(context_ENC_p ctx)
{
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
int origin_qp;/* in DDK setup_rc will change qp strangly,
* just for keep same with DDK
*/
origin_qp = ctx->sRCParams.InitialQp;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "will setup rc data\n");
psPicParams->Flags |= ISRC_FLAGS;
lnc__setup_rcdata(ctx, psPicParams, &ctx->sRCParams);
/* restore it, just keep same with DDK */
ctx->sRCParams.InitialQp = origin_qp;
/* save IN_RC_PARAMS into the cache */
memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
return VA_STATUS_SUCCESS;
}
static VAStatus lnc_UpdateRCParam(context_ENC_p ctx)
{
int origin_qp;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
origin_qp = ctx->sRCParams.InitialQp;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "will update rc data\n");
lnc__update_rcdata(ctx, psPicParams, &ctx->sRCParams);
/* set minQP if hosts set minQP */
if (ctx->sRCParams.MinQP)
psPicParams->sInParams.MinQPVal = ctx->sRCParams.MinQP;
/* if seinitqp is set, restore the value hosts want */
if (origin_qp) {
psPicParams->sInParams.SeInitQP = origin_qp;
psPicParams->sInParams.MyInitQP = origin_qp;
ctx->sRCParams.InitialQp = origin_qp;
}
/* save IN_RC_PARAMS into the cache */
memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
return VA_STATUS_SUCCESS;
}
static VAStatus lnc_PatchRCMode(context_ENC_p ctx)
{
int frame_skip = 0;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch rc data\n");
/* it will ensure previous encode finished */
lnc__PatchBitsConsumedInRCParam(ctx);
/* get frameskip flag */
lnc_surface_get_frameskip(ctx->obj_context->driver_data, ctx->src_surface->psb_surface, &frame_skip);
/* current frame is skipped
* redo RenderPicture with FrameSkip set
*/
if (frame_skip == 1)
lnc_RedoRenderPictureSkippedFrame(ctx);
return VA_STATUS_SUCCESS;
}
VAStatus lnc_EndPicture(context_ENC_p ctx)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
if (ctx->sRCParams.RCEnable == IMG_TRUE) {
if (ctx->obj_context->frame_count == 0)
lnc_SetupRCParam(ctx);
else if (ctx->update_rc_control)
lnc_UpdateRCParam(ctx);
else
lnc_PatchRCMode(ctx);
}
ctx->update_rc_control = 0;
/* save current settings */
ctx->previous_src_surface = ctx->src_surface;
ctx->previous_ref_surface = ctx->ref_surface;
ctx->previous_dest_surface = ctx->dest_surface; /* reconstructed surface */
ctx->pprevious_coded_buf = ctx->previous_coded_buf;
ctx->previous_coded_buf = ctx->coded_buf;
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_END_PIC, 3, 0);
lnc_cmdbuf_insert_command_param(cmdbuf, 0);/* two meaningless parameters */
lnc_cmdbuf_insert_command_param(cmdbuf, 0);
psb_buffer_unmap(&cmdbuf->pic_params);
psb_buffer_unmap(&cmdbuf->header_mem);
psb_buffer_unmap(&cmdbuf->slice_params);
/* unmap MTX_CURRENT_IN_PARAMS buffer only when it is mapped */
if (cmdbuf->topaz_in_params_I_p != NULL) {
psb_buffer_unmap(cmdbuf->topaz_in_params_I);
cmdbuf->topaz_in_params_I_p = NULL;
}
if (cmdbuf->topaz_in_params_P_p != NULL) {
psb_buffer_unmap(cmdbuf->topaz_in_params_P);
cmdbuf->topaz_in_params_P_p = NULL;
}
if (cmdbuf->topaz_above_bellow_params_p != NULL) {
psb_buffer_unmap(cmdbuf->topaz_above_bellow_params);
cmdbuf->topaz_above_bellow_params_p = NULL;
}
if (lnc_context_flush_cmdbuf(ctx->obj_context)) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
}
return vaStatus;
}
static void lnc__setup_busize(context_ENC_p ctx)
{
unsigned int old_busize = ctx->sRCParams.BUSize;
/* it is called at EndPicture, we should now the Slice number */
ctx->Slices = ctx->obj_context->slice_count;
/* if no BU size is given then pick one ourselves */
if (ctx->sRCParams.BUSize != 0) { /* application provided BUSize */
IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
IMG_UINT32 BUs;
IMG_INT32 SliceHeight;
MBs = ctx->Height * ctx->Width / (16 * 16);
SliceHeight = ctx->Height / ctx->Slices;
/* SliceHeight += 15; */
SliceHeight &= ~15;
MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16);
MBsLastSlice = MBs - (MBsperSlice * (ctx->Slices - 1));
/* they have given us a basic unit so validate it */
if (ctx->sRCParams.BUSize < 6) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small, must be greater than 6\n");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
if (ctx->sRCParams.BUSize > MBsperSlice) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than the number of macroblocks in a slice\n");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
if (ctx->sRCParams.BUSize > MBsLastSlice) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than number of macroblocks in the last slice\n");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
BUs = MBsperSlice / ctx->sRCParams.BUSize;
if ((BUs * ctx->sRCParams.BUSize) != MBsperSlice) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size not an integer divisor of MB's in a slice");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
if (BUs > 200) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
BUs = MBsLastSlice / ctx->sRCParams.BUSize;
if (BUs > 200) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
ctx->sRCParams.BUSize = 0; /* need repatch */;
}
}
if (ctx->sRCParams.BUSize == 0) {
IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
IMG_UINT32 BUs, BUsperSlice, BUsLastSlice;
IMG_INT32 SliceHeight;
MBs = ctx->Height * ctx->Width / (16 * 16);
SliceHeight = ctx->Height / ctx->Slices;
/* SliceHeight += 15; */
SliceHeight &= ~15;
MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16);
MBsLastSlice = MBs - (MBsperSlice * (ctx->Slices - 1));
/* we have to verify that MBs is divisiable by BU AND that BU is > pipeline length */
if (ctx->sRCParams.BUSize < 6) {
ctx->sRCParams.BUSize = 6;
}
BUs = MBs / ctx->sRCParams.BUSize;
while (BUs*ctx->sRCParams.BUSize != MBs) {
ctx->sRCParams.BUSize++;
BUs = MBs / ctx->sRCParams.BUSize;
}
/* Check number of BUs in the pipe is less than maximum number allowed 200 */
BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
while ((BUsperSlice *(ctx->Slices - 1) + BUsLastSlice) > 200) {
ctx->sRCParams.BUSize++;
BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
}
/* Check whether there are integer number of BUs in the slices */
BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
while ((BUsperSlice*ctx->sRCParams.BUSize != MBsperSlice) ||
(BUsLastSlice*ctx->sRCParams.BUSize != MBsLastSlice)) {
ctx->sRCParams.BUSize++;
BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
}
if (ctx->sRCParams.BUSize != old_busize)
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Patched Basic unit to %d (original=%d)\n", ctx->sRCParams.BUSize, old_busize);
}
}
/***********************************************************************************
* Function Name : SetupRCData
* Inputs :
* Outputs :
* Returns :
* Description : Sets up RC Data
************************************************************************************/
void lnc__setup_rcdata(
context_ENC_p psContext,
PIC_PARAMS *psPicParams,
IMG_RC_PARAMS *psRCParams)
{
IMG_UINT32 max_bitrate = psContext->Width * psContext->Height * 1.5 * 8 * 60;
IMG_UINT8 InitialSeInitQP = 0;
/* frameskip is always cleared, specially handled at vaEndPicture */
psRCParams->FrameSkip = 0;
if (!psRCParams->BitsPerSecond)
psRCParams->BitsPerSecond = 64000;
if (psRCParams->BitsPerSecond > max_bitrate)
psRCParams->BitsPerSecond = max_bitrate;
if (!psRCParams->FrameRate)
psRCParams->FrameRate = 30;
if (psRCParams->BufferSize == 0) {
if (psRCParams->BitsPerSecond < 256000)
psRCParams->BufferSize = (9 * psRCParams->BitsPerSecond) >> 1;
else
psRCParams->BufferSize = (5 * psRCParams->BitsPerSecond) >> 1;
}
psRCParams->InitialLevel = (3 * psRCParams->BufferSize) >> 4;
psRCParams->InitialDelay = (13 * psRCParams->BufferSize) >> 4;
lnc__setup_busize(psContext); /* calculate BasicUnitSize */
psPicParams->sInParams.SeInitQP = psRCParams->InitialQp;
psPicParams->sInParams.MBPerRow = (psContext->Width >> 4);
psPicParams->sInParams.MBPerBU = psRCParams->BUSize;
psPicParams->sInParams.MBPerFrm = (psContext->Width >> 4) * (psContext->Height >> 4);
psPicParams->sInParams.BUPerFrm = (psPicParams->sInParams.MBPerFrm) / psRCParams->BUSize;
InitialSeInitQP = psPicParams->sInParams.SeInitQP;
lnc__update_rcdata(psContext, psPicParams, psRCParams);
/* set minQP if hosts set minQP */
if (psRCParams->MinQP)
psPicParams->sInParams.MinQPVal = psRCParams->MinQP;
/* if seinitqp is set, restore the value hosts want */
if (InitialSeInitQP) {
psPicParams->sInParams.SeInitQP = InitialSeInitQP;
psPicParams->sInParams.MyInitQP = InitialSeInitQP;
psRCParams->InitialQp = InitialSeInitQP;
}
}
void lnc__update_rcdata(context_ENC_p psContext,
PIC_PARAMS *psPicParams,
IMG_RC_PARAMS *psRCParams)
{
double L1, L2, L3, L4, L5, flBpp;
INT16 i16TempQP;
IMG_INT32 i32BufferSizeInFrames;
flBpp = 1.0 * psRCParams->BitsPerSecond / (psRCParams->FrameRate * psContext->Width * psContext->Height);
/* recalculate for small frames */
if (psContext->Width <= 176)
flBpp = flBpp / 2.0;
psPicParams->sInParams.IntraPeriod = psRCParams->IntraFreq;
psPicParams->sInParams.BitRate = psRCParams->BitsPerSecond;
psPicParams->sInParams.IntraPeriod = psRCParams->IntraFreq;
psPicParams->sInParams.BitsPerFrm = psRCParams->BitsPerSecond / psRCParams->FrameRate;
psPicParams->sInParams.BitsPerGOP = psPicParams->sInParams.BitsPerFrm * psRCParams->IntraFreq;
psPicParams->sInParams.BitsPerBU = psPicParams->sInParams.BitsPerFrm / (4 * psPicParams->sInParams.BUPerFrm);
psPicParams->sInParams.BitsPerMB = psPicParams->sInParams.BitsPerBU / psRCParams->BUSize;
i32BufferSizeInFrames = psRCParams->BufferSize / psPicParams->sInParams.BitsPerFrm;
// select thresholds and initial Qps etc that are codec dependent
switch (psContext->eCodec) {
case IMG_CODEC_H264_CBR:
case IMG_CODEC_H264_VCM:
case IMG_CODEC_H264_VBR:
L1 = 0.1;
L2 = 0.15;
L3 = 0.2;
psPicParams->sInParams.MaxQPVal = 51;
// Set THSkip Values
if (flBpp <= 0.07)
psPicParams->THSkip = TH_SKIP_24;
else if (flBpp <= 0.14)
psPicParams->THSkip = TH_SKIP_12;
else
psPicParams->THSkip = TH_SKIP_0;
if (flBpp <= 0.3)
psPicParams->Flags |= ISRC_I16BIAS;
// Setup MAX and MIN Quant Values
if (flBpp >= 0.50)
i16TempQP = 4;
else if (flBpp > 0.133)
i16TempQP = (unsigned int)(24 - (40 * flBpp));
else
i16TempQP = (unsigned int)(32 - (100 * flBpp));
psPicParams->sInParams.MinQPVal = (max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
// Calculate Initial QP if it has not been specified
L1 = 0.050568;
L2 = 0.202272;
L3 = 0.40454321;
L4 = 0.80908642;
L5 = 1.011358025;
if (flBpp < L1)
i16TempQP = (IMG_INT16)(47 - 78.10 * flBpp);
else if (flBpp >= L1 && flBpp < L2)
i16TempQP = (IMG_INT16)(46 - 72.51 * flBpp);
else if (flBpp >= L2 && flBpp < L3)
i16TempQP = (IMG_INT16)(36 - 24.72 * flBpp);
else if (flBpp >= L3 && flBpp < L4)
i16TempQP = (IMG_INT16)(34 - 19.78 * flBpp);
else if (flBpp >= L4 && flBpp < L5)
i16TempQP = (IMG_INT16)(27 - 9.89 * flBpp);
else if (flBpp >= L5)
i16TempQP = (IMG_INT16)(20 - 4.95 * flBpp);
psPicParams->sInParams.SeInitQP = (IMG_UINT8)(max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
break;
case IMG_CODEC_MPEG4_CBR:
case IMG_CODEC_MPEG4_VBR:
psPicParams->sInParams.MaxQPVal = 31;
if (psContext->Width == 176) {
L1 = 0.1;
L2 = 0.3;
L3 = 0.6;
} else if (psContext->Width == 352) {
L1 = 0.2;
L2 = 0.6;
L3 = 1.2;
} else {
L1 = 0.25;
L2 = 1.4;
L3 = 2.4;
}
// Calculate Initial QP if it has not been specified
if (flBpp <= L1)
psPicParams->sInParams.SeInitQP = 31;
else {
if (flBpp <= L2)
psPicParams->sInParams.SeInitQP = 25;
else
psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
}
if (flBpp >= 0.25) {
psPicParams->sInParams.MinQPVal = 1;
} else {
psPicParams->sInParams.MinQPVal = 2;
}
break;
case IMG_CODEC_H263_CBR:
case IMG_CODEC_H263_VBR:
psPicParams->sInParams.MaxQPVal = 31;
if (psContext->Width == 176) {
L1 = 0.1;
L2 = 0.3;
L3 = 0.6;
} else if (psContext->Width == 352) {
L1 = 0.2;
L2 = 0.6;
L3 = 1.2;
} else {
L1 = 0.25;
L2 = 1.4;
L3 = 2.4;
}
// Calculate Initial QP if it has not been specified
if (flBpp <= L1)
psPicParams->sInParams.SeInitQP = 31;
else {
if (flBpp <= L2)
psPicParams->sInParams.SeInitQP = 25;
else
psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
}
psPicParams->sInParams.MinQPVal = 3;
break;
default:
/* the NO RC cases will fall here */
break;
}
// Set up Input Parameters that are mode dependent
switch (psContext->eCodec) {
case IMG_CODEC_H264_NO_RC:
case IMG_CODEC_H263_NO_RC:
case IMG_CODEC_MPEG4_NO_RC:
return;
case IMG_CODEC_H264_VCM:
psPicParams->Flags |= ISVCM_FLAGS | ISCBR_FLAGS;
/* drop through to CBR case */
/* for SD and above we can target 95% (122/128) of maximum bitrate */
if (psRCParams->VCMBitrateMargin) {
psPicParams->sInParams.VCMBitrateMargin = psRCParams->VCMBitrateMargin;
} else {
if (psContext->Height >= 480)
psPicParams->sInParams.VCMBitrateMargin = 122;
else
psPicParams->sInParams.VCMBitrateMargin = 115; /* for less and SD we target 90% (115/128) of maximum bitrate */
if (i32BufferSizeInFrames < 15)
psPicParams->sInParams.VCMBitrateMargin -= 5;/* when we have a very small window size we reduce the target further to avoid too much skipping */
}
psPicParams->sInParams.ForceSkipMargin = 500;/* start skipping MBs when within 500 bits of slice or frame limit */
// Set a scale factor to avoid overflows in maths
if (psRCParams->BitsPerSecond < 1000000) { // 1 Mbits/s
psPicParams->sInParams.ScaleFactor = 0;
} else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
psPicParams->sInParams.ScaleFactor = 1;
} else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
psPicParams->sInParams.ScaleFactor = 2;
} else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
psPicParams->sInParams.ScaleFactor = 3;
} else {
psPicParams->sInParams.ScaleFactor = 4;
}
psPicParams->sInParams.BufferSize = i32BufferSizeInFrames;
break;
case IMG_CODEC_H264_CBR:
psPicParams->Flags |= ISCBR_FLAGS;
// ------------------- H264 CBR RC ------------------- //
// Initialize the parameters of fluid flow traffic model.
psPicParams->sInParams.BufferSize = psRCParams->BufferSize;
// HRD consideration - These values are used by H.264 reference code.
if (psRCParams->BitsPerSecond < 1000000) { // 1 Mbits/s
psPicParams->sInParams.ScaleFactor = 0;
} else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
psPicParams->sInParams.ScaleFactor = 1;
} else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
psPicParams->sInParams.ScaleFactor = 2;
} else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
psPicParams->sInParams.ScaleFactor = 3;
} else {
psPicParams->sInParams.ScaleFactor = 4;
}
break;
case IMG_CODEC_MPEG4_CBR:
case IMG_CODEC_H263_CBR:
psPicParams->Flags |= ISCBR_FLAGS;
flBpp = 256 * (psRCParams->BitsPerSecond / psContext->Width);
flBpp /= (psContext->Height * psRCParams->FrameRate);
if ((psPicParams->sInParams.MBPerFrm > 1024 && flBpp < 16) || (psPicParams->sInParams.MBPerFrm <= 1024 && flBpp < 24))
psPicParams->sInParams.HalfFrameRate = 1;
else
psPicParams->sInParams.HalfFrameRate = 0;
if (psPicParams->sInParams.HalfFrameRate >= 1) {
psPicParams->sInParams.SeInitQP = 31;
psPicParams->sInParams.AvQPVal = 31;
psPicParams->sInParams.MyInitQP = 31;
}
if (psRCParams->BitsPerSecond <= 384000)
psPicParams->sInParams.BufferSize = ((psRCParams->BitsPerSecond * 5) >> 1);
else
psPicParams->sInParams.BufferSize = psRCParams->BitsPerSecond * 4;
break;
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_H263_VBR:
case IMG_CODEC_H264_VBR:
psPicParams->Flags |= ISVBR_FLAGS;
psPicParams->sInParams.MBPerBU = psPicParams->sInParams.MBPerFrm;
psPicParams->sInParams.BUPerFrm = 1;
// Initialize the parameters of fluid flow traffic model.
psPicParams->sInParams.BufferSize = ((5 * psRCParams->BitsPerSecond) >> 1);
// 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->BitsPerSecond < 640000) {
psPicParams->sInParams.ScaleFactor = 2; // related to complexity
} else if (psRCParams->BitsPerSecond < 2000000) {
psPicParams->sInParams.ScaleFactor = 4;
} else {
psPicParams->sInParams.ScaleFactor = 6;
}
break;
default:
break;
}
psPicParams->sInParams.MyInitQP = psPicParams->sInParams.SeInitQP;
psPicParams->sInParams.InitialDelay = psRCParams->InitialDelay;
psPicParams->sInParams.InitialLevel = psRCParams->InitialLevel;
psRCParams->InitialQp = psPicParams->sInParams.SeInitQP;
}
static void lnc__setup_qpvalue_h264(
MTX_CURRENT_IN_PARAMS * psCurrent,
IMG_BYTE bySliceQP)
{
/* H.264 QP scaling tables */
IMG_BYTE HOST_PVR_QP_SCALE_CR[52] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37,
37, 38, 38, 38, 39, 39, 39, 39
};
psCurrent->bySliceQP = bySliceQP;
psCurrent->bySliceQPC = HOST_PVR_QP_SCALE_CR[psCurrent->bySliceQP];
}
static void lnc__setup_qpvalues_mpeg4(
MTX_CURRENT_IN_PARAMS * psCurrent,
IMG_BYTE bySliceQP)
{
psCurrent->bySliceQP = bySliceQP;
}
static void lnc__setup_slice_row_params(
context_ENC_p ctx,
IMG_BOOL IsIntra,
IMG_UINT16 CurrentRowY,
IMG_INT16 SliceStartRowY,
IMG_INT16 SliceHeight,
IMG_BOOL VectorsValid,
int bySliceQP)
{
/* Note: CurrentRowY and SliceStartRowY are now in pixels (not MacroBlocks)
* - saves needless multiplications and divisions
*/
IMG_INT16 Pos, YPos, srcY;
MTX_CURRENT_IN_PARAMS *psCurrent;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
IMG_UINT16 tmp;
if (IsIntra && cmdbuf->topaz_in_params_I_p == NULL) {
VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_I, &cmdbuf->topaz_in_params_I_p);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
return;
}
}
if ((!IsIntra) && cmdbuf->topaz_in_params_P_p == NULL) {
VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_P, &cmdbuf->topaz_in_params_P_p);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
return;
}
}
if (IsIntra)
psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_I_p + ctx->in_params_ofs);
else
psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_P_p + ctx->in_params_ofs);
psCurrent += (CurrentRowY * (ctx->Width) / 256);
if ((YPos = srcY = CurrentRowY - MVEA_LRB_TOP_OFFSET) < 0)
srcY = 0;
else if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16)
srcY = ctx->HeightMinusLRBSearchHeight;
tmp = (CurrentRowY != SliceStartRowY);
for (Pos = 0; Pos < (int)ctx->Width; Pos += 16, psCurrent++) {
memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS));
psCurrent->MVValid = 0;
psCurrent->ParamsValid = 0;
/* Setup the parameters and motion vectors */
if (tmp) {
psCurrent->MVValid = 66;
psCurrent->ParamsValid |= PARAMS_ABOVE_VALID;
if (Pos + 16 < (int)ctx->Width) {
psCurrent->ParamsValid |= PARAMS_ABOVER_VALID;
psCurrent->MVValid |= 4; /* (1<<2) */
}
if (Pos > 0 && (Pos < (int)ctx->Width)) {
psCurrent->ParamsValid |= PARAMS_ABOVEL_VALID;
psCurrent->MVValid |= 1; /* (1<<0) */
}
}
if ((Pos == 0) && (CurrentRowY == SliceStartRowY)) {
psCurrent->ParamsValid |= MB_START_OF_SLICE;/* OPTI? */
}
/* Have to fill in the right hand row of 4x4 vectors into the the left block */
if (Pos) {
psCurrent->MVValid |= 72; /* (1<<3)+(1<<6) */
psCurrent->ParamsValid |= 8; /* (1<<3) */
}
if (Pos == (int)(ctx->Width - 16)) {
/* indicate the last MB in a row */
psCurrent->ParamsValid |= MB_END_OF_ROW;
/* are we the last mb in the slice? */
if (YPos == (SliceStartRowY + SliceHeight - (MVEA_LRB_TOP_OFFSET + 16))) {
psCurrent->ParamsValid |= MB_END_OF_SLICE;
if (YPos == ctx->HeightMinus16MinusLRBTopOffset) {
psCurrent->ParamsValid |= MB_END_OF_PICTURE;
}
}
}
/* And now the below block
* should do some kind of check to see if we are the first inter block,
* as otherwise the vectors will be invalid!
*/
if (VectorsValid) {
if (YPos < ctx->HeightMinus16MinusLRBTopOffset) {
psCurrent->MVValid |= 16; /* (1<<4) */
if (YPos < ctx->HeightMinus32MinusLRBTopOffset) {
psCurrent->MVValid |= 32; /* (1<<5) */
}
}
}
/* Set up IPEMin and Max for coordinate X in the search reference region */
/* And set up flags in SPEMax when needed */
if (Pos <= 48) {
psCurrent->IPEMin[0] = 48 - Pos;
psCurrent->RealEdge |= SPE_EDGE_LEFT;
} else {
psCurrent->IPEMin[0] = 3;
}
if ((Pos + 48 + 16) > (int)ctx->Width) {
psCurrent->IPEMax[0] = (47 + ctx->Width) - Pos; /* (112 - 1) - ((Pos + 48+16) - ctx->Width); */
psCurrent->RealEdge |= SPE_EDGE_RIGHT;
} else {
psCurrent->IPEMax[0] = 108; /* (112 - 1) - 3; */
}
/* Set up IPEMin and Max for Y coordinate in the search reference region */
/* And set up flags in SPEMax when needed */
if (YPos <= 0) {
psCurrent->IPEMin[1] = 0;
psCurrent->RealEdge |= SPE_EDGE_TOP;
} else {
psCurrent->IPEMin[1] = 3;
}
/* Max Y */
if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) {
psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 1;
psCurrent->RealEdge |= SPE_EDGE_BOTTOM;
} else {
psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 4;
}
psCurrent->CurBlockAddr = ((IMG_UINT8)(((YPos + MVEA_LRB_TOP_OFFSET) - srcY) / 16) << 4) | 0x3;
/* Setup the control register values These will get setup and transferred to a different location within
* the macroblock parameter structure. They are then read out of the esb by the mtx and used to control
* the hardware units
*/
psCurrent->IPEControl = ctx->IPEControl;
switch (ctx->eCodec) {
case IMG_CODEC_H263_NO_RC:
case IMG_CODEC_H263_VBR:
case IMG_CODEC_H263_CBR:
lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
psCurrent->JMCompControl = F_ENCODE(2, MVEA_CR_JMCOMP_MODE);
psCurrent->VLCControl = F_ENCODE(3, TOPAZ_VLC_CR_CODEC) |
F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
break;
case IMG_CODEC_MPEG4_NO_RC:
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_MPEG4_CBR:
lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
psCurrent->JMCompControl = F_ENCODE(1, MVEA_CR_JMCOMP_MODE) |
F_ENCODE(1, MVEA_CR_JMCOMP_AC_ENABLE);
psCurrent->VLCControl = F_ENCODE(2, TOPAZ_VLC_CR_CODEC) |
F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
break;
default:
case IMG_CODEC_H264_NO_RC:
case IMG_CODEC_H264_VBR:
case IMG_CODEC_H264_CBR:
case IMG_CODEC_H264_VCM:
lnc__setup_qpvalue_h264(psCurrent, bySliceQP);
psCurrent->JMCompControl = F_ENCODE(0, MVEA_CR_JMCOMP_MODE);
psCurrent->VLCControl = F_ENCODE(1, TOPAZ_VLC_CR_CODEC) |
F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
break;
}
}
psCurrent->RealEdge = 0;
}
void lnc_setup_slice_params(
context_ENC_p ctx,
IMG_UINT16 YSliceStartPos,
IMG_UINT16 SliceHeight,
IMG_BOOL IsIntra,
IMG_BOOL VectorsValid,
int bySliceQP)
{
IMG_UINT16 Rows, CurrentRowY;
Rows = SliceHeight / 16;
CurrentRowY = YSliceStartPos;
while (Rows) {
lnc__setup_slice_row_params(
ctx,
IsIntra,
CurrentRowY,
YSliceStartPos,
SliceHeight,
VectorsValid, bySliceQP);
CurrentRowY += 16;
Rows--;
}
}
IMG_UINT32 lnc__send_encode_slice_params(
context_ENC_p ctx,
IMG_BOOL IsIntra,
IMG_UINT16 CurrentRow,
IMG_BOOL DeblockSlice,
IMG_UINT32 FrameNum,
IMG_UINT16 SliceHeight,
IMG_UINT16 CurrentSlice,
IMG_UINT32 MaxSliceSize)
{
SLICE_PARAMS *psSliceParams;
IMG_UINT16 RowOffset;
psb_buffer_p psCoded;
object_surface_p ref_surface;
psb_buffer_p psRef;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
ref_surface = ctx->ref_surface;
psRef = &ctx->ref_surface->psb_surface->buf;
psCoded = ctx->coded_buf->psb_buffer;
psSliceParams = (SLICE_PARAMS *)(cmdbuf->slice_params_p +
CurrentSlice * ((sizeof(SLICE_PARAMS) + 15) & 0xfff0));
psSliceParams->SliceHeight = SliceHeight;
psSliceParams->SliceStartRowNum = CurrentRow / 16;
/* We want multiple ones of these so we can submit multiple slices without having to wait for the next */
psSliceParams->CodedDataPos = 0;
psSliceParams->TotalCoded = 0;
psSliceParams->Flags = 0;
#ifdef VA_EMULATOR
psSliceParams->RefYStride = ref_surface->psb_surface->stride;
psSliceParams->RefUVStride = ref_surface->psb_surface->stride;
psSliceParams->RefYRowStride = ref_surface->psb_surface->stride * 16;
psSliceParams->RefUVRowStride = ref_surface->psb_surface->stride * 16 / 2;
#else
psSliceParams->RefYStride = ref_surface->height * 16;
psSliceParams->RefUVStride = ref_surface->height * 8;
psSliceParams->RefYRowStride = psSliceParams->RefYStride;
psSliceParams->RefUVRowStride = psSliceParams->RefUVStride;
#endif
psSliceParams->FCode = ctx->FCode;/* Not clear yet, This field is not appare in firmware doc */
RowOffset = CurrentRow - 32;
if (RowOffset <= 0)
RowOffset = 0;
if (RowOffset > (ctx->Height - 80))
RowOffset = (ctx->Height - 80);
psSliceParams->MaxSliceSize = MaxSliceSize;
psSliceParams->NumAirMBs = ctx->num_air_mbs;
/* DDKv145: 3 lsb of threshold used as spacing between AIR MBs */
psSliceParams->AirThreshold = ctx->air_threshold + (FrameNum & 3) + 2;
if (ctx->autotune_air_flag)
psSliceParams->Flags |= AUTOTUNE_AIR;
if (!IsIntra) {
psSliceParams->Flags |= ISINTER_FLAGS;
}
if (DeblockSlice) {
psSliceParams->Flags |= DEBLOCK_FRAME;
}
switch (ctx->eCodec) {
case IMG_CODEC_H263_NO_RC:
case IMG_CODEC_H263_VBR:
case IMG_CODEC_H263_CBR:
psSliceParams->Flags |= ISH263_FLAGS;
break;
case IMG_CODEC_MPEG4_NO_RC:
case IMG_CODEC_MPEG4_VBR:
case IMG_CODEC_MPEG4_CBR:
psSliceParams->Flags |= ISMPEG4_FLAGS;
break;
case IMG_CODEC_H264_NO_RC:
case IMG_CODEC_H264_VBR:
case IMG_CODEC_H264_CBR:
case IMG_CODEC_H264_VCM:
psSliceParams->Flags |= ISH264_FLAGS;
break;
default:
psSliceParams->Flags |= ISH264_FLAGS;
drv_debug_msg(VIDEO_DEBUG_ERROR, "No format specified defaulting to h.264\n");
break;
}
/* we should also setup the interleaving requirements based on the source format */
if (ctx->eFormat != IMG_CODEC_PL12)
psSliceParams->Flags |= INTERLEAVE_TARGET;
cmdbuf = ctx->obj_context->lnc_cmdbuf;
RELOC_SLICE_PARAMS(&(psSliceParams->RefYBase), 16 * RowOffset, psRef);
RELOC_SLICE_PARAMS(&(psSliceParams->RefUVBase),
ref_surface->psb_surface->stride * ref_surface->height + (RowOffset * 16 / 2),
psRef);
RELOC_SLICE_PARAMS(&(psSliceParams->CodedData), 0, psCoded);
lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_ENCODE_SLICE, 2, (CurrentSlice << 2) | (IsIntra & 0x3));
RELOC_CMDBUF(cmdbuf->cmd_idx++,
CurrentSlice *((sizeof(SLICE_PARAMS) + 15) & 0xfff0),
&cmdbuf->slice_params);
return 0;
}
/*
* Function Name : Reset_EncoderParams
* Description : Reset Above & Below Params at the Start of Intra frame
*/
void lnc_reset_encoder_params(context_ENC_p ctx)
{
unsigned char *Add_Below, *Add_Above;
lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
/* all frames share the same Topaz param, in_param/aboveparam/bellow
* map it only when necessary
*/
if (cmdbuf->topaz_above_bellow_params_p == NULL) {
VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_above_bellow_params, &cmdbuf->topaz_above_bellow_params_p);
if (vaStatus != VA_STATUS_SUCCESS) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
return;
}
}
Add_Below = cmdbuf->topaz_above_bellow_params_p + ctx->bellow_params_ofs;
memset(Add_Below, 0, ctx->bellow_params_size);
Add_Above = cmdbuf->topaz_above_bellow_params_p + ctx->above_params_ofs;
memset(Add_Above, 0, ctx->above_params_size);
}