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