| /* |
| * Copyright 2015 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "SoftAVCEnc" |
| #include <utils/Log.h> |
| #include <utils/misc.h> |
| |
| #include "OMX_Video.h" |
| |
| #include <HardwareAPI.h> |
| #include <MetadataBufferType.h> |
| #include <media/stagefright/foundation/ADebug.h> |
| #include <media/stagefright/MediaDefs.h> |
| #include <media/stagefright/MediaErrors.h> |
| #include <media/stagefright/MetaData.h> |
| #include <media/stagefright/Utils.h> |
| #include <OMX_IndexExt.h> |
| #include <OMX_VideoExt.h> |
| #include <ui/Rect.h> |
| |
| #include "ih264_typedefs.h" |
| #include "iv2.h" |
| #include "ive2.h" |
| #include "ih264e.h" |
| #include "SoftAVCEnc.h" |
| |
| namespace android { |
| |
| #define ive_api_function ih264e_api_function |
| |
| template<class T> |
| static void InitOMXParams(T *params) { |
| params->nSize = sizeof(T); |
| params->nVersion.s.nVersionMajor = 1; |
| params->nVersion.s.nVersionMinor = 0; |
| params->nVersion.s.nRevision = 0; |
| params->nVersion.s.nStep = 0; |
| } |
| |
| struct LevelConversion { |
| OMX_VIDEO_AVCLEVELTYPE omxLevel; |
| WORD32 avcLevel; |
| }; |
| |
| static LevelConversion ConversionTable[] = { |
| { OMX_VIDEO_AVCLevel1, 10 }, |
| { OMX_VIDEO_AVCLevel1b, 9 }, |
| { OMX_VIDEO_AVCLevel11, 11 }, |
| { OMX_VIDEO_AVCLevel12, 12 }, |
| { OMX_VIDEO_AVCLevel13, 13 }, |
| { OMX_VIDEO_AVCLevel2, 20 }, |
| { OMX_VIDEO_AVCLevel21, 21 }, |
| { OMX_VIDEO_AVCLevel22, 22 }, |
| { OMX_VIDEO_AVCLevel3, 30 }, |
| { OMX_VIDEO_AVCLevel31, 31 }, |
| { OMX_VIDEO_AVCLevel32, 32 }, |
| { OMX_VIDEO_AVCLevel4, 40 }, |
| { OMX_VIDEO_AVCLevel41, 41 }, |
| { OMX_VIDEO_AVCLevel42, 42 }, |
| { OMX_VIDEO_AVCLevel5, 50 }, |
| { OMX_VIDEO_AVCLevel51, 51 }, |
| }; |
| |
| static const CodecProfileLevel kProfileLevels[] = { |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 }, |
| { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1b }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel11 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel12 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel13 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel2 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel21 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel22 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel3 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel31 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel32 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel4 }, |
| { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel41 }, |
| |
| }; |
| |
| static size_t GetCPUCoreCount() { |
| long cpuCoreCount = 1; |
| #if defined(_SC_NPROCESSORS_ONLN) |
| cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); |
| #else |
| // _SC_NPROC_ONLN must be defined... |
| cpuCoreCount = sysconf(_SC_NPROC_ONLN); |
| #endif |
| CHECK(cpuCoreCount >= 1); |
| ALOGV("Number of CPU cores: %ld", cpuCoreCount); |
| return (size_t)cpuCoreCount; |
| } |
| |
| static status_t ConvertOmxAvcLevelToAvcSpecLevel( |
| OMX_VIDEO_AVCLEVELTYPE omxLevel, WORD32 *avcLevel) { |
| for (size_t i = 0; i < NELEM(ConversionTable); ++i) { |
| if (omxLevel == ConversionTable[i].omxLevel) { |
| *avcLevel = ConversionTable[i].avcLevel; |
| return OK; |
| } |
| } |
| |
| ALOGE("ConvertOmxAvcLevelToAvcSpecLevel: %d level not supported", |
| (int32_t)omxLevel); |
| |
| return BAD_VALUE; |
| } |
| |
| static status_t ConvertAvcSpecLevelToOmxAvcLevel( |
| WORD32 avcLevel, OMX_VIDEO_AVCLEVELTYPE *omxLevel) { |
| for (size_t i = 0; i < NELEM(ConversionTable); ++i) { |
| if (avcLevel == ConversionTable[i].avcLevel) { |
| *omxLevel = ConversionTable[i].omxLevel; |
| return OK; |
| } |
| } |
| |
| ALOGE("ConvertAvcSpecLevelToOmxAvcLevel: %d level not supported", |
| (int32_t)avcLevel); |
| |
| return BAD_VALUE; |
| } |
| |
| |
| SoftAVC::SoftAVC( |
| const char *name, |
| const OMX_CALLBACKTYPE *callbacks, |
| OMX_PTR appData, |
| OMX_COMPONENTTYPE **component) |
| : SoftVideoEncoderOMXComponent( |
| name, "video_encoder.avc", OMX_VIDEO_CodingAVC, |
| kProfileLevels, NELEM(kProfileLevels), |
| 176 /* width */, 144 /* height */, |
| callbacks, appData, component), |
| mUpdateFlag(0), |
| mIvVideoColorFormat(IV_YUV_420P), |
| mAVCEncProfile(IV_PROFILE_BASE), |
| mAVCEncLevel(41), |
| mStarted(false), |
| mSawInputEOS(false), |
| mSawOutputEOS(false), |
| mSignalledError(false), |
| mCodecCtx(NULL) { |
| |
| initPorts(kNumBuffers, kNumBuffers, ((mWidth * mHeight * 3) >> 1), |
| MEDIA_MIMETYPE_VIDEO_AVC, 2); |
| |
| // If dump is enabled, then open create an empty file |
| GENERATE_FILE_NAMES(); |
| CREATE_DUMP_FILE(mInFile); |
| CREATE_DUMP_FILE(mOutFile); |
| memset(mConversionBuffers, 0, sizeof(mConversionBuffers)); |
| memset(mInputBufferInfo, 0, sizeof(mInputBufferInfo)); |
| |
| initEncParams(); |
| |
| } |
| |
| SoftAVC::~SoftAVC() { |
| releaseEncoder(); |
| List<BufferInfo *> &outQueue = getPortQueue(1); |
| List<BufferInfo *> &inQueue = getPortQueue(0); |
| CHECK(outQueue.empty()); |
| CHECK(inQueue.empty()); |
| } |
| |
| void SoftAVC::initEncParams() { |
| mCodecCtx = NULL; |
| mMemRecords = NULL; |
| mNumMemRecords = DEFAULT_MEM_REC_CNT; |
| mHeaderGenerated = 0; |
| mNumCores = GetCPUCoreCount(); |
| mArch = DEFAULT_ARCH; |
| mSliceMode = DEFAULT_SLICE_MODE; |
| mSliceParam = DEFAULT_SLICE_PARAM; |
| mHalfPelEnable = DEFAULT_HPEL; |
| mIInterval = DEFAULT_I_INTERVAL; |
| mIDRInterval = DEFAULT_IDR_INTERVAL; |
| mDisableDeblkLevel = DEFAULT_DISABLE_DEBLK_LEVEL; |
| mEnableFastSad = DEFAULT_ENABLE_FAST_SAD; |
| mEnableAltRef = DEFAULT_ENABLE_ALT_REF; |
| mEncSpeed = DEFAULT_ENC_SPEED; |
| mIntra4x4 = DEFAULT_INTRA4x4; |
| mConstrainedIntraFlag = DEFAULT_CONSTRAINED_INTRA; |
| mAIRMode = DEFAULT_AIR; |
| mAIRRefreshPeriod = DEFAULT_AIR_REFRESH_PERIOD; |
| mPSNREnable = DEFAULT_PSNR_ENABLE; |
| mReconEnable = DEFAULT_RECON_ENABLE; |
| mEntropyMode = DEFAULT_ENTROPY_MODE; |
| mBframes = DEFAULT_B_FRAMES; |
| |
| gettimeofday(&mTimeStart, NULL); |
| gettimeofday(&mTimeEnd, NULL); |
| |
| } |
| |
| |
| OMX_ERRORTYPE SoftAVC::setDimensions() { |
| ive_ctl_set_dimensions_ip_t s_dimensions_ip; |
| ive_ctl_set_dimensions_op_t s_dimensions_op; |
| IV_STATUS_T status; |
| |
| s_dimensions_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_dimensions_ip.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS; |
| s_dimensions_ip.u4_ht = mHeight; |
| s_dimensions_ip.u4_wd = mWidth; |
| |
| s_dimensions_ip.u4_timestamp_high = -1; |
| s_dimensions_ip.u4_timestamp_low = -1; |
| |
| s_dimensions_ip.u4_size = sizeof(ive_ctl_set_dimensions_ip_t); |
| s_dimensions_op.u4_size = sizeof(ive_ctl_set_dimensions_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_dimensions_ip, &s_dimensions_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set frame dimensions = 0x%x\n", |
| s_dimensions_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setNumCores() { |
| IV_STATUS_T status; |
| ive_ctl_set_num_cores_ip_t s_num_cores_ip; |
| ive_ctl_set_num_cores_op_t s_num_cores_op; |
| s_num_cores_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_num_cores_ip.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES; |
| s_num_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_CORES); |
| s_num_cores_ip.u4_timestamp_high = -1; |
| s_num_cores_ip.u4_timestamp_low = -1; |
| s_num_cores_ip.u4_size = sizeof(ive_ctl_set_num_cores_ip_t); |
| |
| s_num_cores_op.u4_size = sizeof(ive_ctl_set_num_cores_op_t); |
| |
| status = ive_api_function( |
| mCodecCtx, (void *) &s_num_cores_ip, (void *) &s_num_cores_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set processor params = 0x%x\n", |
| s_num_cores_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setFrameRate() { |
| ive_ctl_set_frame_rate_ip_t s_frame_rate_ip; |
| ive_ctl_set_frame_rate_op_t s_frame_rate_op; |
| IV_STATUS_T status; |
| |
| s_frame_rate_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_frame_rate_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE; |
| |
| s_frame_rate_ip.u4_src_frame_rate = mFramerate >> 16; |
| s_frame_rate_ip.u4_tgt_frame_rate = mFramerate >> 16; |
| |
| s_frame_rate_ip.u4_timestamp_high = -1; |
| s_frame_rate_ip.u4_timestamp_low = -1; |
| |
| s_frame_rate_ip.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t); |
| s_frame_rate_op.u4_size = sizeof(ive_ctl_set_frame_rate_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_frame_rate_ip, &s_frame_rate_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set frame rate = 0x%x\n", |
| s_frame_rate_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setIpeParams() { |
| ive_ctl_set_ipe_params_ip_t s_ipe_params_ip; |
| ive_ctl_set_ipe_params_op_t s_ipe_params_op; |
| IV_STATUS_T status; |
| |
| s_ipe_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_ipe_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS; |
| |
| s_ipe_params_ip.u4_enable_intra_4x4 = mIntra4x4; |
| s_ipe_params_ip.u4_enc_speed_preset = mEncSpeed; |
| s_ipe_params_ip.u4_constrained_intra_pred = mConstrainedIntraFlag; |
| |
| s_ipe_params_ip.u4_timestamp_high = -1; |
| s_ipe_params_ip.u4_timestamp_low = -1; |
| |
| s_ipe_params_ip.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t); |
| s_ipe_params_op.u4_size = sizeof(ive_ctl_set_ipe_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_ipe_params_ip, &s_ipe_params_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set ipe params = 0x%x\n", |
| s_ipe_params_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setBitRate() { |
| ive_ctl_set_bitrate_ip_t s_bitrate_ip; |
| ive_ctl_set_bitrate_op_t s_bitrate_op; |
| IV_STATUS_T status; |
| |
| s_bitrate_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_bitrate_ip.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE; |
| |
| s_bitrate_ip.u4_target_bitrate = mBitrate; |
| |
| s_bitrate_ip.u4_timestamp_high = -1; |
| s_bitrate_ip.u4_timestamp_low = -1; |
| |
| s_bitrate_ip.u4_size = sizeof(ive_ctl_set_bitrate_ip_t); |
| s_bitrate_op.u4_size = sizeof(ive_ctl_set_bitrate_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_bitrate_ip, &s_bitrate_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set bit rate = 0x%x\n", s_bitrate_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type) { |
| ive_ctl_set_frame_type_ip_t s_frame_type_ip; |
| ive_ctl_set_frame_type_op_t s_frame_type_op; |
| IV_STATUS_T status; |
| s_frame_type_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_frame_type_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE; |
| |
| s_frame_type_ip.e_frame_type = e_frame_type; |
| |
| s_frame_type_ip.u4_timestamp_high = -1; |
| s_frame_type_ip.u4_timestamp_low = -1; |
| |
| s_frame_type_ip.u4_size = sizeof(ive_ctl_set_frame_type_ip_t); |
| s_frame_type_op.u4_size = sizeof(ive_ctl_set_frame_type_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_frame_type_ip, &s_frame_type_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set frame type = 0x%x\n", |
| s_frame_type_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setQp() { |
| ive_ctl_set_qp_ip_t s_qp_ip; |
| ive_ctl_set_qp_op_t s_qp_op; |
| IV_STATUS_T status; |
| |
| s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP; |
| |
| s_qp_ip.u4_i_qp = DEFAULT_I_QP; |
| s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX; |
| s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN; |
| |
| s_qp_ip.u4_p_qp = DEFAULT_P_QP; |
| s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX; |
| s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN; |
| |
| s_qp_ip.u4_b_qp = DEFAULT_P_QP; |
| s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX; |
| s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN; |
| |
| s_qp_ip.u4_timestamp_high = -1; |
| s_qp_ip.u4_timestamp_low = -1; |
| |
| s_qp_ip.u4_size = sizeof(ive_ctl_set_qp_ip_t); |
| s_qp_op.u4_size = sizeof(ive_ctl_set_qp_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_qp_ip, &s_qp_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set qp 0x%x\n", s_qp_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setEncMode(IVE_ENC_MODE_T e_enc_mode) { |
| IV_STATUS_T status; |
| ive_ctl_set_enc_mode_ip_t s_enc_mode_ip; |
| ive_ctl_set_enc_mode_op_t s_enc_mode_op; |
| |
| s_enc_mode_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_enc_mode_ip.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE; |
| |
| s_enc_mode_ip.e_enc_mode = e_enc_mode; |
| |
| s_enc_mode_ip.u4_timestamp_high = -1; |
| s_enc_mode_ip.u4_timestamp_low = -1; |
| |
| s_enc_mode_ip.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t); |
| s_enc_mode_op.u4_size = sizeof(ive_ctl_set_enc_mode_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_enc_mode_ip, &s_enc_mode_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set in header encode mode = 0x%x\n", |
| s_enc_mode_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setVbvParams() { |
| ive_ctl_set_vbv_params_ip_t s_vbv_ip; |
| ive_ctl_set_vbv_params_op_t s_vbv_op; |
| IV_STATUS_T status; |
| |
| s_vbv_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_vbv_ip.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS; |
| |
| s_vbv_ip.u4_vbv_buf_size = 0; |
| s_vbv_ip.u4_vbv_buffer_delay = 1000; |
| |
| s_vbv_ip.u4_timestamp_high = -1; |
| s_vbv_ip.u4_timestamp_low = -1; |
| |
| s_vbv_ip.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t); |
| s_vbv_op.u4_size = sizeof(ive_ctl_set_vbv_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_vbv_ip, &s_vbv_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set VBC params = 0x%x\n", s_vbv_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setAirParams() { |
| ive_ctl_set_air_params_ip_t s_air_ip; |
| ive_ctl_set_air_params_op_t s_air_op; |
| IV_STATUS_T status; |
| |
| s_air_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_air_ip.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS; |
| |
| s_air_ip.e_air_mode = mAIRMode; |
| s_air_ip.u4_air_refresh_period = mAIRRefreshPeriod; |
| |
| s_air_ip.u4_timestamp_high = -1; |
| s_air_ip.u4_timestamp_low = -1; |
| |
| s_air_ip.u4_size = sizeof(ive_ctl_set_air_params_ip_t); |
| s_air_op.u4_size = sizeof(ive_ctl_set_air_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_air_ip, &s_air_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set air params = 0x%x\n", s_air_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setMeParams() { |
| IV_STATUS_T status; |
| ive_ctl_set_me_params_ip_t s_me_params_ip; |
| ive_ctl_set_me_params_op_t s_me_params_op; |
| |
| s_me_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_me_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS; |
| |
| s_me_params_ip.u4_enable_fast_sad = mEnableFastSad; |
| s_me_params_ip.u4_enable_alt_ref = mEnableAltRef; |
| |
| s_me_params_ip.u4_enable_hpel = mHalfPelEnable; |
| s_me_params_ip.u4_enable_qpel = DEFAULT_QPEL; |
| s_me_params_ip.u4_me_speed_preset = DEFAULT_ME_SPEED; |
| s_me_params_ip.u4_srch_rng_x = DEFAULT_SRCH_RNG_X; |
| s_me_params_ip.u4_srch_rng_y = DEFAULT_SRCH_RNG_Y; |
| |
| s_me_params_ip.u4_timestamp_high = -1; |
| s_me_params_ip.u4_timestamp_low = -1; |
| |
| s_me_params_ip.u4_size = sizeof(ive_ctl_set_me_params_ip_t); |
| s_me_params_op.u4_size = sizeof(ive_ctl_set_me_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_me_params_ip, &s_me_params_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set me params = 0x%x\n", s_me_params_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setGopParams() { |
| IV_STATUS_T status; |
| ive_ctl_set_gop_params_ip_t s_gop_params_ip; |
| ive_ctl_set_gop_params_op_t s_gop_params_op; |
| |
| s_gop_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_gop_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS; |
| |
| s_gop_params_ip.u4_i_frm_interval = mIInterval; |
| s_gop_params_ip.u4_idr_frm_interval = mIDRInterval; |
| |
| s_gop_params_ip.u4_timestamp_high = -1; |
| s_gop_params_ip.u4_timestamp_low = -1; |
| |
| s_gop_params_ip.u4_size = sizeof(ive_ctl_set_gop_params_ip_t); |
| s_gop_params_op.u4_size = sizeof(ive_ctl_set_gop_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_gop_params_ip, &s_gop_params_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set ME params = 0x%x\n", |
| s_gop_params_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setProfileParams() { |
| IV_STATUS_T status; |
| ive_ctl_set_profile_params_ip_t s_profile_params_ip; |
| ive_ctl_set_profile_params_op_t s_profile_params_op; |
| |
| s_profile_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_profile_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS; |
| |
| s_profile_params_ip.e_profile = DEFAULT_EPROFILE; |
| s_profile_params_ip.u4_entropy_coding_mode = mEntropyMode; |
| s_profile_params_ip.u4_timestamp_high = -1; |
| s_profile_params_ip.u4_timestamp_low = -1; |
| |
| s_profile_params_ip.u4_size = sizeof(ive_ctl_set_profile_params_ip_t); |
| s_profile_params_op.u4_size = sizeof(ive_ctl_set_profile_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_profile_params_ip, &s_profile_params_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to set profile params = 0x%x\n", |
| s_profile_params_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setDeblockParams() { |
| IV_STATUS_T status; |
| ive_ctl_set_deblock_params_ip_t s_deblock_params_ip; |
| ive_ctl_set_deblock_params_op_t s_deblock_params_op; |
| |
| s_deblock_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_deblock_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS; |
| |
| s_deblock_params_ip.u4_disable_deblock_level = mDisableDeblkLevel; |
| |
| s_deblock_params_ip.u4_timestamp_high = -1; |
| s_deblock_params_ip.u4_timestamp_low = -1; |
| |
| s_deblock_params_ip.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t); |
| s_deblock_params_op.u4_size = sizeof(ive_ctl_set_deblock_params_op_t); |
| |
| status = ive_api_function(mCodecCtx, &s_deblock_params_ip, &s_deblock_params_op); |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to enable/disable deblock params = 0x%x\n", |
| s_deblock_params_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| void SoftAVC::logVersion() { |
| ive_ctl_getversioninfo_ip_t s_ctl_ip; |
| ive_ctl_getversioninfo_op_t s_ctl_op; |
| UWORD8 au1_buf[512]; |
| IV_STATUS_T status; |
| |
| s_ctl_ip.e_cmd = IVE_CMD_VIDEO_CTL; |
| s_ctl_ip.e_sub_cmd = IVE_CMD_CTL_GETVERSION; |
| s_ctl_ip.u4_size = sizeof(ive_ctl_getversioninfo_ip_t); |
| s_ctl_op.u4_size = sizeof(ive_ctl_getversioninfo_op_t); |
| s_ctl_ip.pu1_version = au1_buf; |
| s_ctl_ip.u4_version_bufsize = sizeof(au1_buf); |
| |
| status = ive_api_function(mCodecCtx, (void *) &s_ctl_ip, (void *) &s_ctl_op); |
| |
| if (status != IV_SUCCESS) { |
| ALOGE("Error in getting version: 0x%x", s_ctl_op.u4_error_code); |
| } else { |
| ALOGV("Ittiam encoder version: %s", (char *)s_ctl_ip.pu1_version); |
| } |
| return; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::initEncoder() { |
| IV_STATUS_T status; |
| WORD32 level; |
| uint32_t displaySizeY; |
| |
| CHECK(!mStarted); |
| |
| OMX_ERRORTYPE errType = OMX_ErrorNone; |
| |
| displaySizeY = mWidth * mHeight; |
| if (displaySizeY > (1920 * 1088)) { |
| level = 50; |
| } else if (displaySizeY > (1280 * 720)) { |
| level = 40; |
| } else if (displaySizeY > (720 * 576)) { |
| level = 31; |
| } else if (displaySizeY > (624 * 320)) { |
| level = 30; |
| } else if (displaySizeY > (352 * 288)) { |
| level = 21; |
| } else { |
| level = 20; |
| } |
| mAVCEncLevel = MAX(level, mAVCEncLevel); |
| |
| mStride = mWidth; |
| |
| if (mInputDataIsMeta) { |
| for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { |
| if (mConversionBuffers[i] != NULL) { |
| free(mConversionBuffers[i]); |
| mConversionBuffers[i] = 0; |
| } |
| |
| if (((uint64_t)mStride * mHeight) > ((uint64_t)INT32_MAX / 3)) { |
| ALOGE("Buffer size is too big."); |
| return OMX_ErrorUndefined; |
| } |
| mConversionBuffers[i] = (uint8_t *)malloc(mStride * mHeight * 3 / 2); |
| |
| if (mConversionBuffers[i] == NULL) { |
| ALOGE("Allocating conversion buffer failed."); |
| return OMX_ErrorUndefined; |
| } |
| |
| mConversionBuffersFree[i] = 1; |
| } |
| } |
| |
| switch (mColorFormat) { |
| case OMX_COLOR_FormatYUV420SemiPlanar: |
| mIvVideoColorFormat = IV_YUV_420SP_UV; |
| ALOGV("colorFormat YUV_420SP"); |
| break; |
| default: |
| case OMX_COLOR_FormatYUV420Planar: |
| mIvVideoColorFormat = IV_YUV_420P; |
| ALOGV("colorFormat YUV_420P"); |
| break; |
| } |
| |
| ALOGD("Params width %d height %d level %d colorFormat %d", mWidth, |
| mHeight, mAVCEncLevel, mIvVideoColorFormat); |
| |
| /* Getting Number of MemRecords */ |
| { |
| iv_num_mem_rec_ip_t s_num_mem_rec_ip; |
| iv_num_mem_rec_op_t s_num_mem_rec_op; |
| |
| s_num_mem_rec_ip.u4_size = sizeof(iv_num_mem_rec_ip_t); |
| s_num_mem_rec_op.u4_size = sizeof(iv_num_mem_rec_op_t); |
| |
| s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; |
| |
| status = ive_api_function(0, &s_num_mem_rec_ip, &s_num_mem_rec_op); |
| |
| if (status != IV_SUCCESS) { |
| ALOGE("Get number of memory records failed = 0x%x\n", |
| s_num_mem_rec_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| |
| mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; |
| } |
| |
| /* Allocate array to hold memory records */ |
| if (mNumMemRecords > SIZE_MAX / sizeof(iv_mem_rec_t)) { |
| ALOGE("requested memory size is too big."); |
| return OMX_ErrorUndefined; |
| } |
| mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t)); |
| if (NULL == mMemRecords) { |
| ALOGE("Unable to allocate memory for hold memory records: Size %zu", |
| mNumMemRecords * sizeof(iv_mem_rec_t)); |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return OMX_ErrorUndefined; |
| } |
| |
| { |
| iv_mem_rec_t *ps_mem_rec; |
| ps_mem_rec = mMemRecords; |
| for (size_t i = 0; i < mNumMemRecords; i++) { |
| ps_mem_rec->u4_size = sizeof(iv_mem_rec_t); |
| ps_mem_rec->pv_base = NULL; |
| ps_mem_rec->u4_mem_size = 0; |
| ps_mem_rec->u4_mem_alignment = 0; |
| ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE; |
| |
| ps_mem_rec++; |
| } |
| } |
| |
| /* Getting MemRecords Attributes */ |
| { |
| iv_fill_mem_rec_ip_t s_fill_mem_rec_ip; |
| iv_fill_mem_rec_op_t s_fill_mem_rec_op; |
| |
| s_fill_mem_rec_ip.u4_size = sizeof(iv_fill_mem_rec_ip_t); |
| s_fill_mem_rec_op.u4_size = sizeof(iv_fill_mem_rec_op_t); |
| |
| s_fill_mem_rec_ip.e_cmd = IV_CMD_FILL_NUM_MEM_REC; |
| s_fill_mem_rec_ip.ps_mem_rec = mMemRecords; |
| s_fill_mem_rec_ip.u4_num_mem_rec = mNumMemRecords; |
| s_fill_mem_rec_ip.u4_max_wd = mWidth; |
| s_fill_mem_rec_ip.u4_max_ht = mHeight; |
| s_fill_mem_rec_ip.u4_max_level = mAVCEncLevel; |
| s_fill_mem_rec_ip.e_color_format = DEFAULT_INP_COLOR_FORMAT; |
| s_fill_mem_rec_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; |
| s_fill_mem_rec_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; |
| s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; |
| s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; |
| |
| status = ive_api_function(0, &s_fill_mem_rec_ip, &s_fill_mem_rec_op); |
| |
| if (status != IV_SUCCESS) { |
| ALOGE("Fill memory records failed = 0x%x\n", |
| s_fill_mem_rec_op.u4_error_code); |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return OMX_ErrorUndefined; |
| } |
| } |
| |
| /* Allocating Memory for Mem Records */ |
| { |
| WORD32 total_size; |
| iv_mem_rec_t *ps_mem_rec; |
| total_size = 0; |
| ps_mem_rec = mMemRecords; |
| |
| for (size_t i = 0; i < mNumMemRecords; i++) { |
| ps_mem_rec->pv_base = ive_aligned_malloc( |
| ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); |
| if (ps_mem_rec->pv_base == NULL) { |
| ALOGE("Allocation failure for mem record id %zu size %u\n", i, |
| ps_mem_rec->u4_mem_size); |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return OMX_ErrorUndefined; |
| |
| } |
| total_size += ps_mem_rec->u4_mem_size; |
| |
| ps_mem_rec++; |
| } |
| } |
| |
| /* Codec Instance Creation */ |
| { |
| ive_init_ip_t s_init_ip; |
| ive_init_op_t s_init_op; |
| |
| mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; |
| mCodecCtx->u4_size = sizeof(iv_obj_t); |
| mCodecCtx->pv_fxns = (void *)ive_api_function; |
| |
| s_init_ip.u4_size = sizeof(ive_init_ip_t); |
| s_init_op.u4_size = sizeof(ive_init_op_t); |
| |
| s_init_ip.e_cmd = IV_CMD_INIT; |
| s_init_ip.u4_num_mem_rec = mNumMemRecords; |
| s_init_ip.ps_mem_rec = mMemRecords; |
| s_init_ip.u4_max_wd = mWidth; |
| s_init_ip.u4_max_ht = mHeight; |
| s_init_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; |
| s_init_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; |
| s_init_ip.u4_max_level = mAVCEncLevel; |
| s_init_ip.e_inp_color_fmt = mIvVideoColorFormat; |
| |
| if (mReconEnable || mPSNREnable) { |
| s_init_ip.u4_enable_recon = 1; |
| } else { |
| s_init_ip.u4_enable_recon = 0; |
| } |
| s_init_ip.e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT; |
| s_init_ip.e_rc_mode = DEFAULT_RC_MODE; |
| s_init_ip.u4_max_framerate = DEFAULT_MAX_FRAMERATE; |
| s_init_ip.u4_max_bitrate = DEFAULT_MAX_BITRATE; |
| s_init_ip.u4_num_bframes = mBframes; |
| s_init_ip.e_content_type = IV_PROGRESSIVE; |
| s_init_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; |
| s_init_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; |
| s_init_ip.e_slice_mode = mSliceMode; |
| s_init_ip.u4_slice_param = mSliceParam; |
| s_init_ip.e_arch = mArch; |
| s_init_ip.e_soc = DEFAULT_SOC; |
| |
| status = ive_api_function(mCodecCtx, &s_init_ip, &s_init_op); |
| |
| if (status != IV_SUCCESS) { |
| ALOGE("Init memory records failed = 0x%x\n", |
| s_init_op.u4_error_code); |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */); |
| return OMX_ErrorUndefined; |
| } |
| } |
| |
| /* Get Codec Version */ |
| logVersion(); |
| |
| /* set processor details */ |
| setNumCores(); |
| |
| /* Video control Set Frame dimensions */ |
| setDimensions(); |
| |
| /* Video control Set Frame rates */ |
| setFrameRate(); |
| |
| /* Video control Set IPE Params */ |
| setIpeParams(); |
| |
| /* Video control Set Bitrate */ |
| setBitRate(); |
| |
| /* Video control Set QP */ |
| setQp(); |
| |
| /* Video control Set AIR params */ |
| setAirParams(); |
| |
| /* Video control Set VBV params */ |
| setVbvParams(); |
| |
| /* Video control Set Motion estimation params */ |
| setMeParams(); |
| |
| /* Video control Set GOP params */ |
| setGopParams(); |
| |
| /* Video control Set Deblock params */ |
| setDeblockParams(); |
| |
| /* Video control Set Profile params */ |
| setProfileParams(); |
| |
| /* Video control Set in Encode header mode */ |
| setEncMode(IVE_ENC_MODE_HEADER); |
| |
| ALOGV("init_codec successfull"); |
| |
| mSpsPpsHeaderReceived = false; |
| mStarted = true; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::releaseEncoder() { |
| IV_STATUS_T status = IV_SUCCESS; |
| iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip; |
| iv_retrieve_mem_rec_op_t s_retrieve_mem_op; |
| iv_mem_rec_t *ps_mem_rec; |
| |
| if (!mStarted) { |
| return OMX_ErrorNone; |
| } |
| |
| s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t); |
| s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t); |
| s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC; |
| s_retrieve_mem_ip.ps_mem_rec = mMemRecords; |
| |
| status = ive_api_function(mCodecCtx, &s_retrieve_mem_ip, &s_retrieve_mem_op); |
| |
| if (status != IV_SUCCESS) { |
| ALOGE("Unable to retrieve memory records = 0x%x\n", |
| s_retrieve_mem_op.u4_error_code); |
| return OMX_ErrorUndefined; |
| } |
| |
| /* Free memory records */ |
| ps_mem_rec = mMemRecords; |
| for (size_t i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) { |
| ive_aligned_free(ps_mem_rec->pv_base); |
| ps_mem_rec++; |
| } |
| |
| free(mMemRecords); |
| |
| for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { |
| if (mConversionBuffers[i]) { |
| free(mConversionBuffers[i]); |
| mConversionBuffers[i] = NULL; |
| } |
| } |
| |
| // clear other pointers into the space being free()d |
| mCodecCtx = NULL; |
| |
| mStarted = false; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params) { |
| switch (index) { |
| case OMX_IndexParamVideoBitrate: |
| { |
| OMX_VIDEO_PARAM_BITRATETYPE *bitRate = |
| (OMX_VIDEO_PARAM_BITRATETYPE *)params; |
| |
| if (!isValidOMXParam(bitRate)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (bitRate->nPortIndex != 1) { |
| return OMX_ErrorUndefined; |
| } |
| |
| bitRate->eControlRate = OMX_Video_ControlRateVariable; |
| bitRate->nTargetBitrate = mBitrate; |
| return OMX_ErrorNone; |
| } |
| |
| case OMX_IndexParamVideoAvc: |
| { |
| OMX_VIDEO_PARAM_AVCTYPE *avcParams = (OMX_VIDEO_PARAM_AVCTYPE *)params; |
| |
| if (!isValidOMXParam(avcParams)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (avcParams->nPortIndex != 1) { |
| return OMX_ErrorUndefined; |
| } |
| |
| OMX_VIDEO_AVCLEVELTYPE omxLevel = OMX_VIDEO_AVCLevel41; |
| if (OMX_ErrorNone |
| != ConvertAvcSpecLevelToOmxAvcLevel(mAVCEncLevel, &omxLevel)) { |
| return OMX_ErrorUndefined; |
| } |
| |
| avcParams->eProfile = OMX_VIDEO_AVCProfileBaseline; |
| avcParams->eLevel = omxLevel; |
| avcParams->nRefFrames = 1; |
| avcParams->bUseHadamard = OMX_TRUE; |
| avcParams->nAllowedPictureTypes = (OMX_VIDEO_PictureTypeI |
| | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB); |
| avcParams->nRefIdx10ActiveMinus1 = 0; |
| avcParams->nRefIdx11ActiveMinus1 = 0; |
| avcParams->bWeightedPPrediction = OMX_FALSE; |
| avcParams->bconstIpred = OMX_FALSE; |
| avcParams->bDirect8x8Inference = OMX_FALSE; |
| avcParams->bDirectSpatialTemporal = OMX_FALSE; |
| avcParams->nCabacInitIdc = 0; |
| return OMX_ErrorNone; |
| } |
| |
| default: |
| return SoftVideoEncoderOMXComponent::internalGetParameter(index, params); |
| } |
| } |
| |
| OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { |
| int32_t indexFull = index; |
| |
| switch (indexFull) { |
| case OMX_IndexParamVideoBitrate: |
| { |
| OMX_VIDEO_PARAM_BITRATETYPE *bitRate = |
| (OMX_VIDEO_PARAM_BITRATETYPE *)params; |
| |
| if (!isValidOMXParam(bitRate)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| return internalSetBitrateParams(bitRate); |
| } |
| |
| case OMX_IndexParamVideoAvc: |
| { |
| OMX_VIDEO_PARAM_AVCTYPE *avcType = (OMX_VIDEO_PARAM_AVCTYPE *)params; |
| |
| if (!isValidOMXParam(avcType)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (avcType->nPortIndex != 1) { |
| return OMX_ErrorUndefined; |
| } |
| |
| mEntropyMode = 0; |
| |
| if (OMX_TRUE == avcType->bEntropyCodingCABAC) |
| mEntropyMode = 1; |
| |
| if ((avcType->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) && |
| avcType->nPFrames) { |
| mBframes = avcType->nBFrames; |
| } |
| |
| mIInterval = (avcType->nPFrames + 1) * (avcType->nBFrames + 1); |
| mConstrainedIntraFlag = avcType->bconstIpred; |
| |
| if (OMX_VIDEO_AVCLoopFilterDisable == avcType->eLoopFilterMode) |
| mDisableDeblkLevel = 4; |
| |
| if (avcType->nRefFrames != 1 |
| || avcType->bUseHadamard != OMX_TRUE |
| || avcType->nRefIdx10ActiveMinus1 != 0 |
| || avcType->nRefIdx11ActiveMinus1 != 0 |
| || avcType->bWeightedPPrediction != OMX_FALSE |
| || avcType->bDirect8x8Inference != OMX_FALSE |
| || avcType->bDirectSpatialTemporal != OMX_FALSE |
| || avcType->nCabacInitIdc != 0) { |
| // OMX does not allow a way to signal what values are wrong, so it's |
| // best for components to just do best effort in supporting these values |
| ALOGV("ignoring unsupported settings"); |
| } |
| |
| if (OK != ConvertOmxAvcLevelToAvcSpecLevel(avcType->eLevel, &mAVCEncLevel)) { |
| return OMX_ErrorUndefined; |
| } |
| |
| return OMX_ErrorNone; |
| } |
| |
| default: |
| return SoftVideoEncoderOMXComponent::internalSetParameter(index, params); |
| } |
| } |
| |
| OMX_ERRORTYPE SoftAVC::getConfig( |
| OMX_INDEXTYPE index, OMX_PTR _params) { |
| switch ((int)index) { |
| case OMX_IndexConfigAndroidIntraRefresh: |
| { |
| OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams = |
| (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params; |
| |
| if (!isValidOMXParam(intraRefreshParams)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (intraRefreshParams->nPortIndex != kOutputPortIndex) { |
| return OMX_ErrorUndefined; |
| } |
| |
| intraRefreshParams->nRefreshPeriod = |
| (mAIRMode == IVE_AIR_MODE_NONE) ? 0 : mAIRRefreshPeriod; |
| return OMX_ErrorNone; |
| } |
| |
| default: |
| return SoftVideoEncoderOMXComponent::getConfig(index, _params); |
| } |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setConfig( |
| OMX_INDEXTYPE index, const OMX_PTR _params) { |
| switch ((int)index) { |
| case OMX_IndexConfigVideoIntraVOPRefresh: |
| { |
| OMX_CONFIG_INTRAREFRESHVOPTYPE *params = |
| (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; |
| |
| if (!isValidOMXParam(params)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (params->nPortIndex != kOutputPortIndex) { |
| return OMX_ErrorBadPortIndex; |
| } |
| |
| if (params->IntraRefreshVOP) { |
| mUpdateFlag |= kRequestKeyFrame; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| case OMX_IndexConfigVideoBitrate: |
| { |
| OMX_VIDEO_CONFIG_BITRATETYPE *params = |
| (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; |
| |
| if (!isValidOMXParam(params)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (params->nPortIndex != kOutputPortIndex) { |
| return OMX_ErrorBadPortIndex; |
| } |
| |
| if (mBitrate != params->nEncodeBitrate) { |
| mBitrate = params->nEncodeBitrate; |
| mUpdateFlag |= kUpdateBitrate; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| case OMX_IndexConfigAndroidIntraRefresh: |
| { |
| const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams = |
| (const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params; |
| |
| if (!isValidOMXParam(intraRefreshParams)) { |
| return OMX_ErrorBadParameter; |
| } |
| |
| if (intraRefreshParams->nPortIndex != kOutputPortIndex) { |
| return OMX_ErrorUndefined; |
| } |
| |
| if (intraRefreshParams->nRefreshPeriod == 0) { |
| mAIRMode = IVE_AIR_MODE_NONE; |
| mAIRRefreshPeriod = 0; |
| } else if (intraRefreshParams->nRefreshPeriod > 0) { |
| mAIRMode = IVE_AIR_MODE_CYCLIC; |
| mAIRRefreshPeriod = intraRefreshParams->nRefreshPeriod; |
| } |
| mUpdateFlag |= kUpdateAIRMode; |
| return OMX_ErrorNone; |
| } |
| |
| default: |
| return SimpleSoftOMXComponent::setConfig(index, _params); |
| } |
| } |
| |
| OMX_ERRORTYPE SoftAVC::internalSetBitrateParams( |
| const OMX_VIDEO_PARAM_BITRATETYPE *bitrate) { |
| if (bitrate->nPortIndex != kOutputPortIndex) { |
| return OMX_ErrorUnsupportedIndex; |
| } |
| |
| mBitrate = bitrate->nTargetBitrate; |
| mUpdateFlag |= kUpdateBitrate; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE SoftAVC::setEncodeArgs( |
| ive_video_encode_ip_t *ps_encode_ip, |
| ive_video_encode_op_t *ps_encode_op, |
| OMX_BUFFERHEADERTYPE *inputBufferHeader, |
| OMX_BUFFERHEADERTYPE *outputBufferHeader) { |
| iv_raw_buf_t *ps_inp_raw_buf; |
| const uint8_t *source; |
| UWORD8 *pu1_buf; |
| |
| ps_inp_raw_buf = &ps_encode_ip->s_inp_buf; |
| ps_encode_ip->s_out_buf.pv_buf = outputBufferHeader->pBuffer; |
| ps_encode_ip->s_out_buf.u4_bytes = 0; |
| ps_encode_ip->s_out_buf.u4_bufsize = outputBufferHeader->nAllocLen; |
| ps_encode_ip->u4_size = sizeof(ive_video_encode_ip_t); |
| ps_encode_op->u4_size = sizeof(ive_video_encode_op_t); |
| |
| ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE; |
| ps_encode_ip->pv_bufs = NULL; |
| ps_encode_ip->pv_mb_info = NULL; |
| ps_encode_ip->pv_pic_info = NULL; |
| ps_encode_ip->u4_mb_info_type = 0; |
| ps_encode_ip->u4_pic_info_type = 0; |
| ps_encode_op->s_out_buf.pv_buf = NULL; |
| |
| /* Initialize color formats */ |
| ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat; |
| source = NULL; |
| if ((inputBufferHeader != NULL) && inputBufferHeader->nFilledLen) { |
| source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; |
| |
| if (mInputDataIsMeta) { |
| uint8_t *conversionBuffer = NULL; |
| for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { |
| if (mConversionBuffersFree[i]) { |
| mConversionBuffersFree[i] = 0; |
| conversionBuffer = mConversionBuffers[i]; |
| break; |
| } |
| } |
| |
| if (NULL == conversionBuffer) { |
| ALOGE("No free buffers to hold conversion data"); |
| return OMX_ErrorUndefined; |
| } |
| |
| source = extractGraphicBuffer( |
| conversionBuffer, (mWidth * mHeight * 3 / 2), source, |
| inputBufferHeader->nFilledLen, mWidth, mHeight); |
| |
| if (source == NULL) { |
| ALOGE("Error in extractGraphicBuffer"); |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return OMX_ErrorUndefined; |
| } |
| } |
| ps_encode_ip->u4_is_last = 0; |
| ps_encode_ip->u4_timestamp_high = (inputBufferHeader->nTimeStamp) >> 32; |
| ps_encode_ip->u4_timestamp_low = (inputBufferHeader->nTimeStamp) & 0xFFFFFFFF; |
| } |
| else { |
| if (mSawInputEOS){ |
| ps_encode_ip->u4_is_last = 1; |
| } |
| memset(ps_inp_raw_buf, 0, sizeof(iv_raw_buf_t)); |
| ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat; |
| ps_inp_raw_buf->u4_size = sizeof(iv_raw_buf_t); |
| return OMX_ErrorNone; |
| } |
| |
| pu1_buf = (UWORD8 *)source; |
| switch (mIvVideoColorFormat) { |
| case IV_YUV_420P: |
| { |
| ps_inp_raw_buf->apv_bufs[0] = pu1_buf; |
| pu1_buf += (mStride) * mHeight; |
| ps_inp_raw_buf->apv_bufs[1] = pu1_buf; |
| pu1_buf += (mStride / 2) * mHeight / 2; |
| ps_inp_raw_buf->apv_bufs[2] = pu1_buf; |
| |
| ps_inp_raw_buf->au4_wd[0] = mWidth; |
| ps_inp_raw_buf->au4_wd[1] = mWidth / 2; |
| ps_inp_raw_buf->au4_wd[2] = mWidth / 2; |
| |
| ps_inp_raw_buf->au4_ht[0] = mHeight; |
| ps_inp_raw_buf->au4_ht[1] = mHeight / 2; |
| ps_inp_raw_buf->au4_ht[2] = mHeight / 2; |
| |
| ps_inp_raw_buf->au4_strd[0] = mStride; |
| ps_inp_raw_buf->au4_strd[1] = (mStride / 2); |
| ps_inp_raw_buf->au4_strd[2] = (mStride / 2); |
| break; |
| } |
| |
| case IV_YUV_422ILE: |
| { |
| ps_inp_raw_buf->apv_bufs[0] = pu1_buf; |
| ps_inp_raw_buf->au4_wd[0] = mWidth * 2; |
| ps_inp_raw_buf->au4_ht[0] = mHeight; |
| ps_inp_raw_buf->au4_strd[0] = mStride * 2; |
| break; |
| } |
| |
| case IV_YUV_420SP_UV: |
| case IV_YUV_420SP_VU: |
| default: |
| { |
| ps_inp_raw_buf->apv_bufs[0] = pu1_buf; |
| pu1_buf += (mStride) * mHeight; |
| ps_inp_raw_buf->apv_bufs[1] = pu1_buf; |
| |
| ps_inp_raw_buf->au4_wd[0] = mWidth; |
| ps_inp_raw_buf->au4_wd[1] = mWidth; |
| |
| ps_inp_raw_buf->au4_ht[0] = mHeight; |
| ps_inp_raw_buf->au4_ht[1] = mHeight / 2; |
| |
| ps_inp_raw_buf->au4_strd[0] = mStride; |
| ps_inp_raw_buf->au4_strd[1] = mStride; |
| break; |
| } |
| } |
| return OMX_ErrorNone; |
| } |
| |
| void SoftAVC::onQueueFilled(OMX_U32 portIndex) { |
| IV_STATUS_T status; |
| WORD32 timeDelay, timeTaken; |
| |
| UNUSED(portIndex); |
| |
| // Initialize encoder if not already initialized |
| if (mCodecCtx == NULL) { |
| if (OMX_ErrorNone != initEncoder()) { |
| ALOGE("Failed to initialize encoder"); |
| notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */); |
| return; |
| } |
| } |
| if (mSignalledError) { |
| return; |
| } |
| |
| List<BufferInfo *> &inQueue = getPortQueue(0); |
| List<BufferInfo *> &outQueue = getPortQueue(1); |
| |
| while (!mSawOutputEOS && !outQueue.empty()) { |
| |
| OMX_ERRORTYPE error; |
| ive_video_encode_ip_t s_encode_ip; |
| ive_video_encode_op_t s_encode_op; |
| BufferInfo *outputBufferInfo = *outQueue.begin(); |
| OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; |
| |
| BufferInfo *inputBufferInfo; |
| OMX_BUFFERHEADERTYPE *inputBufferHeader; |
| |
| if (mSawInputEOS) { |
| inputBufferHeader = NULL; |
| inputBufferInfo = NULL; |
| } else if (!inQueue.empty()) { |
| inputBufferInfo = *inQueue.begin(); |
| inputBufferHeader = inputBufferInfo->mHeader; |
| } else { |
| return; |
| } |
| |
| outputBufferHeader->nTimeStamp = 0; |
| outputBufferHeader->nFlags = 0; |
| outputBufferHeader->nOffset = 0; |
| outputBufferHeader->nFilledLen = 0; |
| outputBufferHeader->nOffset = 0; |
| |
| if (inputBufferHeader != NULL) { |
| outputBufferHeader->nFlags = inputBufferHeader->nFlags; |
| } |
| |
| uint8_t *outPtr = (uint8_t *)outputBufferHeader->pBuffer; |
| |
| if (!mSpsPpsHeaderReceived) { |
| error = setEncodeArgs(&s_encode_ip, &s_encode_op, NULL, outputBufferHeader); |
| if (error != OMX_ErrorNone) { |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return; |
| } |
| status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); |
| |
| if (IV_SUCCESS != status) { |
| ALOGE("Encode Frame failed = 0x%x\n", |
| s_encode_op.u4_error_code); |
| } else { |
| ALOGV("Bytes Generated in header %d\n", |
| s_encode_op.s_out_buf.u4_bytes); |
| } |
| |
| mSpsPpsHeaderReceived = true; |
| |
| outputBufferHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; |
| outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes; |
| if (inputBufferHeader != NULL) { |
| outputBufferHeader->nTimeStamp = inputBufferHeader->nTimeStamp; |
| } |
| |
| outQueue.erase(outQueue.begin()); |
| outputBufferInfo->mOwnedByUs = false; |
| |
| DUMP_TO_FILE( |
| mOutFile, outputBufferHeader->pBuffer, |
| outputBufferHeader->nFilledLen); |
| notifyFillBufferDone(outputBufferHeader); |
| |
| setEncMode(IVE_ENC_MODE_PICTURE); |
| return; |
| } |
| |
| if (mUpdateFlag) { |
| if (mUpdateFlag & kUpdateBitrate) { |
| setBitRate(); |
| } |
| if (mUpdateFlag & kRequestKeyFrame) { |
| setFrameType(IV_IDR_FRAME); |
| } |
| if (mUpdateFlag & kUpdateAIRMode) { |
| setAirParams(); |
| notify(OMX_EventPortSettingsChanged, kOutputPortIndex, |
| OMX_IndexConfigAndroidIntraRefresh, NULL); |
| } |
| mUpdateFlag = 0; |
| } |
| |
| if ((inputBufferHeader != NULL) |
| && (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS)) { |
| mSawInputEOS = true; |
| } |
| |
| /* In normal mode, store inputBufferInfo and this will be returned |
| when encoder consumes this input */ |
| if (!mInputDataIsMeta && (inputBufferInfo != NULL)) { |
| for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) { |
| if (NULL == mInputBufferInfo[i]) { |
| mInputBufferInfo[i] = inputBufferInfo; |
| break; |
| } |
| } |
| } |
| error = setEncodeArgs( |
| &s_encode_ip, &s_encode_op, inputBufferHeader, outputBufferHeader); |
| |
| if (error != OMX_ErrorNone) { |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return; |
| } |
| |
| DUMP_TO_FILE( |
| mInFile, s_encode_ip.s_inp_buf.apv_bufs[0], |
| (mHeight * mStride * 3 / 2)); |
| |
| GETTIME(&mTimeStart, NULL); |
| /* Compute time elapsed between end of previous decode() |
| * to start of current decode() */ |
| TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); |
| status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); |
| |
| if (IV_SUCCESS != status) { |
| ALOGE("Encode Frame failed = 0x%x\n", |
| s_encode_op.u4_error_code); |
| mSignalledError = true; |
| notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); |
| return; |
| } |
| |
| GETTIME(&mTimeEnd, NULL); |
| /* Compute time taken for decode() */ |
| TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); |
| |
| ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, |
| s_encode_op.s_out_buf.u4_bytes); |
| |
| /* In encoder frees up an input buffer, mark it as free */ |
| if (s_encode_op.s_inp_buf.apv_bufs[0] != NULL) { |
| if (mInputDataIsMeta) { |
| for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { |
| if (mConversionBuffers[i] == s_encode_op.s_inp_buf.apv_bufs[0]) { |
| mConversionBuffersFree[i] = 1; |
| break; |
| } |
| } |
| } else { |
| /* In normal mode, call EBD on inBuffeHeader that is freed by the codec */ |
| for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) { |
| uint8_t *buf = NULL; |
| OMX_BUFFERHEADERTYPE *bufHdr = NULL; |
| if (mInputBufferInfo[i] != NULL) { |
| bufHdr = mInputBufferInfo[i]->mHeader; |
| buf = bufHdr->pBuffer + bufHdr->nOffset; |
| } |
| if (s_encode_op.s_inp_buf.apv_bufs[0] == buf) { |
| mInputBufferInfo[i]->mOwnedByUs = false; |
| notifyEmptyBufferDone(bufHdr); |
| mInputBufferInfo[i] = NULL; |
| break; |
| } |
| } |
| } |
| } |
| |
| outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes; |
| |
| if (IV_IDR_FRAME == s_encode_op.u4_encoded_frame_type) { |
| outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; |
| } |
| |
| if (inputBufferHeader != NULL) { |
| inQueue.erase(inQueue.begin()); |
| |
| /* If in meta data, call EBD on input */ |
| /* In case of normal mode, EBD will be done once encoder |
| releases the input buffer */ |
| if (mInputDataIsMeta) { |
| inputBufferInfo->mOwnedByUs = false; |
| notifyEmptyBufferDone(inputBufferHeader); |
| } |
| } |
| |
| if (s_encode_op.u4_is_last) { |
| outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS; |
| mSawOutputEOS = true; |
| } else { |
| outputBufferHeader->nFlags &= ~OMX_BUFFERFLAG_EOS; |
| } |
| |
| if (outputBufferHeader->nFilledLen || s_encode_op.u4_is_last) { |
| outputBufferHeader->nTimeStamp = s_encode_op.u4_timestamp_high; |
| outputBufferHeader->nTimeStamp <<= 32; |
| outputBufferHeader->nTimeStamp |= s_encode_op.u4_timestamp_low; |
| outputBufferInfo->mOwnedByUs = false; |
| outQueue.erase(outQueue.begin()); |
| DUMP_TO_FILE(mOutFile, outputBufferHeader->pBuffer, |
| outputBufferHeader->nFilledLen); |
| notifyFillBufferDone(outputBufferHeader); |
| } |
| |
| if (s_encode_op.u4_is_last == 1) { |
| return; |
| } |
| } |
| return; |
| } |
| |
| void SoftAVC::onReset() { |
| SoftVideoEncoderOMXComponent::onReset(); |
| |
| if (releaseEncoder() != OMX_ErrorNone) { |
| ALOGW("releaseEncoder failed"); |
| } |
| } |
| |
| } // namespace android |
| |
| android::SoftOMXComponent *createSoftOMXComponent( |
| const char *name, const OMX_CALLBACKTYPE *callbacks, |
| OMX_PTR appData, OMX_COMPONENTTYPE **component) { |
| return new android::SoftAVC(name, callbacks, appData, component); |
| } |