| /* |
| * Copyright (c) 2011 Intel Corporation. All Rights Reserved. |
| * Copyright (c) Imagination Technologies Limited, UK |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Elaine Wang <elaine.wang@intel.com> |
| * Zeng Li <zeng.li@intel.com> |
| * |
| */ |
| |
| |
| #include "psb_drv_video.h" |
| |
| //#include "pnw_H263ES.h" |
| #include "pnw_hostcode.h" |
| #include "hwdefs/topazSC_defs.h" |
| #include "psb_def.h" |
| #include "psb_drv_debug.h" |
| #include "psb_cmdbuf.h" |
| #include <stdio.h> |
| #include "psb_output.h" |
| #include <wsbm/wsbm_manager.h> |
| #include "pnw_hostheader.h" |
| |
| #define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1)) |
| #define PAGE_ALIGN(value) ALIGN_TO(value, 4096) |
| |
| /*static VAStatus pnw_DetectFrameSkip(context_ENC_p ctx);*/ |
| |
| static void pnw__update_rcdata( |
| context_ENC_p psContext, |
| PIC_PARAMS *psPicParams, |
| IMG_RC_PARAMS *psRCParams); |
| |
| IMG_UINT32 MVEARegBase[4] = {0x13000, 0x23000, 0x33000, 0x43000}; /* From TopazSC TRM */ |
| |
| /* H264 Zero bias */ |
| //#define ZERO_BIAS |
| |
| static const IMG_INT8 H263_QPLAMBDA_MAP[31] = { |
| 0, 0, 1, 1, 2, |
| 2, 3, 3, 4, 4, |
| 4, 5, 5, 5, 6, |
| 6, 6, 7, 7, 7, |
| 7, 8, 8, 8, 8, |
| 9, 9, 9, 9, 10, 10 |
| }; |
| |
| // New MP4 Lambda table |
| static const IMG_INT8 MPEG4_QPLAMBDA_MAP[31] = { |
| 0, 0, 1, 2, 3, |
| 3, 4, 4, 5, 5, |
| 6, 6, 7, 7, 8, |
| 8, 9, 9, 10, 10, |
| 11, 11, 11, 11, 12, |
| 12, 12, 12, 13, 13, 13 |
| }; |
| |
| // new H.264 Lambda |
| static const IMG_INT8 H264_QPLAMBDA_MAP[40] = { |
| 2, 2, 2, 2, 3, 3, 4, 4, |
| 4, 5, 5, 5, 5, 5, 6, 6, |
| 6, 7, 7, 7, 8, 8, 9, 11, |
| 13, 14, 15, 17, 20, 23, 27, 31, |
| 36, 41, 51, 62, 74, 79, 85, 91 |
| }; |
| |
| static const IMG_INT16 H264_InterIntraBias[27] = |
| { |
| 20,20,20,20,20,20,50, |
| 20,20,20,20,20,20, |
| 20,25,30,45,80,140, |
| 200,300,400,500,550, |
| 600,650,700 |
| }; |
| |
| /*static IMG_INT16 H264InterBias(IMG_INT8 i8QP) |
| { |
| if (i8QP >= 44) |
| return 600; |
| else if (i8QP <= 35) |
| return 20; |
| |
| return (70 * (i8QP - 35)); |
| }*/ |
| static IMG_INT16 H264InterBias(IMG_INT8 i8QP) |
| { |
| if (i8QP > 1) |
| i8QP = 1; |
| else if (i8QP > 51) |
| return 51; |
| |
| return H264_InterIntraBias[(i8QP + 1)>>1]; |
| } |
| |
| |
| static IMG_INT16 H264SkipBias(IMG_INT8 i8QP, TH_SKIP_SCALE eSkipScale) |
| { |
| IMG_INT16 i16Lambda; |
| |
| // pull out lambda from the table |
| i16Lambda = i8QP - 12; |
| i16Lambda = (i16Lambda < 0) ? 0 : i16Lambda; |
| i16Lambda = H264_QPLAMBDA_MAP[i16Lambda]; |
| |
| // now do the multiplication to avoid using the actual multiply we will do this with shifts and adds/subtractions it is probable that the compiler would |
| // pick up the multiply and optimise appropriatly but we aren't sure |
| // * 12 = 8 + *4 |
| switch (eSkipScale) { |
| default: |
| case TH_SKIP_0: |
| i16Lambda = 0; |
| break; |
| case TH_SKIP_24: /* iLambda * 24 == iLambda * 2 * 12 */ |
| i16Lambda <<= 1; |
| /* break deliberatly not used as we want to apply skip12 to skip24*/ |
| case TH_SKIP_12: /* iLambda * 12 == iLambda * (8 + 4) == (iLambda * 8) + (iLambda * 4) == (iLambda << 3) + (iLambda <<2) */ |
| i16Lambda = (i16Lambda << 3) + (i16Lambda << 2); |
| } |
| return i16Lambda; |
| } |
| |
| static IMG_INT16 H264Intra4x4Bias(IMG_INT8 i8QP) |
| { |
| IMG_INT16 i16Lambda; |
| |
| // pull out lambda from the table |
| i16Lambda = i8QP - 12; |
| i16Lambda = (i16Lambda < 0) ? 0 : i16Lambda; |
| i16Lambda = H264_QPLAMBDA_MAP[i16Lambda]; |
| |
| i16Lambda *= 120; |
| return i16Lambda; |
| } |
| |
| static int CalculateDCScaler(IMG_INT iQP, IMG_BOOL bChroma) |
| { |
| IMG_INT iDCScaler; |
| if (!bChroma) { |
| if (iQP > 0 && iQP < 5) { |
| iDCScaler = 8; |
| } else if (iQP > 4 && iQP < 9) { |
| iDCScaler = 2 * iQP; |
| } else if (iQP > 8 && iQP < 25) { |
| iDCScaler = iQP + 8; |
| } else { |
| iDCScaler = 2 * iQP - 16; |
| } |
| } else { |
| if (iQP > 0 && iQP < 5) { |
| iDCScaler = 8; |
| } else if (iQP > 4 && iQP < 25) { |
| iDCScaler = (iQP + 13) / 2; |
| } else { |
| iDCScaler = iQP - 6; |
| } |
| } |
| return iDCScaler; |
| } |
| |
| static void LoadMPEG4Bias( |
| pnw_cmdbuf_p cmdbuf, |
| IMG_INT32 i32Core, |
| IMG_UINT8 __maybe_unused ui8THSkip |
| ) |
| { |
| IMG_INT16 n; |
| IMG_INT16 iX; |
| IMG_UINT32 ui32RegVal; |
| IMG_UINT8 uiDCScaleL, uiDCScaleC, uiLambda; |
| IMG_INT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias; |
| IMG_UINT32 count = 0, cmd_word = 0; |
| uint32_t *pCount; |
| |
| cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | |
| ((i32Core & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT); |
| *cmdbuf->cmd_idx++ = cmd_word; |
| pCount = cmdbuf->cmd_idx; |
| cmdbuf->cmd_idx++; |
| |
| // this should be done for each core.... |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, SPE_ZERO_THRESHOLD); |
| for (n = 31; n > 0; n--) { |
| iX = n - 12; |
| if (iX < 0) { |
| iX = 0; |
| } |
| // Dont Write QP Values To ESB -- IPE will write these values |
| // Update the quantization parameter which includes doing Lamda and the Chroma QP |
| |
| uiDCScaleL = CalculateDCScaler(n, IMG_FALSE); |
| uiDCScaleC = CalculateDCScaler(n, IMG_TRUE); |
| uiLambda = MPEG4_QPLAMBDA_MAP[n - 1]; |
| |
| ui32RegVal = uiDCScaleL; |
| ui32RegVal |= (uiDCScaleC) << 8; |
| ui32RegVal |= (uiLambda) << 16; |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal); |
| |
| |
| uIPESkipVecBias = TH_SKIP_IPE * uiLambda; |
| iInterMBBias = TH_INTER * (n - TH_INTER_QP); |
| if (iInterMBBias < 0) |
| iInterMBBias = 0; |
| if (iInterMBBias > TH_INTER_MAX_LEVEL) |
| iInterMBBias = TH_INTER_MAX_LEVEL; |
| uSPESkipVecBias = TH_SKIP_SPE * uiLambda; |
| iIntra16Bias = 0; |
| |
| if (n & 1) { |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias); |
| } |
| } |
| *pCount = count; |
| } |
| |
| static void LoadH263Bias( |
| pnw_cmdbuf_p cmdbuf, IMG_INT32 i32Core, IMG_UINT8 __maybe_unused ui8THSkip) |
| { |
| IMG_INT16 n; |
| IMG_INT16 iX; |
| IMG_UINT32 ui32RegVal; |
| IMG_UINT8 uiDCScaleL, uiDCScaleC, uiLambda; |
| IMG_INT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias; |
| IMG_UINT32 count = 0, cmd_word = 0; |
| uint32_t *pCount; |
| |
| cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | |
| ((i32Core & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT); |
| *cmdbuf->cmd_idx++ = cmd_word; |
| pCount = cmdbuf->cmd_idx; |
| cmdbuf->cmd_idx++; |
| |
| |
| // this should be done for each core.... |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, SPE_ZERO_THRESHOLD); |
| for (n = 31; n > 0; n--) { |
| iX = n - 12; |
| if (iX < 0) { |
| iX = 0; |
| } |
| // Dont Write QP Values To ESB -- IPE will write these values |
| // Update the quantization parameter which includes doing Lamda and the Chroma QP |
| |
| uiDCScaleL = CalculateDCScaler(n, IMG_FALSE); |
| uiDCScaleC = CalculateDCScaler(n, IMG_TRUE); |
| uiLambda = H263_QPLAMBDA_MAP[n - 1]; |
| |
| ui32RegVal = uiDCScaleL; |
| ui32RegVal |= (uiDCScaleC) << 8; |
| ui32RegVal |= (uiLambda) << 16; |
| |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal); |
| |
| |
| uIPESkipVecBias = TH_SKIP_IPE * uiLambda; |
| iInterMBBias = TH_INTER * (n - TH_INTER_QP); |
| if (iInterMBBias < 0) |
| iInterMBBias = 0; |
| if (iInterMBBias > TH_INTER_MAX_LEVEL) |
| iInterMBBias = TH_INTER_MAX_LEVEL; |
| uSPESkipVecBias = TH_SKIP_SPE * uiLambda; |
| iIntra16Bias = 0; |
| // |
| if (n & 1) { |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias); |
| } |
| } |
| *pCount = count; |
| } |
| |
| static void LoadH264Bias( |
| pnw_cmdbuf_p cmdbuf, IMG_INT32 i32Core, IMG_UINT8 ui8THSkip, IMG_INT8 i8QpOff) |
| { |
| IMG_INT8 n; |
| IMG_INT8 iX; |
| IMG_UINT32 ui32RegVal; |
| IMG_UINT32 uIPESkipVecBias, iInterMBBias, uSPESkipVecBias, iIntra16Bias; |
| IMG_UINT32 count = 0, cmd_word = 0; |
| uint32_t *pCount; |
| |
| cmd_word = ((MTX_CMDID_SW_WRITEREG & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | |
| ((i32Core & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT); |
| *cmdbuf->cmd_idx++ = cmd_word; |
| pCount = cmdbuf->cmd_idx; |
| cmdbuf->cmd_idx++; |
| |
| |
| IMG_BYTE PVR_QP_SCALE_CR[76] = { |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 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, |
| 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, |
| }; |
| |
| for (n = 51; n >= 0; n--) { |
| |
| iX = n - 12; |
| if (iX < 0) |
| iX = 0; |
| |
| // Dont Write QP Values To ESB -- IPE will write these values |
| // Update the quantization parameter which includes doing Lamda and the Chroma QP |
| ui32RegVal = PVR_QP_SCALE_CR[n + 12 + i8QpOff ]; |
| ui32RegVal |= ((H264_QPLAMBDA_MAP[iX] * 24) / 16) << 8; |
| ui32RegVal |= (H264_QPLAMBDA_MAP[iX]) << 16; |
| |
| #ifdef ZERO_BIAS |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, (2 << 16) | F_ENCODE(3, MVEA_CR_IPE_ALPHA_OR_DC_SCALE_CHR_TABLE) | F_ENCODE(PVR_QP_SCALE_CR[n], MVEA_CR_IPE_QPC_OR_DC_SCALE_LUMA_TABLE)); |
| #else |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_LAMBDA_TABLE, ui32RegVal); |
| #endif |
| |
| } |
| for (n = 52; n >= 0; n -= 2) { |
| IMG_INT8 qp = n; |
| if (qp > 51) qp = 51; |
| |
| uIPESkipVecBias = H264SkipBias(qp, ui8THSkip); |
| iInterMBBias = H264InterBias(qp); |
| uSPESkipVecBias = H264SkipBias(qp, ui8THSkip); |
| iIntra16Bias = H264Intra4x4Bias(qp); |
| |
| #ifdef ZERO_BIAS |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, 0); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, 0); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, 0); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, 0); |
| #else |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_IPE_MV_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_PRED_VECTOR_BIAS_TABLE, uIPESkipVecBias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTRA16_BIAS_TABLE, iIntra16Bias); |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_INTER_BIAS_TABLE, iInterMBBias); |
| #endif |
| |
| } |
| |
| pnw_cmdbuf_insert_reg_write(MVEARegBase[i32Core], MVEA_CR_SPE_ZERO_THRESH, 0); |
| *pCount = count; |
| } |
| |
| |
| static VAStatus pnw__alloc_context_buffer(context_ENC_p ctx, unsigned char is_JPEG) |
| { |
| 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; |
| |
| if (is_JPEG == 0) { |
| ctx->pic_params_size = 256; |
| |
| ctx->header_buffer_size = 8 * 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->aud_header_ofs = 4 * HEADER_SIZE; |
| ctx->sei_buf_prd_ofs = 5 * HEADER_SIZE; |
| ctx->sei_pic_tm_ofs = 6 * HEADER_SIZE; |
| ctx->sei_pic_fpa_ofs = 7 * HEADER_SIZE; |
| ctx->slice_header_ofs = 8 * HEADER_SIZE; |
| ctx->in_params_ofs = 0; |
| |
| 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 = ((~0xf) & (15 + 1 + (width + 15) * (height + 15) / (16 * 16))) * sizeof(MTX_CURRENT_IN_PARAMS); |
| ctx->below_params_size = ((BELOW_PARAMS_SIZE * width * height / (16 * 16)) + 0xf) & (~0xf); |
| ctx->above_params_size = ((width / 16) * 128 + 15) & (~0xf) ; |
| |
| vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_I); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| return vaStatus; |
| } |
| |
| vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_P); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| psb_buffer_destroy(&ctx->topaz_in_params_I); |
| return vaStatus; |
| } |
| |
| vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->below_params_size * 4, psb_bt_cpu_vpu, &ctx->topaz_below_params); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| psb_buffer_destroy(&ctx->topaz_in_params_P); |
| psb_buffer_destroy(&ctx->topaz_in_params_I); |
| return vaStatus; |
| } |
| |
| vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->above_params_size * 4, psb_bt_cpu_vpu, &ctx->topaz_above_params); |
| if (VA_STATUS_SUCCESS != vaStatus) { |
| psb_buffer_destroy(&ctx->topaz_in_params_P); |
| psb_buffer_destroy(&ctx->topaz_in_params_I); |
| psb_buffer_destroy(&ctx->topaz_below_params); |
| return vaStatus; |
| } |
| ctx->below_params_ofs = 0; |
| ctx->above_params_ofs = 0; |
| } else { |
| /*JPEG encode need three kinds of buffer but doesn't need above/below buffers.*/ |
| ctx->pic_params_size = (sizeof(JPEG_MTX_QUANT_TABLE) + 0xf) & (~0xf); |
| |
| ctx->header_buffer_size = (sizeof(JPEG_MTX_DMA_SETUP) + 0xf) & (~0xf); |
| ctx->sliceparam_buffer_size = 16; /* Not used*/ |
| } |
| return vaStatus; |
| } |
| |
| unsigned int pnw__get_ipe_control(enum drm_pnw_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 pnw_DestroyContext(object_context_p obj_context) |
| { |
| context_ENC_p ctx; |
| ctx = (context_ENC_p)obj_context->format_data; |
| |
| psb_buffer_destroy(&ctx->topaz_in_params_P); |
| psb_buffer_destroy(&ctx->topaz_in_params_I); |
| psb_buffer_destroy(&ctx->topaz_below_params); |
| psb_buffer_destroy(&ctx->topaz_above_params); |
| |
| 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 pnw_CreateContext( |
| object_context_p obj_context, |
| object_config_p __maybe_unused obj_config, |
| unsigned char is_JPEG) |
| { |
| int width, height; |
| int i; |
| unsigned short SearchWidth, SearchHeight, SearchLeftOffset, SearchTopOffset; |
| 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)); |
| CHECK_ALLOCATION(ctx); |
| |
| obj_context->format_data = (void*) ctx; |
| ctx->obj_context = obj_context; |
| |
| ctx->RawWidth = (unsigned short) width; |
| ctx->RawHeight = (unsigned short) height; |
| |
| if (is_JPEG == 0) { |
| ctx->Width = (unsigned short)(~0xf & (width + 0xf)); |
| ctx->Height = (unsigned short)(~0xf & (height + 0xf)); |
| } else { |
| /*JPEG only require them are even*/ |
| ctx->Width = (unsigned short)(~0x1 & (width + 0x1)); |
| ctx->Height = (unsigned short)(~0x1 & (height + 0x1)); |
| } |
| |
| /* pre-calculated values based on other stream properties */ |
| SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height); |
| SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, ctx->Width); |
| SearchLeftOffset = (((SearchWidth / 2) / 16) * 16); |
| SearchTopOffset = (((SearchHeight / 2) / 16) * 16); |
| |
| ctx->HeightMinus16MinusLRBTopOffset = ctx->Height - (SearchTopOffset + 16); |
| ctx->HeightMinus32MinusLRBTopOffset = ctx->Height - (SearchTopOffset + 32); |
| ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16 = ctx->Height - (SearchTopOffset + SearchTopOffset + 16); |
| ctx->HeightMinusLRBSearchHeight = ctx->Height - SearchHeight; |
| |
| ctx->FCode = 0; |
| |
| ctx->NumCores = 2; /* FIXME Assume there is two encode cores in Penwell, precise value should read from HW */ |
| |
| ctx->BelowParamsBufIdx = 0; |
| ctx->AccessUnitNum = 0; |
| ctx->SyncSequencer = 0; /* FIXME Refer to DDK */ |
| ctx->SliceToCore = -1; |
| ctx->CmdCount = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT; |
| ctx->FrmIdx = 0; |
| |
| for (i = 0; i < MAX_TOPAZ_CORES; i++) { |
| ctx->LastSliceNum[i] = -1; |
| ctx->LastSync[0][i] = ~0; |
| ctx->LastSync[1][i] = ~0; |
| } |
| |
| for (i = 0; i < MAX_SLICES_PER_PICTURE; i++) { |
| ctx->SliceHeaderReady[i] = IMG_FALSE; |
| } |
| |
| vaStatus = pnw__alloc_context_buffer(ctx, is_JPEG); |
| |
| return vaStatus; |
| } |
| |
| VAStatus pnw_BeginPicture(context_ENC_p ctx) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| pnw_cmdbuf_p cmdbuf; |
| int ret, i; |
| |
| if (ctx->raw_frame_count != 0) |
| ctx->previous_src_surface = ctx->src_surface; |
| ctx->src_surface = ctx->obj_context->current_render_target; |
| |
| /* clear frameskip flag to 0 */ |
| CLEAR_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface); |
| ctx->none_vcl_nal = 0; |
| |
| /*if (ctx->sRCParams.RCEnable == IMG_TRUE) |
| { |
| pnw_DetectFrameSkip(ctx); |
| if (0 != (GET_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface) |
| & SURFACE_INFO_SKIP_FLAG_SETTLED)) |
| ctx->sRCParams.FrameSkip = IMG_TRUE; |
| else |
| ctx->sRCParams.FrameSkip = IMG_FALSE; |
| }*/ |
| |
| /* Initialise the command buffer */ |
| ret = pnw_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->pnw_cmdbuf; |
| memset(cmdbuf->cmd_idx_saved, 0, sizeof(cmdbuf->cmd_idx_saved)); |
| |
| |
| /* 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_above_params_p = NULL; |
| cmdbuf->topaz_below_params_p = NULL; |
| cmdbuf->topaz_in_params_I_p = NULL; |
| cmdbuf->topaz_in_params_P_p = NULL; |
| |
| if (ctx->obj_context->frame_count == 0) { /* first picture */ |
| |
| psb_driver_data_p driver_data = ctx->obj_context->driver_data; |
| |
| *cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | |
| (((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT)); |
| pnw_cmdbuf_insert_command_param(ctx->eCodec); |
| pnw_cmdbuf_insert_command_param((ctx->Width << 16) | ctx->Height); |
| } |
| |
| ctx->FrmIdx++; |
| ctx->SliceToCore = ctx->ParallelCores - 1; |
| /* ctx->AccessUnitNum++; Move this back to pnw_EndPicture */ |
| ctx->sRCParams.bBitrateChanged = IMG_FALSE; |
| |
| for (i = 0; i < MAX_TOPAZ_CORES; i++) |
| ctx->LastSliceNum[i] = -1; |
| |
| for (i = 0; i < MAX_SLICES_PER_PICTURE; i++) |
| ctx->SliceHeaderReady[i] = IMG_FALSE; |
| |
| /*If ParallelCores > 1(H264) and encode one slice per frame, the unnecessary start picture |
| *commands will be replaced with MTX_CMDID_PAD and ignored by kernel*/ |
| cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] = cmdbuf->cmd_idx; |
| |
| /* insert START_PIC command for each core */ |
| /* ensure that the master (core #0) will be last to complete this batch */ |
| for (i = (ctx->ParallelCores - 1); i >= 0; i--) { |
| |
| /* |
| * the content of PIC_PARAMS is filled when RenderPicture(...,VAEncPictureParameterBufferXXX) |
| */ |
| pnw_cmdbuf_insert_command_package(ctx->obj_context, |
| i, |
| MTX_CMDID_START_PIC, |
| &cmdbuf->pic_params, |
| i * ctx->pic_params_size); |
| |
| /* no RC paramter provided in vaBeginPicture |
| * so delay RC param setup into vaRenderPicture(SequenceHeader...) |
| */ |
| } |
| |
| ctx->obj_context->slice_count = 0; |
| return 0; |
| } |
| |
| |
| VAStatus pnw_set_bias(context_ENC_p ctx, int core) |
| { |
| pnw_cmdbuf_p cmdbuf = (pnw_cmdbuf_p)ctx->obj_context->pnw_cmdbuf; |
| double flBpp; |
| IMG_UINT8 THSkip; |
| |
| if (ctx->sRCParams.RCEnable) { |
| flBpp = 1.0 * ctx->sRCParams.BitsPerSecond / |
| (ctx->sRCParams.FrameRate * ctx->Width * ctx->Height); |
| } else { |
| flBpp = 0.14; |
| } |
| |
| if (flBpp <= 0.07) { |
| THSkip = TH_SKIP_24; |
| } else if (flBpp <= 0.14) { |
| THSkip = TH_SKIP_12; |
| } else { |
| THSkip = TH_SKIP_0; |
| } |
| switch (ctx->eCodec) { |
| case IMG_CODEC_H264_VBR: |
| case IMG_CODEC_H264_CBR: |
| case IMG_CODEC_H264_VCM: |
| case IMG_CODEC_H264_NO_RC: |
| LoadH264Bias(cmdbuf, core, THSkip, ctx->sRCParams.QCPOffset); |
| break; |
| case IMG_CODEC_H263_CBR: |
| case IMG_CODEC_H263_NO_RC: |
| case IMG_CODEC_H263_VBR: |
| LoadH263Bias(cmdbuf, core, THSkip); |
| break; |
| case IMG_CODEC_MPEG4_NO_RC: |
| case IMG_CODEC_MPEG4_CBR: |
| case IMG_CODEC_MPEG4_VBR: |
| LoadMPEG4Bias(cmdbuf, core, THSkip); |
| break; |
| default: |
| return -1; |
| break; |
| } |
| return 0; |
| } |
| |
| VAStatus pnw_RenderPictureParameter(context_ENC_p ctx, int core) |
| { |
| PIC_PARAMS *psPicParams; /* PIC_PARAMS has been put in pnw_hostcode.h */ |
| object_surface_p src_surface; |
| unsigned int srf_buf_offset; |
| object_surface_p rec_surface; |
| object_surface_p ref_surface; |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN; |
| |
| psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p + ctx->pic_params_size * core); |
| |
| memset(psPicParams, 0, sizeof(PIC_PARAMS)); |
| /* 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; |
| CHECK_SURFACE(src_surface); |
| |
| rec_surface = ctx->dest_surface; |
| CHECK_SURFACE(rec_surface); |
| |
| /*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; |
| CHECK_SURFACE(rec_surface); |
| |
| /* 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 * 8 / 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 * 8; |
| 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; |
| #else |
| psPicParams->DstYStride = rec_surface->psb_surface->stride; |
| psPicParams->DstUVStride = rec_surface->psb_surface->stride; |
| #endif |
| |
| psPicParams->Width = ctx->Width; |
| psPicParams->Height = ctx->Height; |
| psPicParams->NumSlices = ctx->sRCParams.Slices; |
| |
| psPicParams->IsPerSliceOutput = IMG_FALSE; |
| psPicParams->SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, psPicParams->Height); |
| psPicParams->SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, psPicParams->Width); |
| |
| /* 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 | ISCBR_FLAGS); |
| break; |
| 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 0 |
| if (ctx->SyncSequencer) |
| psPicParams->Flags |= SYNC_SEQUENCER; |
| #endif |
| |
| if (ctx->sRCParams.RCEnable) { |
| if (ctx->sRCParams.bDisableFrameSkipping) { |
| psPicParams->Flags |= DISABLE_FRAME_SKIPPING; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Frame skip is disabled.\n"); |
| } |
| |
| if (ctx->sRCParams.bDisableBitStuffing && IS_H264_ENC(ctx->eCodec)) { |
| psPicParams->Flags |= DISABLE_BIT_STUFFING; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bit stuffing is disabled.\n"); |
| } |
| |
| |
| /* for the first frame, will setup RC params in EndPicture */ |
| if (ctx->raw_frame_count > 0) { /* reuse in_params parameter */ |
| /* In case, it's changed in a new sequence */ |
| if (ctx->obj_context->frame_count == 0 |
| && ctx->in_params_cache.IntraPeriod != ctx->sRCParams.IntraFreq) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "On frame %d, Intra period is changed from %d to %d\n", |
| ctx->raw_frame_count, ctx->in_params_cache.IntraPeriod, |
| ctx->sRCParams.IntraFreq); |
| ctx->in_params_cache.IntraPeriod = ctx->sRCParams.IntraFreq; |
| ctx->in_params_cache.BitsPerGOP = |
| (ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate) |
| * ctx->sRCParams.IntraFreq; |
| } |
| |
| psPicParams->Flags &= ~FIRST_FRAME; |
| /* reload IN_RC_PARAMS from cache */ |
| memcpy(&psPicParams->sInParams, &ctx->in_params_cache, sizeof(IN_RC_PARAMS)); |
| } else { |
| psPicParams->Flags |= ISRC_FLAGS; |
| psPicParams->Flags |= FIRST_FRAME; |
| } |
| } 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_PNW(&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_PNW(&psPicParams->SrcUBase, |
| srf_buf_offset + src_surface->psb_surface->chroma_offset, |
| &src_surface->psb_surface->buf); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->SrcVBase, |
| srf_buf_offset + src_surface->psb_surface->chroma_offset * 5 / 4, |
| &src_surface->psb_surface->buf); |
| |
| break; |
| case IMG_CODEC_IMC2: |
| case IMG_CODEC_NV12: |
| default: |
| break; |
| } |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->DstYBase, 0, &rec_surface->psb_surface->buf); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->DstUVBase, |
| rec_surface->psb_surface->stride * rec_surface->height, |
| &rec_surface->psb_surface->buf); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->BelowParamsInBase, |
| ctx->below_params_ofs + ctx->below_params_size *(((ctx->AccessUnitNum) & 0x1)), |
| cmdbuf->topaz_below_params); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->BelowParamsOutBase, |
| ctx->below_params_ofs + ctx->below_params_size *(((ctx->AccessUnitNum + 1) & 0x1)), |
| cmdbuf->topaz_below_params); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->AboveParamsBase, |
| ctx->above_params_ofs + ctx->above_params_size *(core * 2 + (ctx->AccessUnitNum & 0x1)), |
| cmdbuf->topaz_above_params); |
| |
| RELOC_PIC_PARAMS_PNW(&psPicParams->CodedBase, ctx->coded_buf_per_slice * core, ctx->coded_buf->psb_buffer); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "For core %d, above_parmas_off %x\n", core, ctx->above_params_ofs + ctx->above_params_size *(core * 2 + ((ctx->AccessUnitNum) & 0x1))); |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus pnw_SetupRCParam(context_ENC_p ctx) |
| { |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; |
| PIC_PARAMS *psPicParamsTmp; |
| int origin_qp, i;/* in DDK setup_rc will change qp strangly, |
| * just for keep same with DDK |
| */ |
| |
| origin_qp = ctx->sRCParams.InitialQp; |
| |
| psPicParams->Flags |= ISRC_FLAGS; |
| pnw__setup_rcdata(ctx, psPicParams, &ctx->sRCParams); |
| |
| /* restore it, just keep same with DDK */ |
| ctx->sRCParams.InitialQp = origin_qp; |
| |
| /* Assume IN_RC_PARAMS for each core is identical, and copy for each */ |
| for (i = (ctx->ParallelCores - 1); i > 0; i--) { |
| psPicParamsTmp = (PIC_PARAMS *)(cmdbuf->pic_params_p + ctx->pic_params_size * i); |
| memcpy((unsigned char *)&psPicParamsTmp->sInParams, |
| (unsigned char *)&psPicParams->sInParams, |
| sizeof(IN_RC_PARAMS)); |
| psPicParamsTmp->Flags |= psPicParams->Flags; |
| } |
| |
| /* save IN_RC_PARAMS into the cache */ |
| memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS)); |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus pnw_EndPicture(context_ENC_p ctx) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| unsigned int i; |
| int index; |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p; |
| PIC_PARAMS *psPicParamsSlave = NULL; |
| unsigned int val = 0; |
| |
| ctx->AccessUnitNum++; |
| |
| if (ctx->sRCParams.RCEnable) { |
| if (ctx->raw_frame_count == 0) |
| pnw_SetupRCParam(ctx); |
| else if (ctx->sRCParams.bBitrateChanged) { |
| /* Toggle the last bit to make sure encoder firmare recalculate the |
| RC params even if the target bitrate isn't changed.*/ |
| val = ~(ctx->sRCParams.BitsPerSecond & 0x1); |
| ctx->sRCParams.BitsPerSecond &= ~1; |
| ctx->sRCParams.BitsPerSecond |= (val & 1); |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "bitrate is changed to %d, " |
| "update the rc data accordingly\n", ctx->sRCParams.BitsPerSecond); |
| pnw__update_rcdata(ctx, psPicParams, &ctx->sRCParams); |
| if (ctx->sRCParams.MinQP) |
| psPicParams->sInParams.MinQPVal = ctx->sRCParams.MinQP; |
| memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS)); |
| /* Save rate control info in slave core as well */ |
| for (i = 1; i < ctx->ParallelCores; i++) { |
| psPicParamsSlave = (PIC_PARAMS *)(cmdbuf->pic_params_p + ctx->pic_params_size * i); |
| memcpy((unsigned char *)&psPicParamsSlave->sInParams, |
| (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS)); |
| } |
| } |
| } |
| |
| #if TOPAZ_PIC_PARAMS_VERBOSE |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "End Picture for frame %d\n", ctx->raw_frame_count); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof PIC_PARAMS %d\n", sizeof(PIC_PARAMS)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof in_params %d\n", sizeof(psPicParams->sInParams)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYBase 0x%08x\n", psPicParams->SrcYBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUBase 0x%08x\n", psPicParams->SrcUBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcVBase 0x%08x\n", psPicParams->SrcVBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstYBase 0x%08x\n", psPicParams->DstYBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstUVBase 0x%08x\n", psPicParams->DstUVBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYStride 0x%08x\n", psPicParams->SrcYStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUVStride 0x%08x\n", psPicParams->SrcUVStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcYRowStride 0x%08x\n", psPicParams->SrcYRowStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SrcUVRowStride 0x%08x\n", psPicParams->SrcUVRowStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstYStride 0x%08x\n", psPicParams->DstYStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->DstUVStride 0x%08x\n", psPicParams->DstUVStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->CodedBase 0x%08x\n", psPicParams->CodedBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->BelowParamsInBase 0x%08x\n", psPicParams->BelowParamsInBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->BelowParamsOutBase 0x%08x\n", psPicParams->BelowParamsOutBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->AboveParamsBase 0x%08x\n", psPicParams->AboveParamsBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Width 0x%08x\n", psPicParams->Width); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Height 0x%08x\n", psPicParams->Height); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->Flags 0x%08x\n", psPicParams->Flags); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SerachWidth 0x%08x\n", psPicParams->SearchWidth); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->SearchHeight 0x%08x\n", psPicParams->SearchHeight); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "PicParams->NumSlices 0x%08x\n", psPicParams->NumSlices); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->ClockDivBitrate %lld\n", psPicParams->ClockDivBitrate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->MaxBufferMultClockDivBitrate %d\n", |
| psPicParams->MaxBufferMultClockDivBitrate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.SeInitQP %d\n", psPicParams->sInParams.SeInitQP); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MinQPVal %d\n", psPicParams->sInParams.MinQPVal); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MaxQPVal %d\n", psPicParams->sInParams.MaxQPVal); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerRow %d\n", psPicParams->sInParams.MBPerRow); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerFrm %d\n", psPicParams->sInParams.MBPerFrm); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MBPerBU %d\n", psPicParams->sInParams.MBPerBU); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BUPerFrm %d\n", psPicParams->sInParams.BUPerFrm); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.IntraPeriod %d\n", psPicParams->sInParams.IntraPeriod); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerFrm %d\n", psPicParams->sInParams.BitsPerFrm); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerBU %d\n", psPicParams->sInParams.BitsPerBU); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerMB %d\n", psPicParams->sInParams.BitsPerMB); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitRate %d\n", psPicParams->sInParams.BitRate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BufferSize %d\n", psPicParams->sInParams.BufferSize); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.InitialLevel %d\n", psPicParams->sInParams.InitialLevel); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.InitialDelay %d\n", psPicParams->sInParams.InitialDelay); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.ScaleFactor %d\n", psPicParams->sInParams.ScaleFactor); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.VCMBitrateMargin %d\n", psPicParams->sInParams.VCMBitrateMargin); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.HalfFrameRate %d\n", psPicParams->sInParams.HalfFrameRate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.FCode %d\n", psPicParams->sInParams.FCode); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.BitsPerGOP %d\n", psPicParams->sInParams.BitsPerGOP); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.AvQPVal %d\n", psPicParams->sInParams.AvQPVal); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MyInitQP %d\n", psPicParams->sInParams.MyInitQP); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.ForeceSkipMargin %d\n", psPicParams->sInParams.ForeceSkipMargin); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.RCScaleFactor %d\n", psPicParams->sInParams.RCScaleFactor); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.TransferRate %d\n", psPicParams->sInParams.TransferRate); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psPicParams->sInParams.MaxFrameSize %d\n", psPicParams->sInParams.MaxFrameSize); |
| #endif |
| /* save current settings */ |
| ctx->previous_ref_surface = ctx->ref_surface; |
| ctx->previous_dest_surface = ctx->dest_surface; /* reconstructed surface */ |
| SET_CODEDBUF_INFO(SLICE_NUM, ctx->coded_buf->codedbuf_aux_info, |
| ctx->obj_context->slice_count); |
| SET_CODEDBUF_INFO(NONE_VCL_NUM, ctx->coded_buf->codedbuf_aux_info, |
| ctx->none_vcl_nal); |
| |
| for (index = (ctx->ParallelCores - 1); index >= 0; index--) { |
| pnw_cmdbuf_insert_command_package(ctx->obj_context, |
| index, |
| MTX_CMDID_END_PIC, |
| NULL, |
| 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_params_p != NULL) { |
| psb_buffer_unmap(cmdbuf->topaz_above_params); |
| cmdbuf->topaz_above_params_p = NULL; |
| } |
| |
| if (cmdbuf->topaz_below_params_p != NULL) { |
| psb_buffer_unmap(cmdbuf->topaz_below_params); |
| cmdbuf->topaz_below_params_p = NULL; |
| } |
| |
| if (pnw_context_flush_cmdbuf(ctx->obj_context)) { |
| vaStatus = VA_STATUS_ERROR_UNKNOWN; |
| } |
| ctx->raw_frame_count++; |
| return vaStatus; |
| } |
| |
| static void pnw__setup_busize(context_ENC_p ctx) |
| { |
| unsigned int old_busize = ctx->sRCParams.BUSize; |
| int slices = ctx->obj_context->slice_count; |
| |
| /* 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; |
| IMG_UINT32 MaxSlicesPerPipe, MaxMBsPerPipe, MaxBUsPerPipe; |
| |
| MBs = ctx->Height * ctx->Width / (16 * 16); |
| |
| SliceHeight = ctx->Height / slices; |
| /* SliceHeight += 15; */ |
| SliceHeight &= ~15; |
| |
| MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16); |
| MBsLastSlice = MBs - (MBsperSlice * (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 */; |
| } |
| |
| if (ctx->sRCParams.BUSize != 0) { |
| 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 (ctx->sRCParams.BUSize != 0) { |
| BUs = MBsLastSlice / ctx->sRCParams.BUSize; |
| if ((BUs * ctx->sRCParams.BUSize) != MBsLastSlice) { |
| 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 (ctx->sRCParams.BUSize != 0) { |
| // check if the number of BUs per pipe is greater than 200 |
| MaxSlicesPerPipe = (slices + ctx->ParallelCores - 1) / ctx->ParallelCores; |
| MaxMBsPerPipe = (MBsperSlice * (MaxSlicesPerPipe - 1)) + MBsLastSlice; |
| MaxBUsPerPipe = (MaxMBsPerPipe + ctx->sRCParams.BUSize - 1) / ctx->sRCParams.BUSize; |
| if (MaxBUsPerPipe > 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 BUsperSlice, BUsLastSlice; |
| IMG_UINT32 MaxSlicesPerPipe, MaxMBsPerPipe, MaxBUsPerPipe; |
| IMG_INT32 SliceHeight; |
| IMG_UINT32 BUSize = 6; |
| |
| MBs = ctx->Height * ctx->Width / (16 * 16); |
| |
| SliceHeight = ctx->Height / slices; |
| /* SliceHeight += 15; */ |
| SliceHeight &= ~15; |
| |
| MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16); |
| MBsLastSlice = MBs - (MBsperSlice * (slices - 1)); |
| |
| /* Check number of BUs to be encoded on one pipe is less than maximum number allowed 200 */ |
| MaxSlicesPerPipe = (slices + ctx->ParallelCores - 1) / ctx->ParallelCores; |
| MaxMBsPerPipe = (MBsperSlice * (MaxSlicesPerPipe - 1)) + MBsLastSlice; |
| MaxBUsPerPipe = (MaxMBsPerPipe + BUSize - 1) / BUSize; |
| |
| while (MaxBUsPerPipe > 200) { |
| BUSize++; |
| MaxBUsPerPipe = (MaxMBsPerPipe + BUSize - 1) / BUSize; |
| } |
| |
| /* Check whether there are integeral number of BUs in the slices */ |
| BUsperSlice = MBsperSlice / BUSize; |
| BUsLastSlice = MBsLastSlice / BUSize; |
| while ((BUsperSlice*BUSize != MBsperSlice) || |
| (BUsLastSlice*BUSize != MBsLastSlice)) { |
| BUSize++; |
| BUsperSlice = MBsperSlice / BUSize; |
| BUsLastSlice = MBsLastSlice / BUSize; |
| } |
| |
| ctx->sRCParams.BUSize = BUSize; |
| /* |
| ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4; |
| ctx->sRCParams.InitialDelay = (13 * ctx->sRCParams.BufferSize) >> 4; |
| */ |
| } |
| |
| 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); |
| } |
| |
| |
| static void pnw__update_rcdata( |
| context_ENC_p psContext, |
| PIC_PARAMS *psPicParams, |
| IMG_RC_PARAMS *psRCParams) |
| { |
| double L1, L2, L3, L4, L5, L6, flBpp; |
| IMG_INT16 i16TempQP; |
| IMG_INT32 i32BufferSizeInFrames = 0; |
| |
| flBpp = 1.0 * psRCParams->BitsPerSecond |
| / (psRCParams->FrameRate * psContext->Width * psContext->Height); |
| |
| if (psContext->Width <= 176) { |
| /* for very small franes we need to adjust the calculations */ |
| flBpp = flBpp / 2.0; |
| } |
| |
| psPicParams->sInParams.IntraPeriod = psRCParams->IntraFreq; |
| psPicParams->sInParams.BitRate = psRCParams->BitsPerSecond; |
| psPicParams->sInParams.BitsPerFrm = (psRCParams->BitsPerSecond + psRCParams->FrameRate / 2) / psRCParams->FrameRate; |
| psPicParams->sInParams.BitsPerGOP = (psRCParams->BitsPerSecond / psRCParams->FrameRate) * psRCParams->IntraFreq; |
| psPicParams->sInParams.BitsPerBU = psPicParams->sInParams.BitsPerFrm / (4 * psPicParams->sInParams.BUPerFrm); |
| psPicParams->sInParams.BitsPerMB = psPicParams->sInParams.BitsPerBU / psRCParams->BUSize; |
| psPicParams->sInParams.TransferRate = psRCParams->BitsPerSecond / psRCParams->FrameRate; |
| |
| 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; |
| |
| /* Set MaxQP to avoid blocky image in low bitrate */ |
| /* RCScaleFactor indicates the size of GOP for rate control */ |
| if (psContext->eCodec == IMG_CODEC_H264_VCM) { |
| psPicParams->sInParams.MaxQPVal = 51; |
| psPicParams->sInParams.RCScaleFactor = 16; |
| } |
| else { |
| psPicParams->sInParams.MaxQPVal = 51; |
| psPicParams->sInParams.RCScaleFactor = 16; |
| } |
| |
| /* Setup MAX and MIN Quant Values */ |
| if (flBpp >= 0.50) |
| i16TempQP = 4; |
| else |
| i16TempQP = (unsigned int)(26 - (40 * flBpp)); |
| |
| psPicParams->sInParams.MinQPVal = (max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0)); |
| |
| L1 = 0.050568; |
| L2 = 0.202272; |
| L3 = 0.40454321; |
| L4 = 0.80908642; |
| L5 = 1.011358025; |
| if (flBpp < L1) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(47 - 78.10 * flBpp); |
| |
| else if (flBpp >= L1 && flBpp < L2) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(45 - 66.67 * flBpp); |
| |
| else if (flBpp >= L2 && flBpp < L3) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(36 - 24.72 * flBpp); |
| |
| else if (flBpp >= L3 && flBpp < L4) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(34 - 19.78 * flBpp); |
| |
| else if (flBpp >= L4 && flBpp < L5) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(27 - 9.89 * flBpp); |
| |
| else if (flBpp >= L5 && flBpp < 4) |
| psPicParams->sInParams.SeInitQP = (IMG_UINT8)(20 - 4.95 * flBpp); |
| else |
| psPicParams->sInParams.SeInitQP = psPicParams->sInParams.MinQPVal; |
| |
| if (psPicParams->sInParams.SeInitQP < psPicParams->sInParams.MinQPVal) |
| psPicParams->sInParams.SeInitQP = psPicParams->sInParams.MinQPVal; |
| |
| break; |
| |
| case IMG_CODEC_MPEG4_CBR: |
| case IMG_CODEC_MPEG4_VBR: |
| case IMG_CODEC_H263_CBR: |
| case IMG_CODEC_H263_VBR: |
| psPicParams->sInParams.RCScaleFactor = 16; |
| psPicParams->sInParams.MaxQPVal = 31; |
| |
| if (psContext->Width <= 176) { |
| L1 = 0.043; |
| L2 = 0.085; |
| L3 = 0.126; |
| L4 = 0.168; |
| L5 = 0.336; |
| L6 = 0.505; |
| } else if (psContext->Width == 352) { |
| L1 = 0.065; |
| L2 = 0.085; |
| L3 = 0.106; |
| L4 = 0.126; |
| L5 = 0.168 ; |
| L6 = 0.210; |
| } else { |
| L1 = 0.051; |
| L2 = 0.0770; |
| L3 = 0.096; |
| L4 = 0.145; |
| L5 = 0.193; |
| L6 = 0.289; |
| } |
| |
| /* Calculate Initial QP if it has not been specified */ |
| if (flBpp < L1) |
| psPicParams->sInParams.SeInitQP = 31; |
| |
| else if (flBpp >= L1 && flBpp < L2) |
| psPicParams->sInParams.SeInitQP = 26; |
| |
| else if (flBpp >= L2 && flBpp < L3) |
| psPicParams->sInParams.SeInitQP = 22; |
| |
| else if (flBpp >= L3 && flBpp < L4) |
| psPicParams->sInParams.SeInitQP = 18; |
| |
| else if (flBpp >= L4 && flBpp < L5) |
| psPicParams->sInParams.SeInitQP = 14; |
| |
| else if (flBpp >= L5 && flBpp < L6) |
| psPicParams->sInParams.SeInitQP = 10; |
| else |
| psPicParams->sInParams.SeInitQP = 8; |
| |
| psPicParams->sInParams.AvQPVal = psPicParams->sInParams.SeInitQP; |
| |
| if (flBpp >= 0.25 |
| && (psContext->eCodec == IMG_CODEC_MPEG4_CBR || |
| psContext->eCodec == IMG_CODEC_MPEG4_VBR)) { |
| psPicParams->sInParams.MinQPVal = 1; |
| } else { |
| psPicParams->sInParams.MinQPVal = 4; |
| } |
| 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); |
| if (psContext->Height >= 480) { |
| /* for SD and above we can target 95% (122/128) of maximum bitrate */ |
| psPicParams->sInParams.VCMBitrateMargin = 122; |
| } else { |
| /* for less and SD we target 99% of maximum bitrate */ |
| psPicParams->sInParams.VCMBitrateMargin = 127; |
| } |
| if (i32BufferSizeInFrames < 15) { |
| /* when we have a very small window size we reduce the target |
| * further to avoid too much skipping */ |
| psPicParams->sInParams.VCMBitrateMargin -= 5; |
| } |
| psPicParams->sInParams.ForeceSkipMargin = 0; /* start skipping MBs when within 500 bits of slice or frame limit */ |
| 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; |
| } |
| |
| psPicParams->sInParams.BufferSize = psRCParams->BufferSize; |
| if (psPicParams->sInParams.BufferSize > 112 * 16384) // Simple Profile L5 Constraints |
| psPicParams->sInParams.BufferSize = 112 * 16384; |
| 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 = psRCParams->BufferSize; |
| |
| if (psContext->eCodec != IMG_CODEC_H264_VBR) { |
| if (psPicParams->sInParams.BufferSize > 112 * 16384) |
| psPicParams->sInParams.BufferSize = 112 * 16384; // Simple Profile L5 Constraints |
| } |
| |
| /* 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; |
| |
| #if 0 |
| if (psContext->SyncSequencer) |
| psPicParams->Flags |= SYNC_SEQUENCER; |
| #endif |
| |
| psPicParams->sInParams.InitialDelay = psRCParams->InitialDelay; |
| psPicParams->sInParams.InitialLevel = psRCParams->InitialLevel; |
| psRCParams->InitialQp = psPicParams->sInParams.SeInitQP; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "InitQP %d, minQP %d, maxQP %d\n", |
| psPicParams->sInParams.SeInitQP, |
| psPicParams->sInParams.MinQPVal, |
| psPicParams->sInParams.MaxQPVal); |
| |
| /* The rate control uses this value to adjust the reaction rate |
| to larger than expected frames in long GOPS*/ |
| |
| return; |
| } |
| |
| |
| /*********************************************************************************** |
| * Function Name : SetupRCData |
| * Inputs : |
| * Outputs : |
| * Returns : |
| * Description : Sets up RC Data |
| ************************************************************************************/ |
| void pnw__setup_rcdata( |
| context_ENC_p psContext, |
| PIC_PARAMS *psPicParams, |
| IMG_RC_PARAMS *psRCParams) |
| { |
| IMG_UINT8 ui8InitialSeInitQP; |
| |
| /* 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; |
| |
| pnw__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; |
| psPicParams->sInParams.AvQPVal = psRCParams->InitialQp; |
| psPicParams->sInParams.MyInitQP = psRCParams->InitialQp; |
| psPicParams->sInParams.MaxFrameSize = psRCParams->BitsPerSecond / psRCParams->FrameRate; |
| |
| ui8InitialSeInitQP = psPicParams->sInParams.SeInitQP; |
| |
| pnw__update_rcdata(psContext, psPicParams, psRCParams); |
| |
| /*If MinQP has been set, restore this value rather than |
| *the calculated value set by UpdateRCData()*/ |
| if (psRCParams->MinQP) { |
| psPicParams->sInParams.MinQPVal = (IMG_UINT8)psRCParams->MinQP; |
| } |
| |
| /*If SeInitQP has been set, restore this value and other |
| * dependant variables rather than the calculated values set by UpdateRCData()*/ |
| if (ui8InitialSeInitQP) { |
| psPicParams->sInParams.SeInitQP = ui8InitialSeInitQP; |
| psPicParams->sInParams.MyInitQP = ui8InitialSeInitQP; |
| psRCParams->InitialQp = ui8InitialSeInitQP; |
| } |
| |
| /* HRD parameters are meaningless without a bitrate |
| * HRD parameters are not supported in VCM mode */ |
| if (psRCParams->BitsPerSecond == 0 || psContext->eCodec == IMG_CODEC_H264_VCM) |
| psContext->bInserHRDParams = IMG_FALSE; |
| |
| if (psContext->bInserHRDParams) { |
| psPicParams->ClockDivBitrate = (90000 * 0x100000000LL); |
| psPicParams->ClockDivBitrate /= psRCParams->BitsPerSecond; |
| psPicParams->MaxBufferMultClockDivBitrate = (IMG_UINT32) |
| (((IMG_UINT64)(psRCParams->BufferSize) * (IMG_UINT64) 90000) |
| / (IMG_UINT64) psRCParams->BitsPerSecond); |
| } |
| return ; |
| } |
| |
| static void pnw__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 pnw__setup_qpvalues_mpeg4( |
| MTX_CURRENT_IN_PARAMS * psCurrent, |
| IMG_BYTE bySliceQP) |
| { |
| psCurrent->bySliceQP = bySliceQP; |
| } |
| |
| static void pnw__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 |
| */ |
| MTX_CURRENT_IN_PARAMS *psCurrent; |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| |
| IMG_INT16 iPos, iYPos, srcY; |
| IMG_UINT16 ui16tmp; |
| IMG_UINT16 ui16SearchWidth, ui16SearchHeight, ui16SearchLeftOffset, ui16SearchTopOffset, ui16CurBlockX; |
| |
| 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); |
| |
| // Note: CurrentRowY and iSliceStartRowY are now in pixels (not MacroBlocks) - saves needless multiplications and divisions |
| |
| ui16SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height); |
| ui16SearchWidth = min(MVEA_LRB_SEARCH_WIDTH, ctx->Width); |
| ui16SearchLeftOffset = (((ui16SearchWidth / 2) / 16) * 16); // this is the amount of data that gets preloaded |
| ui16SearchTopOffset = (((ui16SearchHeight / 2) / 16) * 16); |
| ui16CurBlockX = MVEA_LRB_SEARCH_WIDTH - (ui16SearchLeftOffset + 16); // this is our block position relative to the start of the LRB |
| |
| if ((iYPos = srcY = CurrentRowY - ui16SearchTopOffset) < 0) |
| srcY = 0; |
| else if (iYPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) |
| srcY = ctx->HeightMinusLRBSearchHeight; |
| |
| |
| /*DDK 243 removed this block of code.*/ |
| /*if((ctx->eCodec==IMG_CODEC_H263_NO_RC)||(ctx->eCodec==IMG_CODEC_H263_CBR)||(ctx->eCodec==IMG_CODEC_H263_VBR)) |
| ui16tmp = CurrentRowY; |
| else*/ |
| ui16tmp = (CurrentRowY != SliceStartRowY); |
| |
| for (iPos = 0; iPos < ctx->Width; iPos += 16, psCurrent++) { |
| memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS)); |
| psCurrent->MVValid = 0; |
| psCurrent->ParamsValid = 0; |
| |
| if (SliceStartRowY) { |
| psCurrent->MVValid = VECTORS_ABOVE_VALID; |
| } |
| /* Setup the parameters and motion vectors*/ |
| if (ui16tmp) { |
| psCurrent->MVValid = VECTORS_ABOVE_VALID | DO_INTRA_PRED; |
| psCurrent->ParamsValid |= PARAMS_ABOVE_VALID; |
| |
| if (iPos + 16 < ctx->Width) { |
| psCurrent->ParamsValid |= PARAMS_ABOVER_VALID; |
| psCurrent->MVValid |= /*VECTORS_LEFT_VALID; //*/(1 << 2); /* Vectors left valid define looks wrong*/ |
| } |
| |
| if (iPos > 0 && (iPos < ctx->Width)) { |
| psCurrent->ParamsValid |= PARAMS_ABOVEL_VALID; |
| psCurrent->MVValid |= VECTORS_ABOVE_LEFT_VALID; //(1<<0) |
| } |
| } else { |
| // are we the first MB in a new slice? |
| if (iPos == 0) { |
| if ((ctx->eCodec == IMG_CODEC_H263_NO_RC) || (ctx->eCodec == IMG_CODEC_H263_CBR) || (ctx->eCodec == IMG_CODEC_H263_VBR)) { |
| if (iYPos == -ui16SearchTopOffset) |
| psCurrent->ParamsValid |= MB_START_OF_SLICE;// OPTI? |
| } else { |
| psCurrent->ParamsValid |= MB_START_OF_SLICE;// OPTI? |
| } |
| } |
| } |
| /*DDK 243 removed this block of code.*/ |
| /*if((ctx->eCodec==IMG_CODEC_H263_NO_RC) || (ctx->eCodec==IMG_CODEC_H263_CBR)||(ctx->eCodec==IMG_CODEC_H263_VBR)) |
| { |
| // clear the above params valid bits |
| psCurrent->ParamsValid &=~(PARAMS_ABOVEL_VALID|PARAMS_ABOVER_VALID|PARAMS_ABOVE_VALID); // OPTI |
| }*/ |
| // Have to fill in the right hand row of 4x4 vectors into the the left block |
| if (iPos) { |
| psCurrent->MVValid |= DO_INTRA_PRED | (1 << 3); /*MV_VALID define looks wrong?! so use hard coded value for now*/ |
| psCurrent->ParamsValid |= 8; //(1<<3) |
| } |
| if (iPos == 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 (iYPos == (SliceStartRowY + SliceHeight - (ui16SearchTopOffset + 16))) { |
| psCurrent->ParamsValid |= MB_END_OF_SLICE; |
| if (iYPos == 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 (iYPos < ctx->HeightMinus16MinusLRBTopOffset) { |
| psCurrent->MVValid |= VECTORS_BELOW_VALID; //(1<<4) |
| |
| if (iYPos < ctx->HeightMinus32MinusLRBTopOffset) { |
| psCurrent->MVValid |= VECTORS_2BELOW_VALID; //(1<<5) |
| } |
| } |
| } |
| |
| /*Set up IPEMin and Max for coordinate X in the search reference region*/ |
| /*And set up flags in SPEMax when needed*/ |
| if (iPos <= ui16SearchLeftOffset) { |
| psCurrent->IPEMin[0] = ui16CurBlockX - iPos; |
| psCurrent->RealEdge |= SPE_EDGE_LEFT; |
| } else { |
| psCurrent->IPEMin[0] = ui16CurBlockX / 16; |
| } |
| |
| if ((iPos + ui16SearchLeftOffset + 16) > ctx->Width) { |
| psCurrent->IPEMax[0] = (ui16CurBlockX - 1 + ctx->Width) - iPos; //(112 - 1) - ((iPos + 48+16) - ctx->psVideo->ui16Width); |
| psCurrent->RealEdge |= SPE_EDGE_RIGHT; |
| } else { |
| psCurrent->IPEMax[0] = (ui16CurBlockX + 16 + ui16SearchLeftOffset) - 1 - 3; //(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 (iYPos <= 0) { |
| psCurrent->IPEMin[1] = 0; |
| psCurrent->RealEdge |= SPE_EDGE_TOP; |
| } else { |
| psCurrent->IPEMin[1] = 3; |
| } |
| |
| //Max Y |
| if (iYPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) { |
| psCurrent->IPEMax[1] = ui16SearchHeight - 1; |
| psCurrent->RealEdge |= ui16SearchHeight - 4; |
| } else { |
| psCurrent->IPEMax[1] = ui16SearchHeight - 4; |
| } |
| |
| psCurrent->CurBlockAddr = ((ui16CurBlockX) / 16); |
| psCurrent->CurBlockAddr |= ((IMG_UINT8)(((iYPos + ui16SearchTopOffset) - srcY) / 16) << 4); |
| |
| /* 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: |
| pnw__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: |
| pnw__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: |
| pnw__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; |
| } |
| } |
| |
| // now setup the dummy end of frame macroblock. |
| if ((CurrentRowY + 16) >= ctx->Height) { |
| memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS)); |
| psCurrent->MVValid = DO_INTRA_PRED; |
| psCurrent->ParamsValid = 0; |
| psCurrent->RealEdge = 0; |
| } |
| } |
| |
| void pnw_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) { |
| pnw__setup_slice_row_params( |
| ctx, |
| IsIntra, |
| CurrentRowY, |
| YSliceStartPos, |
| SliceHeight, |
| VectorsValid, bySliceQP); |
| |
| CurrentRowY += 16; |
| Rows--; |
| } |
| |
| } |
| |
| |
| |
| IMG_UINT32 pnw__send_encode_slice_params( |
| context_ENC_p ctx, |
| IMG_BOOL IsIntra, |
| IMG_UINT16 CurrentRow, |
| IMG_UINT8 DeblockIDC, |
| IMG_UINT32 FrameNum, |
| IMG_UINT16 SliceHeight, |
| IMG_UINT16 CurrentSlice) |
| { |
| SLICE_PARAMS *psSliceParams; |
| IMG_INT16 RowOffset; |
| IMG_UINT16 SearchHeight, SearchTopOffset; |
| |
| psb_buffer_p psCoded; |
| object_surface_p ref_surface; |
| psb_buffer_p psRef; |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Send encode slice parmas, Is Intra:%d, CurrentRow:%d" \ |
| "DeblockIDC:%d, FrameNum:%d, SliceHeight:%d, CurrentSlice:%d\n", |
| IsIntra, CurrentRow, DeblockIDC, FrameNum, SliceHeight, CurrentSlice); |
| |
| 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; |
| psSliceParams->ScanningIntraParams = (1 << SCANNING_INTRA_WIDTH_SHIFT) | |
| (1 << SCANNING_INTRA_STEP_SHIFT); |
| |
| /* We want multiple ones of these so we can submit multiple slices without having to wait for the next */ |
| psSliceParams->Flags = 0; |
| psSliceParams->HostCtx = 0xdafed123; |
| |
| #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->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; |
| #endif |
| psSliceParams->NumAirMBs = ctx->num_air_mbs; |
| psSliceParams->AirThreshold = ctx->air_threshold; |
| |
| if (ctx->eCodec == IMG_CODEC_H264_VCM && ctx->max_slice_size == 0) |
| psSliceParams->MaxSliceSize = ctx->Width * ctx->Height * 12 / 2; |
| else |
| psSliceParams->MaxSliceSize = ctx->max_slice_size; |
| psSliceParams->FCode = ctx->FCode;/* Not clear yet, This field is not appare in firmware doc */ |
| |
| SearchHeight = min(MVEA_LRB_SEARCH_HEIGHT, ctx->Height); |
| SearchTopOffset = (((SearchHeight / 2) / 16) * 16); |
| |
| RowOffset = CurrentRow - SearchTopOffset; |
| if (RowOffset <= 0) |
| RowOffset = 0; |
| if (RowOffset > (ctx->Height - SearchHeight)) |
| RowOffset = (ctx->Height - SearchHeight); |
| if (!IsIntra) { |
| psSliceParams->Flags |= ISINTER_FLAGS; |
| } |
| |
| switch (DeblockIDC) { |
| case 0: |
| psSliceParams->Flags |= DEBLOCK_FRAME; |
| break; |
| case 2: |
| psSliceParams->Flags |= DEBLOCK_SLICE; |
| break; |
| case 1: |
| default: |
| // do nothing |
| break; |
| } |
| |
| 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_CBR: |
| case IMG_CODEC_H264_VCM: |
| case IMG_CODEC_H264_VBR: |
| psSliceParams->Flags |= ISH264_FLAGS; |
| break; |
| default: |
| psSliceParams->Flags |= ISH264_FLAGS; |
| printf("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) /* FIXME contrary with old DDK, take notice */ |
| psSliceParams->Flags |= INTERLEAVE_TARGET; |
| |
| cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| |
| RELOC_SLICE_PARAMS_PNW(&(psSliceParams->RefYBase), 256 * RowOffset / 16, psRef); |
| RELOC_SLICE_PARAMS_PNW(&(psSliceParams->RefUVBase), |
| ref_surface->psb_surface->stride * ref_surface->height + (RowOffset * 128 / 16), |
| psRef); |
| if (IsIntra) |
| RELOC_SLICE_PARAMS_PNW(&(psSliceParams->InParamsBase), |
| ctx->in_params_ofs, |
| //((CurrentRow * (ctx->Width)) / 256 + ctx->obj_context->slice_count) * sizeof(MTX_CURRENT_IN_PARAMS), |
| cmdbuf->topaz_in_params_I); |
| else |
| RELOC_SLICE_PARAMS_PNW(&(psSliceParams->InParamsBase), |
| ctx->in_params_ofs, |
| //((CurrentRow * (ctx->Width)) / 256 + ctx->obj_context->slice_count) * sizeof(MTX_CURRENT_IN_PARAMS), |
| cmdbuf->topaz_in_params_P); |
| |
| #if TOPAZ_PIC_PARAMS_VERBOSE |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof psSliceParams %d\n", sizeof(*psSliceParams)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof MTX_CURRENT_IN_PARAMS %d\n", sizeof(MTX_CURRENT_IN_PARAMS)); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->SliceStartRowNum %d\n", psSliceParams->SliceStartRowNum); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->SliceHeight %d\n", psSliceParams->SliceHeight); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYBase %x\n", psSliceParams->RefYBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVBase %x\n", psSliceParams->RefUVBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYStride %d\n", psSliceParams->RefYStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVStride %d\n", psSliceParams->RefUVStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefYRowStride %d\n", psSliceParams->RefYRowStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->RefUVRowStride %d\n", psSliceParams->RefUVRowStride); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->HostCtx %x\n", psSliceParams->HostCtx); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->Flags %x\n", psSliceParams->Flags); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->MaxSliceSize %d\n", psSliceParams->MaxSliceSize); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->FCode %x\n", psSliceParams->FCode); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->InParamsBase %x\n", psSliceParams->InParamsBase); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->NumAirMBs %d\n", psSliceParams->NumAirMBs); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->AirThreshold %x\n", psSliceParams->AirThreshold); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "psSliceParams->ScanningIntraParams %x\n", psSliceParams->ScanningIntraParams); |
| #endif |
| |
| pnw_cmdbuf_insert_command_package(ctx->obj_context, |
| ctx->SliceToCore, |
| MTX_CMDID_ENCODE_SLICE, |
| &cmdbuf->slice_params, |
| CurrentSlice *((sizeof(SLICE_PARAMS) + 15) & 0xfff0)); |
| |
| |
| return 0; |
| } |
| |
| |
| |
| /* |
| * Function Name : Reset_EncoderParams |
| * Description : Reset Above & Below Params at the Start of Intra frame |
| */ |
| void pnw_reset_encoder_params(context_ENC_p ctx) |
| { |
| unsigned char *Add_Below, *Add_Above; |
| pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf; |
| |
| /* all frames share the same Topaz param, in_param/aboveparam/bellow |
| * map it only when necessary |
| */ |
| if (cmdbuf->topaz_above_params_p == NULL) { |
| VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_above_params, &cmdbuf->topaz_above_params_p); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n"); |
| return; |
| } |
| } |
| |
| if (cmdbuf->topaz_below_params_p == NULL) { |
| VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_below_params, &cmdbuf->topaz_below_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_below_params_p + |
| ctx->below_params_ofs; |
| |
| memset(Add_Below, 0, ctx->below_params_size * 4); |
| |
| Add_Above = cmdbuf->topaz_above_params_p + ctx->above_params_ofs; |
| memset(Add_Above, 0, ctx->above_params_size * MAX_TOPAZ_CORES); |
| } |
| |
| |
| |