| /* |
| * Copyright (c) 2011 Intel Corporation. All Rights Reserved. |
| * Copyright (c) Imagination Technologies Limited, UK |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: |
| * Elaine Wang <elaine.wang@intel.com> |
| * Zeng Li <zeng.li@intel.com> |
| * Edward Lin <edward.lin@intel.com> |
| * |
| */ |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <limits.h> |
| |
| #include "hwdefs/coreflags.h" |
| #include "hwdefs/topaz_vlc_regs.h" |
| #include "hwdefs/topaz_db_regs.h" |
| |
| #include "va/va_enc_h264.h" |
| |
| #include "psb_def.h" |
| #include "psb_drv_debug.h" |
| #include "psb_surface.h" |
| #include "tng_cmdbuf.h" |
| #include "tng_hostcode.h" |
| #include "tng_hostheader.h" |
| #include "tng_picmgmt.h" |
| #include "tng_slotorder.h" |
| #include "tng_hostair.h" |
| #include "tng_H264ES.h" |
| #ifdef _TOPAZHP_PDUMP_ |
| #include "tng_trace.h" |
| #endif |
| |
| #define TOPAZ_H264_MAX_BITRATE 135000000 |
| |
| #define INIT_CONTEXT_H264ES context_ENC_p ctx = (context_ENC_p) obj_context->format_data |
| #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id )) |
| #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id )) |
| |
| static VAStatus tng__H264ES_init_profile( |
| object_context_p obj_context, |
| object_config_p obj_config) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_p ctx; |
| ctx = (context_ENC_p) obj_context->format_data; |
| switch (obj_config->profile) { |
| case VAProfileH264Baseline: |
| case VAProfileH264ConstrainedBaseline: |
| ctx->ui8ProfileIdc = H264ES_PROFILE_BASELINE; |
| break; |
| case VAProfileH264Main: |
| ctx->ui8ProfileIdc = H264ES_PROFILE_MAIN; |
| break; |
| case VAProfileH264High: |
| ctx->ui8ProfileIdc = H264ES_PROFILE_HIGH; |
| break; |
| case VAProfileH264StereoHigh: |
| ctx->ui8ProfileIdc = H264ES_PROFILE_HIGH; |
| ctx->bEnableMVC = 1; |
| ctx->ui16MVCViewIdx = 0; |
| break; |
| default: |
| ctx->ui8ProfileIdc = H264ES_PROFILE_BASELINE; |
| vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; |
| break; |
| } |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: obj_config->profile = %dctx->eStandard = %d, ctx->bEnableMVC = %d\n", |
| __FUNCTION__, obj_config->profile, ctx->eStandard, ctx->bEnableMVC); |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_get_codec_type( |
| object_context_p obj_context, |
| object_config_p __maybe_unused obj_config) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| |
| ctx->eCodec = IMG_CODEC_NUM; |
| |
| if (ctx->bEnableMVC) { |
| switch (psRCParams->eRCMode) { |
| case IMG_RCMODE_NONE: |
| ctx->eCodec = IMG_CODEC_H264MVC_NO_RC; |
| break; |
| case IMG_RCMODE_CBR: |
| ctx->eCodec = IMG_CODEC_H264MVC_CBR; |
| break; |
| case IMG_RCMODE_VBR: |
| ctx->eCodec = IMG_CODEC_H264MVC_VBR; |
| break; |
| default: |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "RC mode MVC\n"); |
| break; |
| } |
| } else { |
| switch (psRCParams->eRCMode) { |
| case IMG_RCMODE_NONE: |
| ctx->eCodec = IMG_CODEC_H264_NO_RC; |
| break; |
| case IMG_RCMODE_CBR: |
| ctx->eCodec = IMG_CODEC_H264_CBR; |
| break; |
| case IMG_RCMODE_VBR: |
| ctx->eCodec = IMG_CODEC_H264_VBR; |
| break; |
| case IMG_RCMODE_VCM: |
| ctx->eCodec = IMG_CODEC_H264_VCM; |
| break; |
| default: |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "RC mode\n"); |
| break; |
| } |
| } |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_init_format_mode( |
| object_context_p obj_context, |
| object_config_p __maybe_unused obj_config) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| |
| ctx->bIsInterlaced = IMG_FALSE; |
| ctx->bIsInterleaved = IMG_FALSE; |
| ctx->ui16PictureHeight = ctx->ui16FrameHeight; |
| ctx->eCodec = IMG_CODEC_H264_NO_RC; |
| return vaStatus; |
| } |
| |
| static void tng__H264ES_init_context(object_context_p obj_context, |
| object_config_p __maybe_unused obj_config) |
| { |
| context_ENC_p ctx = (context_ENC_p) obj_context->format_data; |
| //This parameter need not be exposed |
| ctx->ui8InterIntraIndex = 3; |
| ctx->ui8CodedSkippedIndex = 3; |
| ctx->bEnableHostQP = IMG_FALSE; |
| ctx->uMaxChunks = 0xA0; |
| ctx->uChunksPerMb = 0x40; |
| ctx->uPriorityChunks = (0xA0 - 0x60); |
| ctx->ui32FCode = 4; |
| ctx->iFineYSearchSize = 2; |
| |
| //This parameter need not be exposed |
| //host to control the encoding process |
| ctx->bEnableInpCtrl = IMG_FALSE; |
| ctx->bEnableHostBias = IMG_FALSE; |
| //By default false Newly Added |
| ctx->bEnableCumulativeBiases = IMG_FALSE; |
| |
| //Weighted Prediction is not supported in TopazHP Version 3.0 |
| ctx->bWeightedPrediction = IMG_FALSE; |
| ctx->ui8VPWeightedImplicitBiPred = 0; |
| ctx->bInsertHRDParams = IMG_FALSE; |
| ctx->bArbitrarySO = IMG_FALSE; |
| ctx->ui32BasicUnit = 0; |
| ctx->idr_force_flag = 0; |
| ctx->bVPAdaptiveRoundingDisable = IMG_FALSE; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_framerate_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| VAEncMiscParameterFrameRate *psMiscFrameRateParam; |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeFrameRate); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterFrameRate)); |
| |
| psMiscFrameRateParam = (VAEncMiscParameterFrameRate *)(pBuffer->data); |
| |
| if (psMiscFrameRateParam == NULL) |
| return VA_STATUS_ERROR_INVALID_BUFFER; |
| |
| if (psMiscFrameRateParam->framerate < 1 || psMiscFrameRateParam->framerate > 65535) |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| |
| |
| if (psRCParams->ui32FrameRate == 0) |
| psRCParams->ui32FrameRate = psMiscFrameRateParam->framerate; |
| else { |
| if(psMiscFrameRateParam->framerate != psRCParams->ui32FrameRate){ |
| if (psMiscFrameRateParam->framerate > psRCParams->ui32FrameRate) |
| psRCParams->ui32BitsPerSecond /= (float)psMiscFrameRateParam->framerate / psRCParams->ui32FrameRate; |
| else |
| psRCParams->ui32BitsPerSecond *= (float)psRCParams->ui32FrameRate / psMiscFrameRateParam->framerate; |
| psRCParams->ui32FrameRate = psMiscFrameRateParam->framerate; |
| ctx->rc_update_flag |= RC_MASK_frame_rate; |
| } |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_ratecontrol_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| IMG_INT32 ui32BitsPerFrame; |
| VAEncMiscParameterRateControl *psMiscRcParams; |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| unsigned int max_bps; |
| |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeRateControl); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterRateControl)); |
| psMiscRcParams = (VAEncMiscParameterRateControl *)pBuffer->data; |
| |
| #ifdef _TOPAZHP_PDUMP_ |
| tng_H264ES_trace_misc_rc_params(psMiscRcParams); |
| #endif |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s psRCParams->ui32BitsPerSecond = %d, psMiscRcParams->bits_per_second = %d \n", |
| __FUNCTION__, psRCParams->ui32BitsPerSecond, psMiscRcParams->bits_per_second); |
| |
| if (psMiscRcParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: bits_per_second(%d) exceeds the maximum bitrate, set it with %d\n", |
| __FUNCTION__, psMiscRcParams->bits_per_second, TOPAZ_H264_MAX_BITRATE); |
| psMiscRcParams->bits_per_second = TOPAZ_H264_MAX_BITRATE; |
| } |
| |
| if ((psRCParams->ui32BitsPerSecond != psMiscRcParams->bits_per_second) && |
| psMiscRcParams->bits_per_second != 0) { |
| psRCParams->ui32BitsPerSecond = psMiscRcParams->bits_per_second; |
| ctx->rc_update_flag |= RC_MASK_bits_per_second; |
| } |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: rate control changed from %d to %d\n", __FUNCTION__, |
| psRCParams->ui32BitsPerSecond, psMiscRcParams->bits_per_second); |
| |
| if (psMiscRcParams->rc_flags.value != 0) { |
| if (psMiscRcParams->rc_flags.bits.disable_bit_stuffing) |
| ctx->sRCParams.bDisableBitStuffing = IMG_TRUE; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "bDisableBitStuffing is %d\n", |
| ctx->sRCParams.bDisableBitStuffing); |
| } |
| |
| if (psMiscRcParams->window_size > 2000) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "window_size is too much!\n"); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (psMiscRcParams->window_size != 0) |
| ctx->uiCbrBufferTenths = psMiscRcParams->window_size / 100; |
| |
| if (psRCParams->ui32FrameRate == 0) |
| psRCParams->ui32FrameRate = 30; |
| |
| /* According to Table A-1 Level limits, if resolution is bigger than 625SD, |
| min compression ratio is 4, otherwise min compression ratio is 2 */ |
| if (psRCParams->ui32BitsPerSecond == 0) { |
| max_bps = (ctx->obj_context->picture_width * ctx->obj_context->picture_height * 3 / 2 ) * 8 * psRCParams->ui32FrameRate; |
| if (ctx->ui16SourceWidth > 720) |
| max_bps /= 4; |
| else |
| max_bps /= 2; |
| psRCParams->ui32BitsPerSecond = max_bps; |
| } |
| |
| if (ctx->uiCbrBufferTenths) { |
| psRCParams->ui32BufferSize = (IMG_UINT32)(psRCParams->ui32BitsPerSecond * ctx->uiCbrBufferTenths / 10.0); |
| } else { |
| if (psRCParams->ui32BitsPerSecond < 256000) |
| psRCParams->ui32BufferSize = ((9 * psRCParams->ui32BitsPerSecond) >> 1); |
| else |
| psRCParams->ui32BufferSize = ((5 * psRCParams->ui32BitsPerSecond) >> 1); |
| } |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s ctx->uiCbrBufferTenths = %d, psRCParams->ui32BufferSize = %d\n", |
| __FUNCTION__, ctx->uiCbrBufferTenths, psRCParams->ui32BufferSize); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s psRCParams->ui32BitsPerSecond = %d, psMiscRcParams->bits_per_second = %d\n", |
| __FUNCTION__, psRCParams->ui32BitsPerSecond, psMiscRcParams->bits_per_second); |
| |
| //psRCParams->ui32BUSize = psMiscRcParams->basic_unit_size; |
| psRCParams->i32InitialDelay = (13 * psRCParams->ui32BufferSize) >> 4; |
| psRCParams->i32InitialLevel = (3 * psRCParams->ui32BufferSize) >> 4; |
| |
| ui32BitsPerFrame = psRCParams->ui32BitsPerSecond / psRCParams->ui32FrameRate; |
| /* in order to minimise mismatches between firmware and external world InitialLevel should be a multiple of ui32BitsPerFrame */ |
| psRCParams->i32InitialLevel = ((psRCParams->i32InitialLevel + ui32BitsPerFrame / 2) / ui32BitsPerFrame) * ui32BitsPerFrame; |
| psRCParams->i32InitialLevel = tng__max(psRCParams->i32InitialLevel, ui32BitsPerFrame); |
| psRCParams->i32InitialDelay = psRCParams->ui32BufferSize - psRCParams->i32InitialLevel; |
| |
| //free(psMiscRcParams); |
| if (psMiscRcParams->initial_qp > 51 || |
| psMiscRcParams->min_qp > 51 || |
| psMiscRcParams->max_qp > 51) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: Initial_qp(%d) min_qp(%d) max_qp(%d) invalid.\nQP shouldn't be larger than 51 for H264\n", |
| __FUNCTION__, psMiscRcParams->initial_qp, psMiscRcParams->min_qp, psMiscRcParams->max_qp); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| if ((psRCParams->ui32InitialQp != psMiscRcParams->initial_qp) && |
| (psMiscRcParams->initial_qp != 0)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: initial_qp updated from %d to %d\n", |
| __FUNCTION__, psRCParams->ui32InitialQp, psMiscRcParams->initial_qp); |
| ctx->rc_update_flag |= RC_MASK_initial_qp; |
| psRCParams->ui32InitialQp = psMiscRcParams->initial_qp; |
| } |
| |
| if ((psRCParams->iMinQP != psMiscRcParams->min_qp) && |
| (psMiscRcParams->min_qp != 0)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: min_qp updated from %d to %d\n", |
| __FUNCTION__, psRCParams->iMinQP, psMiscRcParams->min_qp); |
| ctx->rc_update_flag |= RC_MASK_min_qp; |
| psRCParams->iMinQP = psMiscRcParams->min_qp; |
| } |
| |
| if ((ctx->max_qp != psMiscRcParams->max_qp) && |
| (psMiscRcParams->max_qp != 0)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: max_qp updated from %d to %d\n", |
| __FUNCTION__, ctx->max_qp, psMiscRcParams->max_qp); |
| ctx->rc_update_flag |= RC_MASK_max_qp; |
| ctx->max_qp = psMiscRcParams->max_qp; |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_hrd_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| VAEncMiscParameterHRD *psMiscHrdParams = NULL; |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeHRD); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterHRD)); |
| psMiscHrdParams = (VAEncMiscParameterHRD *)pBuffer->data; |
| |
| if (psMiscHrdParams->buffer_size == 0 |
| || psMiscHrdParams->initial_buffer_fullness == 0) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Find zero value for buffer_size " |
| "and initial_buffer_fullness.\n"); |
| vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; |
| return vaStatus; |
| } |
| |
| if (ctx->initial_buffer_fullness > ctx->buffer_size) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "initial_buffer_fullnessi(%d) shouldn't be" |
| " larger that buffer_size(%d)!\n", |
| psMiscHrdParams->initial_buffer_fullness, |
| psMiscHrdParams->buffer_size); |
| vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; |
| return vaStatus; |
| } |
| |
| if (!psRCParams->bRCEnable) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Only when rate control is enabled," |
| " VAEncMiscParameterTypeHRD will take effect.\n"); |
| vaStatus = VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; |
| return vaStatus; |
| } |
| |
| ctx->buffer_size = psMiscHrdParams->buffer_size; |
| ctx->initial_buffer_fullness = psMiscHrdParams->initial_buffer_fullness; |
| ctx->bInsertHRDParams = IMG_TRUE; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "hrd param buffer_size set to %d " |
| "initial buffer fullness set to %d\n", |
| ctx->buffer_size, ctx->initial_buffer_fullness); |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| //APP_SetVideoParams |
| static VAStatus tng__H264ES_process_misc_air_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| VAEncMiscParameterAIR *psMiscAirParams = NULL; |
| ADAPTIVE_INTRA_REFRESH_INFO_TYPE *psAIRInfo = &(ctx->sAirInfo); |
| IMG_UINT32 ui32MbNum; |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeAIR); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterAIR)); |
| |
| psMiscAirParams = (VAEncMiscParameterAIR*)pBuffer->data; |
| ui32MbNum = (ctx->ui16PictureHeight * ctx->ui16Width) >> 8; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: enable_AIR = %d, mb_num = %d, thresh_hold = %d, air_auto = %d\n", __FUNCTION__, |
| ctx->bEnableAIR, psMiscAirParams->air_num_mbs, psMiscAirParams->air_threshold, psMiscAirParams->air_auto); |
| |
| ctx->bEnableAIR = 1; |
| ctx->bEnableInpCtrl = 1; |
| ctx->bEnableHostBias = 1; |
| ctx->ui8EnableSelStatsFlags |= ESF_FIRST_STAGE_STATS; |
| ctx->ui8EnableSelStatsFlags |= ESF_MP_BEST_MB_DECISION_STATS; |
| |
| /*FIXME |
| if (psMiscAirParams->air_threshold == -1 && psMiscAirParams->air_num_mbs == 0) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: ERROR: Cannot have both -AIRMBperFrame set to zero" |
| "AND and -AIRSADThreshold set to -1 (APP_SetVideoParams)\n", |
| __FUNCTION__); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| }*/ |
| |
| if (psMiscAirParams->air_num_mbs > 65535) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: ERROR: air_num_mbs = %d should not bigger than 65536\n", |
| __FUNCTION__, psMiscAirParams->air_num_mbs); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (psMiscAirParams->air_num_mbs > ui32MbNum) |
| psMiscAirParams->air_num_mbs = ui32MbNum; |
| |
| if (psMiscAirParams->air_threshold > 65535) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: ERROR: air_threshold = %d should not bigger than 65536\n", |
| __FUNCTION__, psMiscAirParams->air_threshold); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (psMiscAirParams->air_auto) { |
| psAIRInfo->i32NumAIRSPerFrame = -1; |
| psAIRInfo->i32SAD_Threshold = -1; |
| psAIRInfo->i16AIRSkipCnt = -1; |
| } else { |
| psAIRInfo->i32NumAIRSPerFrame = psMiscAirParams->air_num_mbs; |
| psAIRInfo->i32SAD_Threshold = psMiscAirParams->air_threshold; |
| psAIRInfo->i16AIRSkipCnt = -1; |
| } |
| |
| psAIRInfo->ui16AIRScanPos = 0; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: air slice size changed to num_air_mbs %d " |
| "air_threshold %d, air_auto %d\n", __FUNCTION__, |
| psMiscAirParams->air_num_mbs, psMiscAirParams->air_threshold, |
| psMiscAirParams->air_auto); |
| |
| if (psAIRInfo->pi8AIR_Table != NULL) |
| free(psAIRInfo->pi8AIR_Table); |
| tng_air_buf_create(ctx); |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_cir_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *)obj_buffer->buffer_data; |
| VAEncMiscParameterCIR *psMiscCirParams = NULL; |
| |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeCIR); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterCIR)); |
| |
| psMiscCirParams = (VAEncMiscParameterCIR*)pBuffer->data; |
| |
| if (psMiscCirParams->cir_num_mbs > 0) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "CIR enabled with MB count %d\n", ctx->ui16IntraRefresh); |
| ctx->ui16IntraRefresh = psMiscCirParams->cir_num_mbs; |
| ctx->bEnableCIR = 1; |
| ctx->bEnableInpCtrl = 1; |
| ctx->bEnableHostBias = 1; |
| } else { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: ERROR: invalid cir num mbs(%d), should bigger than 0\n", |
| __FUNCTION__, ctx->ui16IntraRefresh); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static IMG_UINT8 tng__H264ES_calculate_level(context_ENC_p ctx) |
| { |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| IMG_UINT32 ui32MBf=0; |
| IMG_UINT32 ui32MBs; |
| IMG_UINT32 ui32Level=0; |
| IMG_UINT32 ui32TempLevel=0; |
| IMG_UINT32 ui32DpbMbs; |
| // We need to calculate the level based on a few constraints these are |
| // Macroblocks per second |
| // picture size |
| // decoded picture buffer size, and bitrate |
| ui32MBf = (ctx->ui16Width)*(ctx->ui16FrameHeight) >> 8; |
| ui32MBs = ui32MBf * psRCParams->ui32FrameRate; |
| |
| |
| // could do these in nice tables, but this is clearer |
| if (ui32MBf > 22080) ui32Level = SH_LEVEL_51; |
| else if (ui32MBf > 8704) ui32Level = SH_LEVEL_50; |
| else if (ui32MBf > 8192) ui32Level = SH_LEVEL_42; |
| else if (ui32MBf > 5120) ui32Level = SH_LEVEL_40; |
| else if (ui32MBf > 3600) ui32Level = SH_LEVEL_32; |
| else if (ui32MBf > 1620) ui32Level = SH_LEVEL_31; |
| else if (ui32MBf > 792) ui32Level = SH_LEVEL_22; |
| else if (ui32MBf > 396) ui32Level = SH_LEVEL_21; |
| else if (ui32MBf > 99) ui32Level = SH_LEVEL_11; |
| else ui32Level = SH_LEVEL_10; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: ui32MBf = %d, ui32MBs = %d, ui32Level = %d\n", |
| __FUNCTION__, ui32MBf, ui32MBs, ui32Level); |
| |
| //ui32DpbMbs = ui32MBf * (psContext->ui32MaxNumRefFrames + 1); |
| ui32DpbMbs = ui32MBf * (ctx->ui8MaxNumRefFrames + 1); |
| |
| if (ui32DpbMbs > 110400) ui32TempLevel = SH_LEVEL_51; |
| else if (ui32DpbMbs > 34816) ui32TempLevel = SH_LEVEL_50; |
| else if (ui32DpbMbs > 32768) ui32TempLevel = SH_LEVEL_42; |
| else if (ui32DpbMbs > 20480) ui32TempLevel = SH_LEVEL_40; |
| else if (ui32DpbMbs > 18000) ui32TempLevel = SH_LEVEL_32; |
| else if (ui32DpbMbs > 8100) ui32TempLevel = SH_LEVEL_31; |
| else if (ui32DpbMbs > 4752) ui32TempLevel = SH_LEVEL_22; |
| else if (ui32DpbMbs > 2376) ui32TempLevel = SH_LEVEL_21; |
| else if (ui32DpbMbs > 900) ui32TempLevel = SH_LEVEL_12; |
| else if (ui32DpbMbs > 396) ui32TempLevel = SH_LEVEL_11; |
| else ui32TempLevel = SH_LEVEL_10; |
| ui32Level = tng__max(ui32Level, ui32TempLevel); |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: ui32DpbMbs = %d, ui32Level = %d\n", |
| __FUNCTION__, ui32DpbMbs, ui32Level); |
| |
| // now restrict based on the number of macroblocks per second |
| if (ui32MBs > 589824) ui32TempLevel = SH_LEVEL_51; |
| else if (ui32MBs > 522240) ui32TempLevel = SH_LEVEL_50; |
| else if (ui32MBs > 245760) ui32TempLevel = SH_LEVEL_42; |
| else if (ui32MBs > 216000) ui32TempLevel = SH_LEVEL_40; |
| else if (ui32MBs > 108000) ui32TempLevel = SH_LEVEL_32; |
| else if (ui32MBs > 40500) ui32TempLevel = SH_LEVEL_31; |
| else if (ui32MBs > 20250) ui32TempLevel = SH_LEVEL_30; |
| else if (ui32MBs > 19800) ui32TempLevel = SH_LEVEL_22; |
| else if (ui32MBs > 11880) ui32TempLevel = SH_LEVEL_21; |
| else if (ui32MBs > 6000) ui32TempLevel = SH_LEVEL_13; |
| else if (ui32MBs > 3000) ui32TempLevel = SH_LEVEL_12; |
| else if (ui32MBs > 1485) ui32TempLevel = SH_LEVEL_11; |
| else ui32TempLevel = SH_LEVEL_10; |
| ui32Level = tng__max(ui32Level, ui32TempLevel); |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: ui32TempLevel = %d, ui32Level = %d\n", |
| __FUNCTION__, ui32TempLevel, ui32Level); |
| |
| if (psRCParams->bRCEnable) { |
| // now restrict based on the requested bitrate |
| if (psRCParams->ui32FrameRate > 135000000) ui32TempLevel = SH_LEVEL_51; |
| else if (psRCParams->ui32FrameRate > 50000000) ui32TempLevel = SH_LEVEL_50; |
| else if (psRCParams->ui32FrameRate > 20000000) ui32TempLevel = SH_LEVEL_41; |
| else if (psRCParams->ui32FrameRate > 14000000) ui32TempLevel = SH_LEVEL_32; |
| else if (psRCParams->ui32FrameRate > 10000000) ui32TempLevel = SH_LEVEL_31; |
| else if (psRCParams->ui32FrameRate > 4000000) ui32TempLevel = SH_LEVEL_30; |
| else if (psRCParams->ui32FrameRate > 2000000) ui32TempLevel = SH_LEVEL_21; |
| else if (psRCParams->ui32FrameRate > 768000) ui32TempLevel = SH_LEVEL_20; |
| else if (psRCParams->ui32FrameRate > 384000) ui32TempLevel = SH_LEVEL_13; |
| else if (psRCParams->ui32FrameRate > 192000) ui32TempLevel = SH_LEVEL_12; |
| else if (psRCParams->ui32FrameRate > 128000) ui32TempLevel = SH_LEVEL_11; |
| else if (psRCParams->ui32FrameRate > 64000) ui32TempLevel = SH_LEVEL_1B; |
| else ui32TempLevel = SH_LEVEL_10; |
| |
| ui32Level = tng__max(ui32Level, ui32TempLevel); |
| } |
| /* |
| if (pParams->bLossless) { |
| ui32Level = tng__max(ui32Level, 320); |
| } |
| */ |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: target level is %d, input level is %d\n", |
| __FUNCTION__, ui32Level, ctx->ui8LevelIdc); |
| return (IMG_UINT8)ui32Level; |
| } |
| |
| static VAStatus tng__H264ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncSequenceParameterBufferH264 *psSeqParams; |
| H264_CROP_PARAMS* psCropParams = &(ctx->sCropParams); |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| FRAME_ORDER_INFO *psFrameInfo = &(ctx->sFrameOrderInfo); |
| H264_VUI_PARAMS *psVuiParams = &(ctx->sVuiParams); |
| IMG_UINT32 ui32MaxUnit32 = (IMG_UINT32)0x7ffa; |
| IMG_UINT32 ui32IPCount = 0; |
| IMG_UINT64 ui64Temp = 0; |
| |
| ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType); |
| ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH264)); |
| |
| if (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH264)) { |
| vaStatus = VA_STATUS_ERROR_UNKNOWN; |
| goto out1; |
| } |
| |
| ctx->obj_context->frame_count = 0; |
| psSeqParams = (VAEncSequenceParameterBufferH264 *) obj_buffer->buffer_data; |
| obj_buffer->buffer_data = NULL; |
| obj_buffer->size = 0; |
| |
| #ifdef _TOPAZHP_PDUMP_ |
| tng_H264ES_trace_seq_params(psSeqParams); |
| #endif |
| |
| ctx->ui8LevelIdc = psSeqParams->level_idc; |
| ctx->ui8MaxNumRefFrames = psSeqParams->max_num_ref_frames; |
| |
| ctx->ui32IdrPeriod = psSeqParams->intra_idr_period; |
| ctx->ui32IntraCnt = psSeqParams->intra_period; |
| ui32IPCount = (IMG_UINT32)(psSeqParams->ip_period); |
| |
| if ((ui32IPCount > 4) || (ui32IPCount == 0)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: ip_period %d, it should be in [1, 4]\n", |
| __FUNCTION__, psSeqParams->ip_period); |
| vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; |
| goto out1; |
| } |
| |
| if (ctx->ui32IntraCnt == 0) { |
| if (ui32IPCount == 1) |
| ctx->ui32IntraCnt = INT_MAX; |
| else |
| ctx->ui32IntraCnt = INT_MAX - (INT_MAX % ui32IPCount); |
| ctx->ui32IdrPeriod = 1; |
| } else if (ctx->ui32IntraCnt == 1) { |
| //only I frame or IDR frames; |
| ui32IPCount = 1; |
| if (ctx->ui32IdrPeriod == 0) |
| ctx->ui32IdrPeriod = INT_MAX; |
| } else { |
| if (ctx->ui32IdrPeriod == 0) { |
| ctx->ui32IdrPeriod = INT_MAX / ctx->ui32IntraCnt; |
| } else if (ctx->ui32IdrPeriod > 1) { |
| ui64Temp = (IMG_UINT64)(ctx->ui32IdrPeriod) * (IMG_UINT64)(ctx->ui32IntraCnt); |
| if (ui64Temp >= (IMG_UINT64)INT_MAX) { |
| ctx->ui32IdrPeriod = INT_MAX / ctx->ui32IntraCnt; |
| } |
| } |
| |
| if ((ctx->ui32IntraCnt % ui32IPCount) != 0) { |
| if (ctx->ui32IntraCnt > INT_MAX - ui32IPCount + (ctx->ui32IntraCnt % ui32IPCount)) |
| ctx->ui32IntraCnt = INT_MAX - ui32IPCount + (ctx->ui32IntraCnt % ui32IPCount); |
| else |
| ctx->ui32IntraCnt += ui32IPCount - (ctx->ui32IntraCnt % ui32IPCount); |
| } |
| } |
| |
| if (ctx->ui32FrameCount[ctx->ui32StreamID] > 0) { |
| ctx->idr_force_flag = 1; |
| if (ctx->ui32IntraCntSave != ctx->ui32IntraCnt) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: intra_period updated from %d to %d\n", |
| __FUNCTION__, ctx->ui32IntraCntSave, ctx->ui32IntraCnt); |
| ctx->rc_update_flag |= RC_MASK_intra_period; |
| } |
| } |
| |
| ctx->ui32IntraCntSave = ctx->ui32IntraCnt; |
| |
| ctx->ui8SlotsInUse = ui32IPCount + 1; //Bframes + 2 |
| |
| //bits per second |
| if (!psSeqParams->bits_per_second) { |
| psSeqParams->bits_per_second = ctx->ui16Width * ctx->ui16PictureHeight * 30 * 12; |
| } |
| |
| if (psSeqParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) { |
| psSeqParams->bits_per_second = TOPAZ_H264_MAX_BITRATE; |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: bits_per_second(%d) exceeds the maximum bitrate, set it with %d\n", |
| __FUNCTION__, psSeqParams->bits_per_second, |
| TOPAZ_H264_MAX_BITRATE); |
| } |
| |
| if (psRCParams->ui32BitsPerSecond == 0) |
| psRCParams->ui32BitsPerSecond = psSeqParams->bits_per_second; |
| |
| if (psSeqParams->bits_per_second != psRCParams->ui32BitsPerSecond) { |
| psRCParams->ui32BitsPerSecond = psSeqParams->bits_per_second; |
| ctx->rc_update_flag |= RC_MASK_bits_per_second; |
| } |
| |
| psRCParams->ui32IntraFreq = ctx->ui32IntraCnt; |
| psRCParams->ui32TransferBitsPerSecond = psRCParams->ui32BitsPerSecond; |
| psRCParams->ui16BFrames = ui32IPCount - 1; |
| |
| if (psRCParams->ui32FrameRate == 0) |
| psRCParams->ui32FrameRate = 30; |
| |
| //set the B frames |
| if (psRCParams->eRCMode == IMG_RCMODE_VCM) |
| psRCParams->ui16BFrames = 0; |
| |
| if ((psRCParams->ui16BFrames > 0) && (ctx->ui8ProfileIdc == H264ES_PROFILE_BASELINE)) { |
| ctx->ui8ProfileIdc = H264ES_PROFILE_MAIN; |
| } |
| |
| if (psFrameInfo->slot_consume_dpy_order != NULL) |
| free(psFrameInfo->slot_consume_dpy_order); |
| if (psFrameInfo->slot_consume_enc_order != NULL) |
| free(psFrameInfo->slot_consume_enc_order); |
| |
| if (psRCParams->ui16BFrames != 0) { |
| memset(psFrameInfo, 0, sizeof(FRAME_ORDER_INFO)); |
| psFrameInfo->slot_consume_dpy_order = (int *)malloc(ctx->ui8SlotsInUse * sizeof(int)); |
| psFrameInfo->slot_consume_enc_order = (int *)malloc(ctx->ui8SlotsInUse * sizeof(int)); |
| |
| if ((psFrameInfo->slot_consume_dpy_order == NULL) || |
| (psFrameInfo->slot_consume_enc_order == NULL)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: error malloc slot order array\n", __FUNCTION__); |
| } |
| } |
| |
| //set the crop parameters |
| psCropParams->bClip = psSeqParams->frame_cropping_flag; |
| psCropParams->ui16LeftCropOffset = psSeqParams->frame_crop_left_offset; |
| psCropParams->ui16RightCropOffset = psSeqParams->frame_crop_right_offset; |
| psCropParams->ui16TopCropOffset = psSeqParams->frame_crop_top_offset; |
| psCropParams->ui16BottomCropOffset = psSeqParams->frame_crop_bottom_offset; |
| |
| //set level idc parameter |
| ctx->ui32VertMVLimit = 255 ;//(63.75 in qpel increments) |
| ctx->bLimitNumVectors = IMG_FALSE; |
| |
| if (ctx->ui8LevelIdc == 111) |
| ctx->ui8LevelIdc = SH_LEVEL_1B; |
| |
| ctx->ui8LevelIdc = tng__H264ES_calculate_level(ctx); |
| |
| /*Setting VertMVLimit and LimitNumVectors only for H264*/ |
| if (ctx->ui8LevelIdc >= SH_LEVEL_30) |
| ctx->bLimitNumVectors = IMG_TRUE; |
| else |
| ctx->bLimitNumVectors = IMG_FALSE; |
| |
| if (ctx->ui8LevelIdc >= SH_LEVEL_31) |
| ctx->ui32VertMVLimit = 2047 ;//(511.75 in qpel increments) |
| else if (ctx->ui8LevelIdc >= SH_LEVEL_21) |
| ctx->ui32VertMVLimit = 1023 ;//(255.75 in qpel increments) |
| else if (ctx->ui8LevelIdc >= SH_LEVEL_11) |
| ctx->ui32VertMVLimit = 511 ;//(127.75 in qpel increments) |
| |
| //set VUI info |
| memset(psVuiParams, 0, sizeof(H264_VUI_PARAMS)); |
| if (psSeqParams->time_scale != 0 && psSeqParams->num_units_in_tick != 0 |
| && (psSeqParams->time_scale > psSeqParams->num_units_in_tick)) { |
| psVuiParams->Time_Scale = psSeqParams->time_scale; |
| psVuiParams->num_units_in_tick = psSeqParams->num_units_in_tick; |
| } |
| |
| out1: |
| free(obj_buffer->buffer_data); |
| obj_buffer->buffer_data = NULL; |
| obj_buffer->size = 0; |
| |
| return vaStatus; |
| } |
| |
| #if 0 |
| static VAStatus tng__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); |
| context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf[ctx->ui32StreamID]); |
| IMG_RC_PARAMS * psRCParams = &(ctx->sRCParams); |
| VAEncPictureParameterBufferH264 *psPicParams; |
| IMG_BOOL bDepViewPPS = IMG_FALSE; |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n",__FUNCTION__); |
| ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); |
| if (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); |
| return VA_STATUS_ERROR_UNKNOWN; |
| } |
| |
| /* Transfer ownership of VAEncPictureParameterBufferH264 data */ |
| psPicParams = (VAEncPictureParameterBufferH264 *) obj_buffer->buffer_data; |
| |
| obj_buffer->buffer_data = NULL; |
| obj_buffer->size = 0; |
| |
| ASSERT(ctx->ui16Width == psPicParams->picture_width); |
| ASSERT(ctx->ui16PictureHeight == psPicParams->picture_height); |
| |
| #ifdef _TOPAZHP_OLD_LIBVA_ |
| ps_buf->ref_surface = SURFACE(psPicParams->ReferenceFrames[0].picture_id); |
| ps_buf->coded_buf = BUFFER(psPicParams->coded_buf); |
| #else |
| { |
| IMG_INT32 i; |
| ps_buf->rec_surface = SURFACE(psPicParams->CurrPic.picture_id); |
| for (i = 0; i < 16; i++) |
| ps_buf->ref_surface[i] = SURFACE(psPicParams->ReferenceFrames[i].picture_id); |
| ps_buf->coded_buf = BUFFER(psPicParams->coded_buf); |
| } |
| #endif |
| |
| if (NULL == ps_buf->coded_buf) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); |
| free(psPicParams); |
| return VA_STATUS_ERROR_INVALID_BUFFER; |
| } |
| |
| if ((ctx->bEnableMvc) && (ctx->ui16MVCViewIdx != 0) && |
| (ctx->ui16MVCViewIdx != (IMG_UINT16)(NON_MVC_VIEW))) { |
| bDepViewPPS = IMG_TRUE; |
| } |
| |
| /************* init **************** |
| ctx->bCabacEnabled = psPicParams->pic_fields.bits.entropy_coding_mode_flag; |
| ctx->bH2648x8Transform = psPicParams->pic_fields.bits.transform_8x8_mode_flag; |
| ctx->bH264IntraConstrained = psPicParams->pic_fields.bits.constrained_intra_pred_flag; |
| ctx->bWeightedPrediction = psPicParams->pic_fields.bits.weighted_pred_flag; |
| ctx->ui8VPWeightedImplicitBiPred = psPicParams->pic_fields.bits.weighted_bipred_idc; |
| ctx->bCustomScaling = psPicParams->pic_fields.bits.pic_scaling_matrix_present_flag; |
| ************* set rc params *************/ |
| // ctx->sRCParams.ui32InitialQp = psPicParams->pic_init_qp; |
| // ctx->sRCParams.i8QCPOffset = psPicParams->chroma_qp_index_offset; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s psRCParams->ui32InitialQp = %d, psRCParams->iMinQP = %d\n", __FUNCTION__, psPicParams->pic_init_qp, psPicParams->chroma_qp_index_offset); |
| tng__H264ES_prepare_picture_header( |
| ps_mem->bufs_pic_template.virtual_addr, |
| 0, //IMG_BOOL bCabacEnabled, |
| ctx->bH2648x8Transform, //IMG_BOOL b_8x8transform, |
| 0, //IMG_BOOL bIntraConstrained, |
| 0, //IMG_INT8 i8CQPOffset, |
| 0, //IMG_BOOL bWeightedPrediction, |
| 0, //IMG_UINT8 ui8WeightedBiPred, |
| 0, //IMG_BOOL bMvcPPS, |
| 0, //IMG_BOOL bScalingMatrix, |
| 0 //IMG_BOOL bScalingLists |
| ); |
| free(psPicParams); |
| /* |
| if (psRCParams->ui16BFrames == 0) { |
| tng_send_codedbuf(ctx, (ctx->obj_context->frame_count&1)); |
| tng_send_source_frame(ctx, (ctx->obj_context->frame_count&1), ctx->obj_context->frame_count); |
| } else |
| tng__H264ES_provide_buffer_for_BFrames(ctx); |
| */ |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n",__FUNCTION__); |
| |
| return vaStatus; |
| } |
| #endif |
| |
| static VAStatus tng__H264ES_process_picture_param_base(context_ENC_p ctx, unsigned char *buf) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); |
| VAEncPictureParameterBufferH264 *psPicParams; |
| #ifndef _TNG_FRAMES_ |
| IMG_INT32 i; |
| #endif |
| psPicParams = (VAEncPictureParameterBufferH264 *) buf; |
| |
| #ifdef _TOPAZHP_PDUMP_ |
| tng_H264ES_trace_pic_params(psPicParams); |
| #endif |
| |
| #ifdef _TNG_FRAMES_ |
| ps_buf->rec_surface = SURFACE(psPicParams->CurrPic.picture_id); |
| ps_buf->ref_surface = SURFACE(psPicParams->ReferenceFrames[0].picture_id); |
| ps_buf->ref_surface1 = SURFACE(psPicParams->ReferenceFrames[1].picture_id); |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: psPicParams->coded_buf = 0x%08x, ps_buf->coded_buf = 0x%08x\n", |
| __FUNCTION__, psPicParams->coded_buf, ps_buf->coded_buf); |
| #else |
| { |
| ps_buf->rec_surface = SURFACE(psPicParams->CurrPic.picture_id); |
| for (i = 0; i < 4; i++) { |
| ps_buf->ref_surface[i] = SURFACE(psPicParams->ReferenceFrames[i].picture_id); |
| ps_buf->ref_surface[i]->is_ref_surface = 1; |
| } |
| } |
| #endif |
| |
| ps_buf->coded_buf = BUFFER(psPicParams->coded_buf); |
| |
| if (NULL == ps_buf->coded_buf) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); |
| free(psPicParams); |
| return VA_STATUS_ERROR_INVALID_BUFFER; |
| } |
| |
| ctx->bH2648x8Transform = psPicParams->pic_fields.bits.transform_8x8_mode_flag; |
| if ((ctx->bH2648x8Transform == 1) && (ctx->ui8ProfileIdc != H264ES_PROFILE_HIGH)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d only high profile could set bH2648x8Transform TRUE\n", |
| __FUNCTION__, __LINE__); |
| ctx->bH2648x8Transform = 0; |
| } |
| |
| ctx->bH264IntraConstrained = psPicParams->pic_fields.bits.constrained_intra_pred_flag; |
| if (ctx->bEnableMVC == 1) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d MVC could not set bH264IntraConstrained TRUE\n", |
| __FUNCTION__, __LINE__); |
| ctx->bH264IntraConstrained = 0; |
| } |
| |
| ctx->bCabacEnabled = psPicParams->pic_fields.bits.entropy_coding_mode_flag; |
| ctx->bWeightedPrediction = psPicParams->pic_fields.bits.weighted_pred_flag; |
| ctx->ui8VPWeightedImplicitBiPred = psPicParams->pic_fields.bits.weighted_bipred_idc; |
| |
| /************* init **************** |
| ctx->bCustomScaling = psPicParams->pic_fields.bits.pic_scaling_matrix_present_flag; |
| ************* set rc params *************/ |
| if (ctx->sRCParams.ui32InitialQp == 0) |
| ctx->sRCParams.ui32InitialQp = psPicParams->pic_init_qp; |
| |
| ctx->ui32LastPicture = psPicParams->last_picture; |
| |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_picture_param_mvc(context_ENC_p ctx, unsigned char *buf) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncPictureParameterBufferH264_MVC *psPicMvcParams; |
| |
| psPicMvcParams = (VAEncPictureParameterBufferH264_MVC *) buf; |
| ctx->ui16MVCViewIdx = ctx->ui32StreamID = psPicMvcParams->view_id; |
| //vaStatus = tng__H264ES_process_picture_param_base(ctx, (unsigned char*)&(psPicMvcParams->base_picture_param)); |
| |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| |
| ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); |
| |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: ctx->bEnableMVC = %d\n", __FUNCTION__, ctx->bEnableMVC); |
| |
| if (ctx->bEnableMVC) { |
| if (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264_MVC)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d Invalid picture parameter H264 mvc buffer handle\n", |
| __FUNCTION__, __LINE__); |
| return VA_STATUS_ERROR_UNKNOWN; |
| } |
| vaStatus = tng__H264ES_process_picture_param_mvc(ctx, obj_buffer->buffer_data); |
| } else { |
| if (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d Invalid picture parameter H264 buffer handle\n", |
| __FUNCTION__, __LINE__); |
| return VA_STATUS_ERROR_UNKNOWN; |
| } |
| vaStatus = tng__H264ES_process_picture_param_base(ctx, obj_buffer->buffer_data); |
| } |
| free(obj_buffer->buffer_data); |
| obj_buffer->buffer_data = NULL; |
| obj_buffer->size = 0; |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_slice_param_mrfld(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncSliceParameterBufferH264 *psSliceParamsH264; |
| unsigned int i; |
| unsigned int uiPreMBAddress = 0; |
| unsigned int uiCurMBAddress = 0; |
| unsigned int uiPreMBNumbers = 0; |
| unsigned int uiCurMBNumbers = 0; |
| unsigned int uiAllMBNumbers = 0; |
| unsigned char ucPreDeblockIdc = 0; |
| unsigned char ucCurDeblockIdc = 0; |
| |
| /* Transfer ownership of VAEncPictureParameterBufferH264 data */ |
| psSliceParamsH264 = (VAEncSliceParameterBufferH264*) obj_buffer->buffer_data; |
| |
| #ifdef _TOPAZHP_PDUMP_ |
| tng_H264ES_trace_slice_params(psSliceParamsH264); |
| #endif |
| |
| ucPreDeblockIdc = psSliceParamsH264->disable_deblocking_filter_idc; |
| |
| for (i = 0; i < obj_buffer->num_elements; i++) { |
| uiCurMBAddress = psSliceParamsH264->macroblock_address; |
| uiCurMBNumbers = psSliceParamsH264->num_macroblocks; |
| if (uiCurMBAddress != uiPreMBAddress + uiPreMBNumbers) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d Error Macroblock Address (%d), address (%d), number (%d)\n", |
| __FUNCTION__, __LINE__, i, psSliceParamsH264->macroblock_address, |
| psSliceParamsH264->num_macroblocks); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| uiPreMBNumbers = uiCurMBNumbers; |
| uiPreMBAddress = uiCurMBAddress; |
| uiAllMBNumbers += uiCurMBNumbers; |
| |
| ucCurDeblockIdc = psSliceParamsH264->disable_deblocking_filter_idc; |
| if (ucPreDeblockIdc != ucCurDeblockIdc) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d Error Macroblock Address (%d), deblock idc pre (%d), cur (%d)\n", |
| __FUNCTION__, __LINE__, i, ucPreDeblockIdc, ucCurDeblockIdc); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| psSliceParamsH264++; |
| } |
| |
| if (uiAllMBNumbers != (unsigned int)(((IMG_UINT16)(ctx->ui16Width) * (IMG_UINT16)(ctx->ui16PictureHeight)) >> 8)) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s L%d Error Macroblock all number (%d), (%d)\n", |
| __FUNCTION__, __LINE__, i, uiAllMBNumbers, |
| ((ctx->ui16Width * ctx->ui16PictureHeight) >> 8)); |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| //deblocking behaviour |
| ctx->bArbitrarySO = IMG_FALSE; |
| ctx->ui8DeblockIDC = ucCurDeblockIdc; |
| ctx->ui8SlicesPerPicture = obj_buffer->num_elements; |
| |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_slice_param_mdfld(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncSliceParameterBuffer *psSliceParams = NULL; |
| psSliceParams = (VAEncSliceParameterBuffer*) obj_buffer->buffer_data; |
| |
| //deblocking behaviour |
| ctx->bArbitrarySO = IMG_FALSE; |
| ctx->ui8DeblockIDC = psSliceParams->slice_flags.bits.disable_deblocking_filter_idc; |
| ctx->ui8SlicesPerPicture = obj_buffer->num_elements; |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_max_slice_size_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAEncMiscParameterBuffer *pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| VAEncMiscParameterMaxSliceSize *psMiscMaxSliceSizeParams = NULL; |
| IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams); |
| |
| ASSERT(obj_buffer->type == VAEncMiscParameterTypeMaxSliceSize); |
| ASSERT(obj_buffer->size == sizeof(VAEncMiscParameterMaxSliceSize)); |
| |
| psMiscMaxSliceSizeParams = (VAEncMiscParameterMaxSliceSize*)pBuffer->data; |
| |
| if (psMiscMaxSliceSizeParams->max_slice_size > 0) { |
| psRCParams->ui32SliceByteLimit = psMiscMaxSliceSizeParams->max_slice_size; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "Max slice size is %d\n", psRCParams->ui32SliceByteLimit); |
| } else { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, |
| "%s: ERROR: invalid max slice size(%d), should bigger than 0\n", |
| __FUNCTION__, psMiscMaxSliceSizeParams->max_slice_size); |
| psRCParams->ui32SliceByteLimit = 0; |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus tng__H264ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| ASSERT(obj_buffer->type == VAEncSliceParameterBufferType); |
| /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */ |
| |
| if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBufferH264 buffer\n"); |
| vaStatus = tng__H264ES_process_slice_param_mrfld(ctx, obj_buffer); |
| } else if (obj_buffer->size == sizeof(VAEncSliceParameterBuffer)) { |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBuffer buffer\n"); |
| vaStatus = tng__H264ES_process_slice_param_mdfld(ctx, obj_buffer); |
| } else { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "Buffer size(%d) is wrong. It should be %d or %d\n", |
| obj_buffer->size, sizeof(VAEncSliceParameterBuffer), |
| sizeof(VAEncSliceParameterBufferH264)); |
| vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| free(obj_buffer->buffer_data); |
| obj_buffer->size = 0; |
| obj_buffer->buffer_data = NULL; |
| return vaStatus; |
| } |
| |
| static VAStatus tng__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncMiscParameterBuffer *pBuffer; |
| |
| ASSERT(obj_buffer->type == VAEncMiscParameterBufferType); |
| ASSERT(ctx != NULL); |
| /* Transfer ownership of VAEncMiscParameterBuffer data */ |
| pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data; |
| obj_buffer->size = 0; |
| |
| switch (pBuffer->type) { |
| case VAEncMiscParameterTypeFrameRate: |
| vaStatus = tng__H264ES_process_misc_framerate_param(ctx, obj_buffer); |
| break; |
| case VAEncMiscParameterTypeRateControl: |
| vaStatus = tng__H264ES_process_misc_ratecontrol_param(ctx, obj_buffer); |
| break; |
| case VAEncMiscParameterTypeHRD: |
| vaStatus = tng__H264ES_process_misc_hrd_param(ctx, obj_buffer); |
| break; |
| case VAEncMiscParameterTypeAIR: |
| vaStatus = tng__H264ES_process_misc_air_param(ctx, obj_buffer); |
| break; |
| case VAEncMiscParameterTypeCIR: |
| vaStatus = tng__H264ES_process_misc_cir_param(ctx, obj_buffer); |
| break; |
| case VAEncMiscParameterTypeMaxSliceSize: |
| vaStatus = tng__H264ES_process_misc_max_slice_size_param(ctx, obj_buffer); |
| break; |
| default: |
| break; |
| } |
| free(obj_buffer->buffer_data); |
| obj_buffer->buffer_data = NULL; |
| |
| return vaStatus; |
| } |
| |
| static void tng_H264ES_QueryConfigAttributes( |
| VAProfile __maybe_unused profile, |
| VAEntrypoint __maybe_unused entrypoint, |
| VAConfigAttrib *attrib_list, |
| int num_attribs) |
| { |
| int i; |
| |
| /* RateControl attributes */ |
| for (i = 0; i < num_attribs; i++) { |
| switch (attrib_list[i].type) { |
| case VAConfigAttribRTFormat: |
| break; |
| |
| case VAConfigAttribRateControl: |
| attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM; |
| break; |
| |
| case VAConfigAttribEncAutoReference: |
| attrib_list[i].value = 1; |
| break; |
| |
| case VAConfigAttribEncMaxRefFrames: |
| attrib_list[i].value = 4; |
| break; |
| |
| default: |
| attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; |
| break; |
| } |
| } |
| } |
| |
| static VAStatus tng_H264ES_ValidateConfig( |
| object_config_p obj_config) |
| { |
| int i; |
| |
| /* Check all attributes */ |
| for (i = 0; i < obj_config->attrib_count; i++) { |
| switch (obj_config->attrib_list[i].type) { |
| case VAConfigAttribRTFormat: |
| /* Ignore */ |
| break; |
| case VAConfigAttribRateControl: |
| break; |
| case VAConfigAttribEncAutoReference: |
| break; |
| case VAConfigAttribEncMaxRefFrames: |
| break; |
| default: |
| return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; |
| } |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| static VAStatus tng_H264ES_setup_profile_features(context_ENC_p ctx) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| |
| IMG_ENCODE_FEATURES * pEncFeatures = &ctx->sEncFeatures; |
| pEncFeatures->bEnable8x16MVDetect = IMG_TRUE; |
| pEncFeatures->bEnable16x8MVDetect = IMG_TRUE; |
| |
| return vaStatus; |
| } |
| |
| |
| static VAStatus tng_H264ES_CreateContext( |
| object_context_p obj_context, |
| object_config_p obj_config) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| context_ENC_p ctx; |
| |
| vaStatus = tng_CreateContext(obj_context, obj_config, 0); |
| |
| if (VA_STATUS_SUCCESS != vaStatus) |
| return VA_STATUS_ERROR_ALLOCATION_FAILED; |
| |
| ctx = (context_ENC_p) obj_context->format_data; |
| ctx->eStandard = IMG_STANDARD_H264; |
| |
| tng__H264ES_init_context(obj_context, obj_config); |
| |
| vaStatus = tng__H264ES_init_profile(obj_context, obj_config); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__H264ES_init_profile\n", __FUNCTION__); |
| } |
| |
| vaStatus = tng__H264ES_init_format_mode(obj_context, obj_config); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__H264ES_init_format_mode\n", __FUNCTION__); |
| } |
| |
| vaStatus = tng__H264ES_get_codec_type(obj_context, obj_config); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__H264ES_init_rc_mode\n", __FUNCTION__); |
| } |
| |
| vaStatus = tng_H264ES_setup_profile_features(ctx); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__profile_features\n", __FUNCTION__); |
| } |
| |
| vaStatus = tng__patch_hw_profile(ctx); |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: tng__patch_hw_profile\n", __FUNCTION__); |
| } |
| |
| return vaStatus; |
| } |
| |
| static void tng_H264ES_DestroyContext( |
| object_context_p obj_context) |
| { |
| tng_DestroyContext(obj_context, 0); |
| } |
| |
| static VAStatus tng_H264ES_BeginPicture( |
| object_context_p obj_context) |
| { |
| INIT_CONTEXT_H264ES; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| vaStatus = tng_BeginPicture(ctx); |
| return vaStatus; |
| } |
| |
| static VAStatus tng_H264ES_RenderPicture( |
| object_context_p obj_context, |
| object_buffer_p *buffers, |
| int num_buffers) |
| { |
| INIT_CONTEXT_H264ES; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| int i; |
| |
| for (i = 0; i < num_buffers; i++) { |
| object_buffer_p obj_buffer = buffers[i]; |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "%s: type = %d, num = %d\n", |
| __FUNCTION__, obj_buffer->type, num_buffers); |
| |
| switch (obj_buffer->type) { |
| case VAEncSequenceParameterBufferType: |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "tng_H264_RenderPicture got VAEncSequenceParameterBufferType\n"); |
| vaStatus = tng__H264ES_process_sequence_param(ctx, obj_buffer); |
| DEBUG_FAILURE; |
| break; |
| case VAEncPictureParameterBufferType: |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "tng_H264_RenderPicture got VAEncPictureParameterBuffer\n"); |
| vaStatus = tng__H264ES_process_picture_param(ctx, obj_buffer); |
| DEBUG_FAILURE; |
| break; |
| |
| case VAEncSliceParameterBufferType: |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "tng_H264_RenderPicture got VAEncSliceParameterBufferType\n"); |
| vaStatus = tng__H264ES_process_slice_param(ctx, obj_buffer); |
| DEBUG_FAILURE; |
| break; |
| |
| case VAEncMiscParameterBufferType: |
| drv_debug_msg(VIDEO_DEBUG_GENERAL, |
| "tng_H264_RenderPicture got VAEncMiscParameterBufferType\n"); |
| vaStatus = tng__H264ES_process_misc_param(ctx, obj_buffer); |
| DEBUG_FAILURE; |
| break; |
| default: |
| vaStatus = VA_STATUS_ERROR_UNKNOWN; |
| DEBUG_FAILURE; |
| } |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| break; |
| } |
| } |
| return vaStatus; |
| } |
| |
| static VAStatus tng_H264ES_EndPicture( |
| object_context_p obj_context) |
| { |
| INIT_CONTEXT_H264ES; |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| vaStatus = tng_EndPicture(ctx); |
| return vaStatus; |
| } |
| |
| struct format_vtable_s tng_H264ES_vtable = { |
| queryConfigAttributes: |
| tng_H264ES_QueryConfigAttributes, |
| validateConfig: |
| tng_H264ES_ValidateConfig, |
| createContext: |
| tng_H264ES_CreateContext, |
| destroyContext: |
| tng_H264ES_DestroyContext, |
| beginPicture: |
| tng_H264ES_BeginPicture, |
| renderPicture: |
| tng_H264ES_RenderPicture, |
| endPicture: |
| tng_H264ES_EndPicture |
| }; |
| |
| /*EOF*/ |