/* * Copyright (c) 2009-2011 Intel Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <string.h> #include <stdlib.h> #include "VideoEncoderLog.h" #include "VideoEncoderVP8.h" #include <va/va_tpi.h> #include <va/va_enc_vp8.h> VideoEncoderVP8::VideoEncoderVP8() :VideoEncoderBase() { mVideoParamsVP8.profile = 0; mVideoParamsVP8.error_resilient = 0; mVideoParamsVP8.num_token_partitions = 4; mVideoParamsVP8.kf_auto = 0; mVideoParamsVP8.kf_min_dist = 128; mVideoParamsVP8.kf_max_dist = 128; mVideoParamsVP8.min_qp = 0; mVideoParamsVP8.max_qp = 63; mVideoParamsVP8.init_qp = 26; mVideoParamsVP8.rc_undershoot = 100; mVideoParamsVP8.rc_overshoot = 100; mVideoParamsVP8.hrd_buf_size = 1000; mVideoParamsVP8.hrd_buf_initial_fullness = 500; mVideoParamsVP8.hrd_buf_optimal_fullness = 600; mVideoParamsVP8.max_frame_size_ratio = 0; mVideoConfigVP8.force_kf = 0; mVideoConfigVP8.refresh_entropy_probs = 0; mVideoConfigVP8.value = 0; mVideoConfigVP8.sharpness_level = 2; mVideoConfigVP8ReferenceFrame.no_ref_last = 0; mVideoConfigVP8ReferenceFrame.no_ref_gf = 0; mVideoConfigVP8ReferenceFrame.no_ref_arf = 0; mVideoConfigVP8ReferenceFrame.refresh_last = 1; mVideoConfigVP8ReferenceFrame.refresh_golden_frame = 1; mVideoConfigVP8ReferenceFrame.refresh_alternate_frame = 1; mComParams.profile = VAProfileVP8Version0_3; } VideoEncoderVP8::~VideoEncoderVP8() { } Encode_Status VideoEncoderVP8::start() { Encode_Status ret = ENCODE_SUCCESS; LOG_V( "Begin\n"); ret = VideoEncoderBase::start (); CHECK_ENCODE_STATUS_RETURN("VideoEncoderBase::start"); if (mComParams.rcMode == VA_RC_VCM) { mRenderBitRate = false; } LOG_V( "end\n"); return ret; } Encode_Status VideoEncoderVP8::renderSequenceParams() { Encode_Status ret = ENCODE_SUCCESS; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncSequenceParameterBufferVP8 vp8SeqParam = VAEncSequenceParameterBufferVP8(); LOG_V( "Begin\n"); vp8SeqParam.frame_width = mComParams.resolution.width; vp8SeqParam.frame_height = mComParams.resolution.height; vp8SeqParam.error_resilient = mVideoParamsVP8.error_resilient; vp8SeqParam.kf_auto = mVideoParamsVP8.kf_auto; vp8SeqParam.kf_min_dist = mVideoParamsVP8.kf_min_dist; vp8SeqParam.kf_max_dist = mVideoParamsVP8.kf_max_dist; vp8SeqParam.bits_per_second = mComParams.rcParams.bitRate; memcpy(vp8SeqParam.reference_frames, mAutoRefSurfaces, sizeof(mAutoRefSurfaces) * mAutoReferenceSurfaceNum); vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAEncSequenceParameterBufferType, sizeof(vp8SeqParam), 1, &vp8SeqParam, &mSeqParamBuf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSeqParamBuf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture"); LOG_V( "End\n"); return ret; } Encode_Status VideoEncoderVP8::renderPictureParams(EncodeTask *task) { Encode_Status ret = ENCODE_SUCCESS; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncPictureParameterBufferVP8 vp8PicParam = VAEncPictureParameterBufferVP8(); LOG_V( "Begin\n"); vp8PicParam.coded_buf = task->coded_buffer; vp8PicParam.pic_flags.value = 0; vp8PicParam.ref_flags.bits.force_kf = mVideoConfigVP8.force_kf; //0; if(!vp8PicParam.ref_flags.bits.force_kf) { vp8PicParam.ref_flags.bits.no_ref_last = mVideoConfigVP8ReferenceFrame.no_ref_last; vp8PicParam.ref_flags.bits.no_ref_arf = mVideoConfigVP8ReferenceFrame.no_ref_arf; vp8PicParam.ref_flags.bits.no_ref_gf = mVideoConfigVP8ReferenceFrame.no_ref_gf; } vp8PicParam.pic_flags.bits.refresh_entropy_probs = 0; vp8PicParam.sharpness_level = 2; vp8PicParam.pic_flags.bits.num_token_partitions = 2; vp8PicParam.pic_flags.bits.refresh_last = mVideoConfigVP8ReferenceFrame.refresh_last; vp8PicParam.pic_flags.bits.refresh_golden_frame = mVideoConfigVP8ReferenceFrame.refresh_golden_frame; vp8PicParam.pic_flags.bits.refresh_alternate_frame = mVideoConfigVP8ReferenceFrame.refresh_alternate_frame; vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAEncPictureParameterBufferType, sizeof(vp8PicParam), 1, &vp8PicParam, &mPicParamBuf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mPicParamBuf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture"); LOG_V( "End\n"); return ret; } Encode_Status VideoEncoderVP8::renderRCParams(uint32_t layer_id, bool total_bitrate) { VABufferID rc_param_buf; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterRateControl *misc_rate_ctrl; vaStatus = vaCreateBuffer(mVADisplay, mVAContext, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl), 1,NULL,&rc_param_buf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaMapBuffer(mVADisplay, rc_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeRateControl; misc_rate_ctrl = (VAEncMiscParameterRateControl *)misc_param->data; memset(misc_rate_ctrl, 0, sizeof(*misc_rate_ctrl)); if(total_bitrate) misc_rate_ctrl->bits_per_second = mComParams.rcParams.bitRate; else { misc_rate_ctrl->rc_flags.bits.temporal_id = layer_id; if(mTemporalLayerBitrateFramerate[layer_id].bitRate != 0) misc_rate_ctrl->bits_per_second = mTemporalLayerBitrateFramerate[layer_id].bitRate; } misc_rate_ctrl->target_percentage = 100; misc_rate_ctrl->window_size = 1000; misc_rate_ctrl->initial_qp = mVideoParamsVP8.init_qp; misc_rate_ctrl->min_qp = mVideoParamsVP8.min_qp; misc_rate_ctrl->basic_unit_size = 0; misc_rate_ctrl->max_qp = mVideoParamsVP8.max_qp; vaUnmapBuffer(mVADisplay, rc_param_buf); vaStatus = vaRenderPicture(mVADisplay,mVAContext, &rc_param_buf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture");; return 0; } Encode_Status VideoEncoderVP8::renderFrameRateParams(uint32_t layer_id, bool total_framerate) { VABufferID framerate_param_buf; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterFrameRate * misc_framerate; uint32_t frameRateNum = mComParams.frameRate.frameRateNum; uint32_t frameRateDenom = mComParams.frameRate.frameRateDenom; vaStatus = vaCreateBuffer(mVADisplay, mVAContext, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterFrameRate), 1,NULL,&framerate_param_buf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaMapBuffer(mVADisplay, framerate_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeFrameRate; misc_framerate = (VAEncMiscParameterFrameRate *)misc_param->data; memset(misc_framerate, 0, sizeof(*misc_framerate)); if(total_framerate) misc_framerate->framerate = (unsigned int) (frameRateNum + frameRateDenom /2) / frameRateDenom; else { misc_framerate->framerate_flags.bits.temporal_id = layer_id; if(mTemporalLayerBitrateFramerate[layer_id].frameRate != 0) misc_framerate->framerate = mTemporalLayerBitrateFramerate[layer_id].frameRate; } vaUnmapBuffer(mVADisplay, framerate_param_buf); vaStatus = vaRenderPicture(mVADisplay,mVAContext, &framerate_param_buf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture");; return 0; } Encode_Status VideoEncoderVP8::renderHRDParams(void) { VABufferID hrd_param_buf; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterHRD * misc_hrd; vaStatus = vaCreateBuffer(mVADisplay, mVAContext, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterHRD), 1,NULL,&hrd_param_buf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaMapBuffer(mVADisplay, hrd_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeHRD; misc_hrd = (VAEncMiscParameterHRD *)misc_param->data; memset(misc_hrd, 0, sizeof(*misc_hrd)); misc_hrd->buffer_size = 1000; misc_hrd->initial_buffer_fullness = 500; misc_hrd->optimal_buffer_fullness = 600; vaUnmapBuffer(mVADisplay, hrd_param_buf); vaStatus = vaRenderPicture(mVADisplay,mVAContext, &hrd_param_buf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture");; return 0; } Encode_Status VideoEncoderVP8::renderMaxFrameSizeParams(void) { VABufferID max_frame_size_param_buf; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterBufferMaxFrameSize * misc_maxframesize; unsigned int frameRateNum = mComParams.frameRate.frameRateNum; unsigned int frameRateDenom = mComParams.frameRate.frameRateDenom; unsigned int frameRate = (unsigned int)(frameRateNum + frameRateDenom /2); unsigned int bitRate = mComParams.rcParams.bitRate; vaStatus = vaCreateBuffer(mVADisplay, mVAContext, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterHRD), 1,NULL,&max_frame_size_param_buf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaMapBuffer(mVADisplay, max_frame_size_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeMaxFrameSize; misc_maxframesize = (VAEncMiscParameterBufferMaxFrameSize *)misc_param->data; memset(misc_maxframesize, 0, sizeof(*misc_maxframesize)); misc_maxframesize->max_frame_size = (unsigned int)((bitRate/frameRate) * mVideoParamsVP8.max_frame_size_ratio); vaUnmapBuffer(mVADisplay, max_frame_size_param_buf); vaStatus = vaRenderPicture(mVADisplay,mVAContext, &max_frame_size_param_buf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture");; return 0; } Encode_Status VideoEncoderVP8::renderLayerStructureParam(void) { VABufferID layer_struc_buf; VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterTemporalLayerStructure *misc_layer_struc; uint32_t i; vaStatus = vaCreateBuffer(mVADisplay, mVAContext, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterTemporalLayerStructure), 1, NULL, &layer_struc_buf); CHECK_VA_STATUS_RETURN("vaCreateBuffer"); vaMapBuffer(mVADisplay, layer_struc_buf, (void **)&misc_param); misc_param->type = VAEncMiscParameterTypeTemporalLayerStructure; misc_layer_struc = (VAEncMiscParameterTemporalLayerStructure *)misc_param->data; memset(misc_layer_struc, 0, sizeof(*misc_layer_struc)); misc_layer_struc->number_of_layers = mComParams.numberOfLayer; misc_layer_struc->periodicity = mComParams.nPeriodicity; LOGE("renderLayerStructureParam misc_layer_struc->number_of_layers is %d",misc_layer_struc->number_of_layers); for(i=0;i<mComParams.nPeriodicity;i++) { misc_layer_struc->layer_id[i] = mComParams.nLayerID[i]; } vaUnmapBuffer(mVADisplay, layer_struc_buf); vaStatus = vaRenderPicture(mVADisplay, mVAContext, &layer_struc_buf, 1); CHECK_VA_STATUS_RETURN("vaRenderPicture");; return 0; } Encode_Status VideoEncoderVP8::sendEncodeCommand(EncodeTask *task) { Encode_Status ret = ENCODE_SUCCESS; uint32_t i; if (mFrameNum == 0) { ret = renderSequenceParams(); ret = renderFrameRateParams(0,true); ret = renderRCParams(0,true); ret = renderHRDParams(); ret = renderMaxFrameSizeParams(); if(mRenderMultiTemporal) { ret = renderLayerStructureParam(); mRenderMultiTemporal = false; } if(mComParams.numberOfLayer > 1) for(i=0;i<mComParams.numberOfLayer;i++) { ret = renderFrameRateParams(i, false); ret = renderRCParams(i, false); } CHECK_ENCODE_STATUS_RETURN("renderSequenceParams"); } if (mRenderBitRate){ ret = renderRCParams(0,true); CHECK_ENCODE_STATUS_RETURN("renderRCParams"); mRenderBitRate = false; } if (mRenderFrameRate) { ret = renderFrameRateParams(0,true); CHECK_ENCODE_STATUS_RETURN("renderFrameRateParams"); mRenderFrameRate = false; } if (mRenderMaxFrameSize) { ret = renderMaxFrameSizeParams(); CHECK_ENCODE_STATUS_RETURN("renderMaxFrameSizeParams"); mRenderMaxFrameSize = false; } ret = renderPictureParams(task); CHECK_ENCODE_STATUS_RETURN("renderPictureParams"); if(mForceKFrame) { mVideoConfigVP8.force_kf = 0;//rest it as default value mForceKFrame = false; } LOG_V( "End\n"); return ret; } Encode_Status VideoEncoderVP8::derivedSetParams(VideoParamConfigSet *videoEncParams) { CHECK_NULL_RETURN_IFFAIL(videoEncParams); VideoParamsVP8 *encParamsVP8 = reinterpret_cast <VideoParamsVP8*> (videoEncParams); if (encParamsVP8->size != sizeof(VideoParamsVP8)) { return ENCODE_INVALID_PARAMS; } mVideoParamsVP8 = *encParamsVP8; return ENCODE_SUCCESS; } Encode_Status VideoEncoderVP8::derivedGetParams(VideoParamConfigSet *videoEncParams) { CHECK_NULL_RETURN_IFFAIL(videoEncParams); VideoParamsVP8 *encParamsVP8 = reinterpret_cast <VideoParamsVP8*> (videoEncParams); if (encParamsVP8->size != sizeof(VideoParamsVP8)) { return ENCODE_INVALID_PARAMS; } *encParamsVP8 = mVideoParamsVP8; return ENCODE_SUCCESS; } Encode_Status VideoEncoderVP8::derivedGetConfig(VideoParamConfigSet *videoEncConfig) { CHECK_NULL_RETURN_IFFAIL(videoEncConfig); switch (videoEncConfig->type) { case VideoConfigTypeVP8:{ VideoConfigVP8 *encConfigVP8 = reinterpret_cast<VideoConfigVP8*> (videoEncConfig); if (encConfigVP8->size != sizeof(VideoConfigVP8)) { return ENCODE_INVALID_PARAMS; } *encConfigVP8 = mVideoConfigVP8; } break; case VideoConfigTypeVP8ReferenceFrame:{ VideoConfigVP8ReferenceFrame *encConfigVP8ReferenceFrame = reinterpret_cast<VideoConfigVP8ReferenceFrame*> (videoEncConfig); if (encConfigVP8ReferenceFrame->size != sizeof(VideoConfigVP8ReferenceFrame)) { return ENCODE_INVALID_PARAMS; } *encConfigVP8ReferenceFrame = mVideoConfigVP8ReferenceFrame; } break; case VideoConfigTypeVP8MaxFrameSizeRatio :{ VideoConfigVP8MaxFrameSizeRatio *encConfigVP8MaxFrameSizeRatio = reinterpret_cast<VideoConfigVP8MaxFrameSizeRatio*> (videoEncConfig); if (encConfigVP8MaxFrameSizeRatio->size != sizeof(VideoConfigVP8MaxFrameSizeRatio)) { return ENCODE_INVALID_PARAMS; } encConfigVP8MaxFrameSizeRatio->max_frame_size_ratio = mVideoParamsVP8.max_frame_size_ratio; } break; default: { LOG_E ("Invalid Config Type"); break; } } return ENCODE_SUCCESS; } Encode_Status VideoEncoderVP8::derivedSetConfig(VideoParamConfigSet *videoEncConfig) { CHECK_NULL_RETURN_IFFAIL(videoEncConfig); switch (videoEncConfig->type) { case VideoConfigTypeVP8:{ VideoConfigVP8 *encConfigVP8 = reinterpret_cast<VideoConfigVP8*> (videoEncConfig); if (encConfigVP8->size != sizeof(VideoConfigVP8)) { return ENCODE_INVALID_PARAMS; } mVideoConfigVP8 = *encConfigVP8; } break; case VideoConfigTypeVP8ReferenceFrame:{ VideoConfigVP8ReferenceFrame *encConfigVP8ReferenceFrame = reinterpret_cast<VideoConfigVP8ReferenceFrame*> (videoEncConfig); if (encConfigVP8ReferenceFrame->size != sizeof(VideoConfigVP8ReferenceFrame)) { return ENCODE_INVALID_PARAMS; } mVideoConfigVP8ReferenceFrame = *encConfigVP8ReferenceFrame; } break; case VideoConfigTypeVP8MaxFrameSizeRatio:{ VideoConfigVP8MaxFrameSizeRatio *encConfigVP8MaxFrameSizeRatio = reinterpret_cast<VideoConfigVP8MaxFrameSizeRatio*> (videoEncConfig); if (encConfigVP8MaxFrameSizeRatio->size != sizeof(VideoConfigVP8MaxFrameSizeRatio)) { return ENCODE_INVALID_PARAMS; } mVideoParamsVP8.max_frame_size_ratio = encConfigVP8MaxFrameSizeRatio->max_frame_size_ratio; mRenderMaxFrameSize = true; } break; case VideoConfigTypeIDRRequest:{ mVideoConfigVP8.force_kf = 1; mForceKFrame = true; } break; default: { LOG_E ("Invalid Config Type"); break; } } return ENCODE_SUCCESS; }