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