diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp index 95eab84..cb9d246 100644 --- a/fuzzer/Android.bp +++ b/fuzzer/Android.bp @@ -20,3 +20,25 @@ cc_fuzz { componentid: 155276, }, } + +cc_fuzz { + name: "avc_enc_fuzzer", + host_supported: true, + srcs: [ + "avc_enc_fuzzer.cpp", + ], + static_libs: [ + "libavcenc", + "liblog", + ], + cflags: [ + "-Wall", + "-Werror", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 155276, + }, +} diff --git a/fuzzer/README.md b/fuzzer/README.md index a42e8b5..8e29ec6 100644 --- a/fuzzer/README.md +++ b/fuzzer/README.md @@ -64,6 +64,138 @@ To run on host $ $ANDROID_HOST_OUT/fuzz/avc_dec_fuzzer CORPUS_DIR ``` + +# Fuzzer for libavc encoder + +## Plugin Design Considerations +The fuzzer plugin for AVC is designed based on the understanding of the +codec and tries to achieve the following: + +##### Maximize code coverage +The configuration parameters are not hardcoded, but instead selected based on +incoming data. This ensures more code paths are reached by the fuzzer. + +AVC supports the following parameters: +1. Frame Width (parameter name: `u4_wd`) +2. Frame Height (parameter name: `u4_ht`) +3. Input color format (parameter name: `e_inp_color_fmt`) +4. Architecture type (parameter name: `e_arch`) +5. Rate control mode (parameter name: `e_rc_mode`) +6. Number of cores (parameter name: `u4_num_cores`) +7. Maximum B frames (parameter name: `u4_num_bframes`) +8. Encoder speed preset (parameter name: `u4_enc_speed_preset`) +9. enable constrained intra prediction (parameter name: `u4_constrained_intra_pred`) +10. enable intra 4x4 (parameter name: `u4_enable_intra_4x4`) +11. Qp for I frames (parameter name: `u4_i_qp`) +12. Qp for P frames (parameter name: `u4_p_qp`) +13. Qp for B frames (parameter name: `u4_b_qp`) +14. Target Bitrate (parameter name: `u4_target_bitrate`) +15. Intra refresh period in frames (parameter name: `u4_air_refresh_period`) +16. Enable half pel ME (parameter name: `u4_enable_hpel`) +17. Enable quarter pel ME (parameter name: `u4_enable_qpel`) +18. ME speed preset (parameter name: `u4_me_speed_preset`) +19. Adaptive intra refresh mode (parameter name: `e_air_mode`) +20. Disable deblock level (parameter name: `u4_disable_deblock_level`) +21. Max search range in X direction (parameter name: `u4_srch_rng_x`) +22. Max search range in Y direction (parameter name: `u4_srch_rng_y`) +23. I frame interval (parameter name: `u4_i_frm_interval`) +24. IDR frame interval (parameter name: `u4_idr_frm_interval`) +25. Enable mastering display color volume info (parameter name: `u1_sei_mdcv_params_present_flag`) +26. Enable content light level info (parameter name: `u1_sei_cll_params_present_flag`) +27. Enable ambient viewing environment info (parameter name: `u1_sei_ave_params_present_flag`) +28. Enable content color volume info (parameter name: `u1_sei_ccv_params_present_flag`) +29. Profile (parameter name: `e_profile`) +30. Enable aspect_ratio info (parameter name: `u1_aspect_ratio_info_present_flag`) +31. Enable NAL HRD parameters presence (parameter name: `u1_nal_hrd_parameters_present_flag`) +32. Enable VCL HRD parameters presence (parameter name: `u1_vcl_hrd_parameters_present_flag`) +33. Enable force IDR frame (parameter name: `mIsForceIdrEnabled`) +34. Enable dynamic bitrate change (parameter name: `mIsDynamicBitRateChangeEnabled`) +35. Enable dynamic framerate change (parameter name: `mIsDynamicFrameRateChangeEnabled`) +36. Force IDR frame number (parameter name: `mForceIdrInterval`) +37. Frame number for dynamic bitrate (parameter name: `mDynamicBitRateInterval`) +38. Frame number for dynamic framerate (parameter name: `mDynamicFrameRateInterval`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +| `u4_wd` | In the range `0 to 10239` | All the bits of 1st and 2nd byte of data | +| `u4_ht` | In the range `0 to 10239` | All the bits of 3rd and 4th byte of data | +| `e_inp_color_fmt` | 0. `IV_YUV_420P` 1. `IV_YUV_420SP_UV` 2. `IV_YUV_422ILE` 3. `IV_YUV_420SP_VU` | All the bits of 5th byte of data | +| `e_arch` | 0. `ARCH_ARM_NONEON` 1. `ARCH_NA` | bit 0 and 1 of 6th byte of data | +| `e_rc_mode` | 0. `IVE_RC_NONE` 1. `IVE_RC_STORAGE` 2. `IVE_RC_CBR_NON_LOW_DELAY` 3. `IVE_RC_CBR_LOW_DELAY` | All the bits of 7th byte of data modulus 4 | +| `u4_num_cores` | 0. `0` 1. `1` 2. `2` 3. `3`| bit 0 and 1 of 8th byte of data | +| `u4_num_bframes` | In the range `0 to 7` | bit 0, 1 and 2 of 9th byte of data | +| `u4_enc_speed_preset` | 0. `IVE_CONFIG` 1. `IVE_SLOWEST` 2. `IVE_NORMAL` 3. `IVE_FAST` 4. `IVE_HIGH_SPEED` 5. `IVE_FASTEST` | All the bits of 10th byte of data modulus 6 | +| `u4_constrained_intra_pred` | 0. `0` 1. `1` | bit 0 of 11th byte of data | +| `u4_enable_intra_4x4` | 0. `0` 1. `1` | bit 0 of 12th byte of data | +| `u4_i_qp` | In the range `4 to 51` | All the bits of 13th byte of data | +| `u4_p_qp` | In the range `4 to 51` | All the bits of 14th byte of data | +| `u4_b_qp` | In the range `4 to 51` | All the bits of 15th byte of data | +| `u4_target_bitrate` | In the range `0 to 500000000` | All the bits of 16th and 17th byte of data | +| `u4_target_bitrate` | In the range `0 to 255` | All the bits of 18th byte of data | +| `u4_air_refresh_period` | In the range `1 to 256` | All the bits of 19th byte of data | +| `u4_air_refresh_period` | In the range `1 to 256` | All the bits of 19th byte of data | +| `u4_enable_hpel` | 0. `0` 1. `1` | bit 0 of 20th byte of data | +| `u4_enable_qpel` | 0. `0` 1. `1` | bit 0 of 21st byte of data | +| `u4_me_speed_preset` | 0. `0` 1. `50` 2. `75` 3. `100` | All the bits of 22nd byte of data modulus 4 | +| `e_air_mode` | 0. `IVE_AIR_MODE_NONE` 1. `IVE_AIR_MODE_CYCLIC` 2. `IVE_AIR_MODE_RANDOM` | All the bits of 23rd byte of data modulus 3 | +| `u4_disable_deblock_level` | 0. `0` 1. `1` 2. `2` 3. `3` | bit 0 and 1 of 24th byte of data | +| `u4_srch_rng_x` | In the range `0 to 255` | All the bits of 25th byte of data | +| `u4_srch_rng_y` | In the range `0 to 255`| All the bits of 26th byte of data | +| `u4_i_frm_interval` | In the range `1 to 256` | All the bits of 27th byte of data | +| `u4_idr_frm_interval` | In the range `1 to 256` | All the bits of 28th byte of data | +| `u1_sei_mdcv_params_present_flag` | 0. `0` 1. `1` | bit 0 of 29th byte of data | +| `u1_sei_cll_params_present_flag` | 0. `0` 1. `1` | bit 0 of 30th byte of data | +| `u1_sei_ave_params_present_flag` | 0. `0` 1. `1` | bit 0 of 31st byte of data | +| `u1_sei_ccv_params_present_flag` | 0. `0` 1. `1` | bit 0 of 32nd byte of data | +| `e_profile` | 0. `IV_PROFILE_BASE` 1. `IV_PROFILE_MAIN` | bit 0 and 1 of 33th byte of data modulus 2 | +| `u1_aspect_ratio_info_present_flag` | 0. `0` 1. `1` | bit 0 of 34th byte of data | +| `u1_nal_hrd_parameters_present_flag` | 0. `0` 1. `1` | bit 0 of 35th byte of data | +| `u1_vcl_hrd_parameters_present_flag` | 0. `0` 1. `1` | bit 0 of 36th byte of data | +| `mIsForceIdrEnabled` | 0. `0` 1. `1` | bit 0 of 37th byte of data | +| `mIsDynamicBitRateChangeEnabled` | 0. `0` 1. `1` | bit 0 of 38th byte of data | +| `mIsDynamicFrameRateChangeEnabled` | 0. `0` 1. `1` | bit 0 of 39th byte of data | +| `mForceIdrInterval` | In the range `0 to 7` | bit 0, 1 and 2 of 40th byte of data | +| `mDynamicBitRateInterval` | In the range `0 to 7` | bit 0, 1 and 2 of 41st byte of data | +| `mDynamicFrameRateInterval` | In the range `0 to 7` | bit 0, 1 and 2 of 42nd byte of data | + +This also ensures that the plugin is always deterministic for any given input. + +##### Maximize utilization of input data +The plugin feeds the entire input data to the codec using a loop. +If the encode operation was successful, the input is advanced by the frame size. +If the encode operation was un-successful, the input is still advanced by frame size so +that the fuzzer can proceed to feed the next frame. + +This ensures that the plugin tolerates any kind of input (empty, huge, +malformed, etc) and doesnt `exit()` on any input and thereby increasing the +chance of identifying vulnerabilities. + +## Build + +This describes steps to build avc_enc_fuzzer binary. + +### Android + +#### Steps to build +Build the fuzzer +``` + $ mm -j$(nproc) avc_enc_fuzzer +``` + +#### Steps to run +Create a directory CORPUS_DIR and copy some yuv files to that folder +Push this directory to device. + +To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/avc_enc_fuzzer/avc_enc_fuzzer CORPUS_DIR +``` +To run on host +``` + $ $ANDROID_HOST_OUT/fuzz/x86_64/avc_enc_fuzzer/avc_enc_fuzzer CORPUS_DIR +``` + ## References: * http://llvm.org/docs/LibFuzzer.html * https://github.com/google/oss-fuzz diff --git a/fuzzer/avc_enc_fuzzer.cpp b/fuzzer/avc_enc_fuzzer.cpp new file mode 100644 index 0000000..e01f6a5 --- /dev/null +++ b/fuzzer/avc_enc_fuzzer.cpp @@ -0,0 +1,1001 @@ +/****************************************************************************** + * + * Copyright (C) 2020 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. + * + ***************************************************************************** + * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore + */ +#include +#include + +#include "ih264_defs.h" +#include "ih264_typedefs.h" +#include "ih264e.h" +#include "ih264e_error.h" +#define ive_api_function ih264e_api_function + +constexpr uint32_t kHeaderLength = 0x800; +constexpr int16_t kCompressionRatio = 1; + +constexpr int kMeSpeedPreset[] = {0, 50, 75, 100}; +constexpr IVE_AIR_MODE_T kAirMode[] = {IVE_AIR_MODE_NONE, IVE_AIR_MODE_CYCLIC, IVE_AIR_MODE_RANDOM}; +constexpr IVE_SPEED_CONFIG kEncSpeed[] = {IVE_CONFIG, IVE_SLOWEST, IVE_NORMAL, + IVE_FAST, IVE_HIGH_SPEED, IVE_FASTEST}; +constexpr IV_PROFILE_T kProfle[] = {IV_PROFILE_BASE, IV_PROFILE_MAIN}; +constexpr IVE_RC_MODE_T kRCMode[] = {IVE_RC_NONE, IVE_RC_STORAGE, IVE_RC_CBR_NON_LOW_DELAY, + IVE_RC_CBR_LOW_DELAY}; +constexpr IV_COLOR_FORMAT_T kSupportedColorFormats[] = {IV_YUV_420P, IV_YUV_420SP_UV, IV_YUV_422ILE, + IV_YUV_420SP_VU}; + +constexpr size_t kAirModeNum = std::size(kAirMode); +constexpr size_t kEncSpeedNum = std::size(kEncSpeed); +constexpr size_t kMeSpeedPresetNum = std::size(kMeSpeedPreset); +constexpr size_t kProfleNum = std::size(kProfle); +constexpr size_t kRCModeNum = std::size(kRCMode); +constexpr size_t kSupportedColorFormatsNum = std::size(kSupportedColorFormats); +constexpr size_t kMinQP = 4; +constexpr size_t kMaxWidth = 10240; +constexpr size_t kMaxHeight = 10240; +constexpr size_t kMaxBitrate = 500000000; + +enum { + IDX_WD_BYTE_1, + IDX_WD_BYTE_2, + IDX_HT_BYTE_1, + IDX_HT_BYTE_2, + IDX_COLOR_FORMAT, + IDX_ARCH_TYPE, + IDX_RC_MODE, + IDX_NUM_CORES, + IDX_NUM_B_FRAMES, + IDX_ENC_SPEED, + IDX_CONSTRAINED_INTRA_FLAG, + IDX_INTRA_4x4, + IDX_I_FRAME_QP, + IDX_P_FRAME_QP, + IDX_B_FRAME_QP, + IDX_BITRATE_BYTE_1, + IDX_BITRATE_BYTE_2, + IDX_FRAME_RATE, + IDX_INTRA_REFRESH, + IDX_ENABLE_HALF_PEL, + IDX_ENABLE_Q_PEL, + IDX_ME_SPEED_PRESET, + IDX_AIR_MODE, + IDX_DISABLE_DEBLOCK_LEVEL, + IDX_SEARCH_RANGE_X, + IDX_SEARCH_RANGE_Y, + IDX_I_INTERVAL, + IDX_IDR_INTERVAL, + IDX_SEI_MDCV_FLAG, + IDX_SEI_CLL_FLAG, + IDX_SEI_AVE_FLAG, + IDX_SEI_CCV_FLAG, + IDX_PROFILE, + IDX_ASPECT_RATIO_FLAG, + IDX_NAL_HRD_FLAG, + IDX_VCL_HRD_FLAG, + IDX_ENABLE_FORCE_IDR, + IDX_ENABLE_DYNAMIC_BITRATE, + IDX_ENABLE_DYNAMIC_FRAME_RATE, + IDX_FORCE_IDR_INTERVAL, + IDX_DYNAMIC_BITRATE_INTERVAL, + IDX_DYNAMIC_FRAME_RATE_INTERVAL, + IDX_LAST +}; + +class Codec { + public: + Codec() = default; + ~Codec() { deInitEncoder(); } + bool initEncoder(const uint8_t **pdata, size_t *psize); + void encodeFrames(const uint8_t *data, size_t size); + void deInitEncoder(); + + private: + void setEncParams(iv_raw_buf_t *psInpRawBuf, const uint8_t *data); + void setFrameType(IV_PICTURE_CODING_TYPE_T eFrameType); + void setQp(); + void setEncMode(IVE_ENC_MODE_T eEncMode); + void setDimensions(); + void setNumCores(); + void setFrameRate(); + void setIpeParams(); + void setBitRate(); + void setAirParams(); + void setMeParams(); + void setGopParams(); + void setProfileParams(); + void setDeblockParams(); + void setVbvParams(); + void setDefault(); + void setVuiParams(); + void getBufInfo(); + void setSeiMdcvParams(); + void setSeiCllParams(); + void setSeiAveParams(); + void setSeiCcvParams(); + void logVersion(); + bool mHalfPelEnable = 1; + bool mQPelEnable = 1; + bool mIntra4x4 = 0; + bool mEnableFastSad = 0; + bool mEnableAltRef = 0; + bool mConstrainedIntraFlag = 0; + bool mSeiCllFlag = 1; + bool mSeiAveFlag = 1; + bool mSeiCcvFlag = 1; + bool mSeiMdcvFlag = 1; + bool mAspectRatioFlag = 0; + bool mNalHrdFlag = 0; + bool mVclHrdFlag = 0; + bool mIsForceIdrEnabled = false; + bool mIsDynamicBitRateChangeEnabled = false; + bool mIsDynamicFrameRateChangeEnabled = false; + uint32_t mWidth = 2560; + uint32_t mHeight = 2560; + uint32_t mAvcEncLevel = 41; + uint32_t mNumMemRecords = 0; + uint32_t mNumCores = 1; + uint32_t mBframes = 0; + uint32_t mSliceParam = 256; + uint32_t mMeSpeedPreset = 100; + uint32_t mIInterval = 60; + uint32_t mIDRInterval = 60; + uint32_t mDisableDeblockLevel = 0; + uint32_t m_I_QP = 22; + uint32_t m_P_QP = 28; + uint32_t m_B_QP = 22; + uint32_t mIntraRefresh = 30; + uint32_t mSearchRangeX = 64; + uint32_t mSearchRangeY = 48; + uint32_t mForceIdrInterval = 0; // in number of frames + uint32_t mDynamicBitRateInterval = 0; // in number of frames + uint32_t mDynamicFrameRateInterval = 0; // in number of frames + uint64_t mBitrate = 6000000; + float mFrameRate = 30; + iv_obj_t *mCodecCtx = nullptr; + iv_mem_rec_t *mMemRecords = nullptr; + IVE_AIR_MODE_T mAirMode = IVE_AIR_MODE_NONE; + IVE_SPEED_CONFIG mEncSpeed = IVE_NORMAL; + IVE_RC_MODE_T mRCMode = IVE_RC_STORAGE; + IV_ARCH_T mArch = ARCH_NA; + IVE_SLICE_MODE_T mSliceMode = IVE_SLICE_MODE_NONE; + IV_COLOR_FORMAT_T mIvVideoColorFormat = IV_YUV_420P; + IV_COLOR_FORMAT_T mReconFormat = IV_YUV_420P; + IV_PROFILE_T mProfile = IV_PROFILE_BASE; +}; + +bool Codec::initEncoder(const uint8_t **pdata, size_t *psize) { + uint8_t *data = const_cast(*pdata); + mWidth = ((data[IDX_WD_BYTE_1] << 8) | data[IDX_WD_BYTE_2]) % kMaxWidth; + mHeight = ((data[IDX_HT_BYTE_1] << 8) | data[IDX_HT_BYTE_2]) % kMaxHeight; + + mIvVideoColorFormat = + kSupportedColorFormats[data[IDX_COLOR_FORMAT] % kSupportedColorFormatsNum]; + mArch = ((data[IDX_ARCH_TYPE] & 0x03) == 0x00) ? ARCH_ARM_NONEON : ARCH_NA; + mRCMode = kRCMode[data[IDX_RC_MODE] % kRCModeNum]; + mNumCores = (data[IDX_NUM_CORES] & 0x07) + 1; + mBframes = data[IDX_NUM_B_FRAMES] & 0x07; + mEncSpeed = kEncSpeed[data[IDX_ENC_SPEED] % kEncSpeedNum]; + mConstrainedIntraFlag = data[IDX_CONSTRAINED_INTRA_FLAG] & 0x01; + mIntra4x4 = data[IDX_INTRA_4x4] & 0x01; + m_I_QP = (data[IDX_I_FRAME_QP] % (MAX_H264_QP - kMinQP)) + kMinQP; + m_P_QP = (data[IDX_P_FRAME_QP] % (MAX_H264_QP - kMinQP)) + kMinQP; + m_B_QP = (data[IDX_B_FRAME_QP] % (MAX_H264_QP - kMinQP)) + kMinQP; + mBitrate = (((data[IDX_BITRATE_BYTE_1] << 8) | data[IDX_BITRATE_BYTE_2]) * 1000) % kMaxBitrate; + mFrameRate = data[IDX_FRAME_RATE]; + mIntraRefresh = data[IDX_INTRA_REFRESH] + 1; + mHalfPelEnable = data[IDX_ENABLE_HALF_PEL] & 0x01; + mQPelEnable = data[IDX_ENABLE_Q_PEL] & 0x01; + mMeSpeedPreset = kMeSpeedPreset[data[IDX_ME_SPEED_PRESET] % kMeSpeedPresetNum]; + mAirMode = kAirMode[data[IDX_AIR_MODE] % kAirModeNum]; + mDisableDeblockLevel = data[IDX_DISABLE_DEBLOCK_LEVEL] & 0x03; + mSearchRangeX = data[IDX_SEARCH_RANGE_X]; + mSearchRangeY = data[IDX_SEARCH_RANGE_Y]; + mIInterval = data[IDX_I_INTERVAL] + 1; + mIDRInterval = data[IDX_IDR_INTERVAL] + 1; + mSeiMdcvFlag = data[IDX_SEI_MDCV_FLAG] & 0x01; + mSeiCllFlag = data[IDX_SEI_CLL_FLAG] & 0x01; + mSeiAveFlag = data[IDX_SEI_AVE_FLAG] & 0x01; + mSeiCcvFlag = data[IDX_SEI_CCV_FLAG] & 0x01; + mProfile = kProfle[data[IDX_PROFILE] % kProfleNum]; + mAspectRatioFlag = data[IDX_ASPECT_RATIO_FLAG] & 0x01; + mNalHrdFlag = data[IDX_NAL_HRD_FLAG] & 0x01; + mVclHrdFlag = data[IDX_VCL_HRD_FLAG] & 0x01; + mIsForceIdrEnabled = data[IDX_ENABLE_FORCE_IDR] & 0x01; + mIsDynamicBitRateChangeEnabled = data[IDX_ENABLE_DYNAMIC_BITRATE] & 0x01; + mIsDynamicFrameRateChangeEnabled = data[IDX_ENABLE_DYNAMIC_FRAME_RATE] & 0x01; + mForceIdrInterval = data[IDX_FORCE_IDR_INTERVAL] & 0x07; + mDynamicBitRateInterval = data[IDX_DYNAMIC_BITRATE_INTERVAL] & 0x07; + mDynamicFrameRateInterval = data[IDX_DYNAMIC_FRAME_RATE_INTERVAL] & 0x07; + + /* Getting Number of MemRecords */ + iv_num_mem_rec_ip_t sNumMemRecIp{}; + iv_num_mem_rec_op_t sNumMemRecOp{}; + + sNumMemRecIp.u4_size = sizeof(iv_num_mem_rec_ip_t); + sNumMemRecOp.u4_size = sizeof(iv_num_mem_rec_op_t); + sNumMemRecIp.e_cmd = IV_CMD_GET_NUM_MEM_REC; + + if (IV_SUCCESS != ive_api_function(nullptr, &sNumMemRecIp, &sNumMemRecOp)) { + return false; + } + mNumMemRecords = sNumMemRecOp.u4_num_mem_rec; + mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t)); + if (!mMemRecords) { + return false; + } + iv_mem_rec_t *psMemRec; + psMemRec = mMemRecords; + for (size_t i = 0; i < mNumMemRecords; ++i) { + psMemRec->u4_size = sizeof(iv_mem_rec_t); + psMemRec->pv_base = nullptr; + psMemRec->u4_mem_size = 0; + psMemRec->u4_mem_alignment = 0; + psMemRec->e_mem_type = IV_NA_MEM_TYPE; + ++psMemRec; + } + + /* Getting MemRecords Attributes */ + iv_fill_mem_rec_ip_t sFillMemRecIp{}; + iv_fill_mem_rec_op_t sFillMemRecOp{}; + + sFillMemRecIp.u4_size = sizeof(iv_fill_mem_rec_ip_t); + sFillMemRecOp.u4_size = sizeof(iv_fill_mem_rec_op_t); + + sFillMemRecIp.e_cmd = IV_CMD_FILL_NUM_MEM_REC; + sFillMemRecIp.ps_mem_rec = mMemRecords; + sFillMemRecIp.u4_num_mem_rec = mNumMemRecords; + sFillMemRecIp.u4_max_wd = mWidth; + sFillMemRecIp.u4_max_ht = mHeight; + sFillMemRecIp.u4_max_level = mAvcEncLevel; + sFillMemRecIp.e_color_format = IV_YUV_420SP_VU; + sFillMemRecIp.u4_max_ref_cnt = 2; + sFillMemRecIp.u4_max_reorder_cnt = 0; + sFillMemRecIp.u4_max_srch_rng_x = 256; + sFillMemRecIp.u4_max_srch_rng_y = 256; + + if (IV_SUCCESS != ive_api_function(nullptr, &sFillMemRecIp, &sFillMemRecOp)) { + return false; + } + /* Allocating Memory for Mem Records */ + psMemRec = mMemRecords; + for (size_t i = 0; i < mNumMemRecords; ++i) { + posix_memalign(&psMemRec->pv_base, psMemRec->u4_mem_alignment, psMemRec->u4_mem_size); + if (!psMemRec->pv_base) { + return false; + } + ++psMemRec; + } + + /* Codec Instance Creation */ + ive_init_ip_t sInitIp{}; + ive_init_op_t sInitOp{}; + + mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; + mCodecCtx->u4_size = sizeof(iv_obj_t); + mCodecCtx->pv_fxns = (void *)ive_api_function; + + sInitIp.u4_size = sizeof(ive_init_ip_t); + sInitOp.u4_size = sizeof(ive_init_op_t); + + sInitIp.e_cmd = IV_CMD_INIT; + sInitIp.u4_num_mem_rec = mNumMemRecords; + sInitIp.ps_mem_rec = mMemRecords; + sInitIp.u4_max_wd = mWidth; + sInitIp.u4_max_ht = mHeight; + sInitIp.u4_max_ref_cnt = 2; + sInitIp.u4_max_reorder_cnt = 0; + sInitIp.u4_max_level = mAvcEncLevel; + sInitIp.e_inp_color_fmt = mIvVideoColorFormat; + sInitIp.u4_enable_recon = 0; + sInitIp.e_recon_color_fmt = mReconFormat; + sInitIp.e_rc_mode = mRCMode; + sInitIp.u4_max_framerate = 120000; + sInitIp.u4_max_bitrate = 240000000; + sInitIp.u4_num_bframes = mBframes; + sInitIp.e_content_type = IV_PROGRESSIVE; + sInitIp.u4_max_srch_rng_x = 256; + sInitIp.u4_max_srch_rng_y = 256; + sInitIp.e_slice_mode = mSliceMode; + sInitIp.u4_slice_param = mSliceParam; + sInitIp.e_arch = mArch; + sInitIp.e_soc = SOC_GENERIC; + + if (IV_SUCCESS != ive_api_function(mCodecCtx, &sInitIp, &sInitOp)) { + return false; + } + + logVersion(); + setDefault(); + getBufInfo(); + setNumCores(); + setDimensions(); + setFrameRate(); + setIpeParams(); + setBitRate(); + setQp(); + setAirParams(); + setVbvParams(); + setMeParams(); + setGopParams(); + setDeblockParams(); + setVuiParams(); + setSeiMdcvParams(); + setSeiCllParams(); + setSeiAveParams(); + setSeiCcvParams(); + setProfileParams(); + setEncMode(IVE_ENC_MODE_HEADER); + + *pdata += IDX_LAST; + *psize -= IDX_LAST; + return true; +} + +void Codec::setDimensions() { + ive_ctl_set_dimensions_ip_t sDimensionsIp{}; + ive_ctl_set_dimensions_op_t sDimensionsOp{}; + + sDimensionsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sDimensionsIp.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS; + sDimensionsIp.u4_ht = mHeight; + sDimensionsIp.u4_wd = mWidth; + + sDimensionsIp.u4_timestamp_high = -1; + sDimensionsIp.u4_timestamp_low = -1; + + sDimensionsIp.u4_size = sizeof(ive_ctl_set_dimensions_ip_t); + sDimensionsOp.u4_size = sizeof(ive_ctl_set_dimensions_op_t); + + ive_api_function(mCodecCtx, &sDimensionsIp, &sDimensionsOp); + return; +} + +void Codec::setNumCores() { + ive_ctl_set_num_cores_ip_t sNumCoresIp{}; + ive_ctl_set_num_cores_op_t sNumCoresOp{}; + + sNumCoresIp.e_cmd = IVE_CMD_VIDEO_CTL; + sNumCoresIp.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES; + sNumCoresIp.u4_num_cores = mNumCores; + + sNumCoresIp.u4_timestamp_high = -1; + sNumCoresIp.u4_timestamp_low = -1; + + sNumCoresIp.u4_size = sizeof(ive_ctl_set_num_cores_ip_t); + sNumCoresOp.u4_size = sizeof(ive_ctl_set_num_cores_op_t); + + ive_api_function(mCodecCtx, (void *)&sNumCoresIp, (void *)&sNumCoresOp); + return; +} + +void Codec::setDefault() { + ive_ctl_setdefault_ip_t sDefaultIp{}; + ive_ctl_setdefault_op_t sDefaultOp{}; + + sDefaultIp.e_cmd = IVE_CMD_VIDEO_CTL; + sDefaultIp.e_sub_cmd = IVE_CMD_CTL_SETDEFAULT; + + sDefaultIp.u4_timestamp_high = -1; + sDefaultIp.u4_timestamp_low = -1; + + sDefaultIp.u4_size = sizeof(ive_ctl_setdefault_ip_t); + sDefaultOp.u4_size = sizeof(ive_ctl_setdefault_op_t); + + ive_api_function(mCodecCtx, &sDefaultIp, &sDefaultOp); + return; +} + +void Codec::getBufInfo() { + ih264e_ctl_getbufinfo_ip_t sGetBufInfoIp{}; + ih264e_ctl_getbufinfo_op_t sGetBufInfoOp{}; + + sGetBufInfoIp.s_ive_ip.u4_size = sizeof(ih264e_ctl_getbufinfo_ip_t); + sGetBufInfoOp.s_ive_op.u4_size = sizeof(ih264e_ctl_getbufinfo_op_t); + + sGetBufInfoIp.s_ive_ip.e_cmd = IVE_CMD_VIDEO_CTL; + sGetBufInfoIp.s_ive_ip.e_sub_cmd = IVE_CMD_CTL_GETBUFINFO; + sGetBufInfoIp.s_ive_ip.u4_max_ht = mHeight; + sGetBufInfoIp.s_ive_ip.u4_max_wd = mWidth; + sGetBufInfoIp.s_ive_ip.e_inp_color_fmt = mIvVideoColorFormat; + + ih264e_api_function(mCodecCtx, &sGetBufInfoIp, &sGetBufInfoOp); + return; +} + +void Codec::setFrameRate() { + ive_ctl_set_frame_rate_ip_t sFrameRateIp{}; + ive_ctl_set_frame_rate_op_t sFrameRateOp{}; + + sFrameRateIp.e_cmd = IVE_CMD_VIDEO_CTL; + sFrameRateIp.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE; + sFrameRateIp.u4_src_frame_rate = mFrameRate; + sFrameRateIp.u4_tgt_frame_rate = mFrameRate; + + sFrameRateIp.u4_timestamp_high = -1; + sFrameRateIp.u4_timestamp_low = -1; + + sFrameRateIp.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t); + sFrameRateOp.u4_size = sizeof(ive_ctl_set_frame_rate_op_t); + + ive_api_function(mCodecCtx, &sFrameRateIp, &sFrameRateOp); + return; +} + +void Codec::setIpeParams() { + ive_ctl_set_ipe_params_ip_t sIpeParamsIp{}; + ive_ctl_set_ipe_params_op_t sIpeParamsOp{}; + + sIpeParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sIpeParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS; + sIpeParamsIp.u4_enable_intra_4x4 = mIntra4x4; + sIpeParamsIp.u4_enc_speed_preset = mEncSpeed; + sIpeParamsIp.u4_constrained_intra_pred = mConstrainedIntraFlag; + + sIpeParamsIp.u4_timestamp_high = -1; + sIpeParamsIp.u4_timestamp_low = -1; + + sIpeParamsIp.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t); + sIpeParamsOp.u4_size = sizeof(ive_ctl_set_ipe_params_op_t); + + ive_api_function(mCodecCtx, &sIpeParamsIp, &sIpeParamsOp); + return; +} + +void Codec::setBitRate() { + ive_ctl_set_bitrate_ip_t sBitrateIp{}; + ive_ctl_set_bitrate_op_t sBitrateOp{}; + + sBitrateIp.e_cmd = IVE_CMD_VIDEO_CTL; + sBitrateIp.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE; + sBitrateIp.u4_target_bitrate = mBitrate; + + sBitrateIp.u4_timestamp_high = -1; + sBitrateIp.u4_timestamp_low = -1; + + sBitrateIp.u4_size = sizeof(ive_ctl_set_bitrate_ip_t); + sBitrateOp.u4_size = sizeof(ive_ctl_set_bitrate_op_t); + + ive_api_function(mCodecCtx, &sBitrateIp, &sBitrateOp); + return; +} + +void Codec::setFrameType(IV_PICTURE_CODING_TYPE_T eFrameType) { + ive_ctl_set_frame_type_ip_t sFrameTypeIp{}; + ive_ctl_set_frame_type_op_t sFrameTypeOp{}; + + sFrameTypeIp.e_cmd = IVE_CMD_VIDEO_CTL; + sFrameTypeIp.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE; + sFrameTypeIp.e_frame_type = eFrameType; + + sFrameTypeIp.u4_timestamp_high = -1; + sFrameTypeIp.u4_timestamp_low = -1; + + sFrameTypeIp.u4_size = sizeof(ive_ctl_set_frame_type_ip_t); + sFrameTypeOp.u4_size = sizeof(ive_ctl_set_frame_type_op_t); + + ive_api_function(mCodecCtx, &sFrameTypeIp, &sFrameTypeOp); + return; +} + +void Codec::setQp() { + ive_ctl_set_qp_ip_t s_QpIp{}; + ive_ctl_set_qp_op_t s_QpOp{}; + + s_QpIp.e_cmd = IVE_CMD_VIDEO_CTL; + s_QpIp.e_sub_cmd = IVE_CMD_CTL_SET_QP; + + s_QpIp.u4_i_qp = m_I_QP; + s_QpIp.u4_i_qp_max = MAX_H264_QP; + s_QpIp.u4_i_qp_min = kMinQP; + + s_QpIp.u4_p_qp = m_P_QP; + s_QpIp.u4_p_qp_max = MAX_H264_QP; + s_QpIp.u4_p_qp_min = kMinQP; + + s_QpIp.u4_b_qp = m_B_QP; + s_QpIp.u4_b_qp_max = MAX_H264_QP; + s_QpIp.u4_b_qp_min = kMinQP; + + s_QpIp.u4_timestamp_high = -1; + s_QpIp.u4_timestamp_low = -1; + + s_QpIp.u4_size = sizeof(ive_ctl_set_qp_ip_t); + s_QpOp.u4_size = sizeof(ive_ctl_set_qp_op_t); + + ive_api_function(mCodecCtx, &s_QpIp, &s_QpOp); + return; +} + +void Codec::setEncMode(IVE_ENC_MODE_T eEncMode) { + ive_ctl_set_enc_mode_ip_t sEncModeIp{}; + ive_ctl_set_enc_mode_op_t sEncModeOp{}; + + sEncModeIp.e_cmd = IVE_CMD_VIDEO_CTL; + sEncModeIp.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE; + sEncModeIp.e_enc_mode = eEncMode; + + sEncModeIp.u4_timestamp_high = -1; + sEncModeIp.u4_timestamp_low = -1; + + sEncModeIp.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t); + sEncModeOp.u4_size = sizeof(ive_ctl_set_enc_mode_op_t); + + ive_api_function(mCodecCtx, &sEncModeIp, &sEncModeOp); + return; +} + +void Codec::setVbvParams() { + ive_ctl_set_vbv_params_ip_t sVbvIp{}; + ive_ctl_set_vbv_params_op_t sVbvOp{}; + + sVbvIp.e_cmd = IVE_CMD_VIDEO_CTL; + sVbvIp.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS; + sVbvIp.u4_vbv_buf_size = 0; + sVbvIp.u4_vbv_buffer_delay = 1000; + + sVbvIp.u4_timestamp_high = -1; + sVbvIp.u4_timestamp_low = -1; + + sVbvIp.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t); + sVbvOp.u4_size = sizeof(ive_ctl_set_vbv_params_op_t); + + ive_api_function(mCodecCtx, &sVbvIp, &sVbvOp); + return; +} + +void Codec::setAirParams() { + ive_ctl_set_air_params_ip_t sAirIp{}; + ive_ctl_set_air_params_op_t sAirOp{}; + + sAirIp.e_cmd = IVE_CMD_VIDEO_CTL; + sAirIp.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS; + sAirIp.e_air_mode = mAirMode; + sAirIp.u4_air_refresh_period = mIntraRefresh; + + sAirIp.u4_timestamp_high = -1; + sAirIp.u4_timestamp_low = -1; + + sAirIp.u4_size = sizeof(ive_ctl_set_air_params_ip_t); + sAirOp.u4_size = sizeof(ive_ctl_set_air_params_op_t); + + ive_api_function(mCodecCtx, &sAirIp, &sAirOp); + return; +} + +void Codec::setMeParams() { + ive_ctl_set_me_params_ip_t sMeParamsIp{}; + ive_ctl_set_me_params_op_t sMeParamsOp{}; + + sMeParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sMeParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS; + sMeParamsIp.u4_enable_fast_sad = mEnableFastSad; + sMeParamsIp.u4_enable_alt_ref = mEnableAltRef; + + sMeParamsIp.u4_enable_hpel = mHalfPelEnable; + sMeParamsIp.u4_enable_qpel = mQPelEnable; + sMeParamsIp.u4_me_speed_preset = mMeSpeedPreset; + sMeParamsIp.u4_srch_rng_x = mSearchRangeX; + sMeParamsIp.u4_srch_rng_y = mSearchRangeY; + + sMeParamsIp.u4_timestamp_high = -1; + sMeParamsIp.u4_timestamp_low = -1; + + sMeParamsIp.u4_size = sizeof(ive_ctl_set_me_params_ip_t); + sMeParamsOp.u4_size = sizeof(ive_ctl_set_me_params_op_t); + + ive_api_function(mCodecCtx, &sMeParamsIp, &sMeParamsOp); + return; +} + +void Codec::setGopParams() { + ive_ctl_set_gop_params_ip_t sGopParamsIp{}; + ive_ctl_set_gop_params_op_t sGopParamsOp{}; + + sGopParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sGopParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS; + + sGopParamsIp.u4_i_frm_interval = mIInterval; + sGopParamsIp.u4_idr_frm_interval = mIDRInterval; + + sGopParamsIp.u4_timestamp_high = -1; + sGopParamsIp.u4_timestamp_low = -1; + + sGopParamsIp.u4_size = sizeof(ive_ctl_set_gop_params_ip_t); + sGopParamsOp.u4_size = sizeof(ive_ctl_set_gop_params_op_t); + + ive_api_function(mCodecCtx, &sGopParamsIp, &sGopParamsOp); + return; +} + +void Codec::setProfileParams() { + ive_ctl_set_profile_params_ip_t sProfileParamsIp{}; + ive_ctl_set_profile_params_op_t sProfileParamsOp{}; + + sProfileParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sProfileParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS; + + sProfileParamsIp.e_profile = mProfile; + if (sProfileParamsIp.e_profile == IV_PROFILE_BASE) { + sProfileParamsIp.u4_entropy_coding_mode = 0; + } else { + sProfileParamsIp.u4_entropy_coding_mode = 1; + } + sProfileParamsIp.u4_timestamp_high = -1; + sProfileParamsIp.u4_timestamp_low = -1; + + sProfileParamsIp.u4_size = sizeof(ive_ctl_set_profile_params_ip_t); + sProfileParamsOp.u4_size = sizeof(ive_ctl_set_profile_params_op_t); + + ive_api_function(mCodecCtx, &sProfileParamsIp, &sProfileParamsOp); + return; +} + +void Codec::setDeblockParams() { + ive_ctl_set_deblock_params_ip_t sDeblockParamsIp{}; + ive_ctl_set_deblock_params_op_t sDeblockParamsOp{}; + + sDeblockParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sDeblockParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS; + + sDeblockParamsIp.u4_disable_deblock_level = mDisableDeblockLevel; + + sDeblockParamsIp.u4_timestamp_high = -1; + sDeblockParamsIp.u4_timestamp_low = -1; + + sDeblockParamsIp.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t); + sDeblockParamsOp.u4_size = sizeof(ive_ctl_set_deblock_params_op_t); + + ive_api_function(mCodecCtx, &sDeblockParamsIp, &sDeblockParamsOp); + return; +} + +void Codec::setVuiParams() { + ih264e_vui_ip_t sVuiParamsIp{}; + ih264e_vui_op_t sVuiParamsOp{}; + + sVuiParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sVuiParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_VUI_PARAMS; + + sVuiParamsIp.u1_aspect_ratio_info_present_flag = mAspectRatioFlag; + sVuiParamsIp.u1_aspect_ratio_idc = 0; + sVuiParamsIp.u2_sar_width = 0; + sVuiParamsIp.u2_sar_height = 0; + sVuiParamsIp.u1_overscan_info_present_flag = 0; + sVuiParamsIp.u1_overscan_appropriate_flag = 0; + sVuiParamsIp.u1_video_signal_type_present_flag = 1; + sVuiParamsIp.u1_video_format = 0; + sVuiParamsIp.u1_video_full_range_flag = 0; + sVuiParamsIp.u1_colour_description_present_flag = 1; + sVuiParamsIp.u1_colour_primaries = 0; + sVuiParamsIp.u1_transfer_characteristics = 0; + sVuiParamsIp.u1_matrix_coefficients = 0; + sVuiParamsIp.u1_chroma_loc_info_present_flag = 0; + sVuiParamsIp.u1_chroma_sample_loc_type_top_field = 0; + sVuiParamsIp.u1_chroma_sample_loc_type_bottom_field = 0; + sVuiParamsIp.u1_vui_timing_info_present_flag = 0; + sVuiParamsIp.u4_vui_num_units_in_tick = 0; + sVuiParamsIp.u4_vui_time_scale = 0; + sVuiParamsIp.u1_fixed_frame_rate_flag = 0; + sVuiParamsIp.u1_nal_hrd_parameters_present_flag = mNalHrdFlag; + sVuiParamsIp.u1_vcl_hrd_parameters_present_flag = mVclHrdFlag; + sVuiParamsIp.u1_low_delay_hrd_flag = 0; + sVuiParamsIp.u1_pic_struct_present_flag = 0; + sVuiParamsIp.u1_bitstream_restriction_flag = 0; + sVuiParamsIp.u1_motion_vectors_over_pic_boundaries_flag = 0; + sVuiParamsIp.u1_max_bytes_per_pic_denom = 0; + sVuiParamsIp.u1_max_bits_per_mb_denom = 0; + sVuiParamsIp.u1_log2_max_mv_length_horizontal = 0; + sVuiParamsIp.u1_log2_max_mv_length_vertical = 0; + sVuiParamsIp.u1_num_reorder_frames = 0; + sVuiParamsIp.u1_max_dec_frame_buffering = 0; + + sVuiParamsIp.u4_size = sizeof(ih264e_vui_ip_t); + sVuiParamsOp.u4_size = sizeof(ih264e_vui_op_t); + + ive_api_function(mCodecCtx, &sVuiParamsIp, &sVuiParamsOp); + return; +} + +void Codec::setSeiMdcvParams() { + ih264e_ctl_set_sei_mdcv_params_ip_t sSeiMdcvParamsIp{}; + ih264e_ctl_set_sei_mdcv_params_op_t sSeiMdcvParamsOp{}; + + sSeiMdcvParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sSeiMdcvParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_SEI_MDCV_PARAMS; + sSeiMdcvParamsIp.u1_sei_mdcv_params_present_flag = mSeiMdcvFlag; + if (mSeiMdcvFlag) { + for (int i4_count = 0; i4_count < NUM_SEI_MDCV_PRIMARIES; ++i4_count) { + sSeiMdcvParamsIp.au2_display_primaries_x[i4_count] = 30000; + sSeiMdcvParamsIp.au2_display_primaries_y[i4_count] = 35000; + } + sSeiMdcvParamsIp.u2_white_point_x = 30000; + sSeiMdcvParamsIp.u2_white_point_y = 35000; + sSeiMdcvParamsIp.u4_max_display_mastering_luminance = 100000000; + sSeiMdcvParamsIp.u4_min_display_mastering_luminance = 50000; + } + + sSeiMdcvParamsIp.u4_timestamp_high = -1; + sSeiMdcvParamsIp.u4_timestamp_low = -1; + + sSeiMdcvParamsIp.u4_size = sizeof(ih264e_ctl_set_sei_mdcv_params_ip_t); + sSeiMdcvParamsOp.u4_size = sizeof(ih264e_ctl_set_sei_mdcv_params_op_t); + ih264e_api_function(mCodecCtx, &sSeiMdcvParamsIp, &sSeiMdcvParamsOp); + return; +} + +void Codec::setSeiCllParams() { + ih264e_ctl_set_sei_cll_params_ip_t sSeiCllParamsIp{}; + ih264e_ctl_set_sei_cll_params_op_t sSeiCllParamsOp{}; + + sSeiCllParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sSeiCllParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_SEI_CLL_PARAMS; + sSeiCllParamsIp.u1_sei_cll_params_present_flag = mSeiCllFlag; + if (mSeiCllFlag) { + sSeiCllParamsIp.u2_max_content_light_level = 0; + sSeiCllParamsIp.u2_max_pic_average_light_level = 0; + } + + sSeiCllParamsIp.u4_timestamp_high = -1; + sSeiCllParamsIp.u4_timestamp_low = -1; + + sSeiCllParamsIp.u4_size = sizeof(ih264e_ctl_set_sei_cll_params_ip_t); + sSeiCllParamsOp.u4_size = sizeof(ih264e_ctl_set_sei_cll_params_op_t); + + ih264e_api_function(mCodecCtx, &sSeiCllParamsIp, &sSeiCllParamsOp); + return; +} + +void Codec::setSeiAveParams() { + ih264e_ctl_set_sei_ave_params_ip_t sSeiAveParamsIp{}; + ih264e_ctl_set_sei_ave_params_op_t sSeiAveParamsOp{}; + + sSeiAveParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sSeiAveParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_SEI_AVE_PARAMS; + sSeiAveParamsIp.u1_sei_ave_params_present_flag = mSeiAveFlag; + if (mSeiAveFlag) { + sSeiAveParamsIp.u4_ambient_illuminance = 1; + sSeiAveParamsIp.u2_ambient_light_x = 0; + sSeiAveParamsIp.u2_ambient_light_y = 0; + } + + sSeiAveParamsIp.u4_timestamp_high = -1; + sSeiAveParamsIp.u4_timestamp_low = -1; + + sSeiAveParamsIp.u4_size = sizeof(ih264e_ctl_set_sei_ave_params_ip_t); + sSeiAveParamsOp.u4_size = sizeof(ih264e_ctl_set_sei_ave_params_op_t); + + ih264e_api_function(mCodecCtx, &sSeiAveParamsIp, &sSeiAveParamsOp); + return; +} + +void Codec::setSeiCcvParams() { + ih264e_ctl_set_sei_ccv_params_ip_t sSeiCcvParamsIp{}; + ih264e_ctl_set_sei_ccv_params_op_t sSeiCcvParamsOp{}; + + sSeiCcvParamsIp.e_cmd = IVE_CMD_VIDEO_CTL; + sSeiCcvParamsIp.e_sub_cmd = IVE_CMD_CTL_SET_SEI_CCV_PARAMS; + sSeiCcvParamsIp.u1_sei_ccv_params_present_flag = mSeiCcvFlag; + if (mSeiCcvFlag) { + sSeiCcvParamsIp.u1_ccv_cancel_flag = 0; + sSeiCcvParamsIp.u1_ccv_persistence_flag = 1; + sSeiCcvParamsIp.u1_ccv_primaries_present_flag = 1; + sSeiCcvParamsIp.u1_ccv_min_luminance_value_present_flag = 1; + sSeiCcvParamsIp.u1_ccv_max_luminance_value_present_flag = 1; + sSeiCcvParamsIp.u1_ccv_avg_luminance_value_present_flag = 1; + sSeiCcvParamsIp.u1_ccv_reserved_zero_2bits = 0; + for (int i4_count = 0; i4_count < NUM_SEI_CCV_PRIMARIES; ++i4_count) { + sSeiCcvParamsIp.ai4_ccv_primaries_x[i4_count] = 1; + sSeiCcvParamsIp.ai4_ccv_primaries_y[i4_count] = 1; + } + sSeiCcvParamsIp.u4_ccv_min_luminance_value = 1; + sSeiCcvParamsIp.u4_ccv_max_luminance_value = 1; + sSeiCcvParamsIp.u4_ccv_avg_luminance_value = 1; + } + + sSeiCcvParamsIp.u4_timestamp_high = -1; + sSeiCcvParamsIp.u4_timestamp_low = -1; + + sSeiCcvParamsIp.u4_size = sizeof(ih264e_ctl_set_sei_ccv_params_ip_t); + sSeiCcvParamsOp.u4_size = sizeof(ih264e_ctl_set_sei_ccv_params_op_t); + + ih264e_api_function(mCodecCtx, &sSeiCcvParamsIp, &sSeiCcvParamsOp); + return; +} + +void Codec::logVersion() { + ive_ctl_getversioninfo_ip_t sCtlIp{}; + ive_ctl_getversioninfo_op_t sCtlOp{}; + UWORD8 au1Buf[512]; + + sCtlIp.e_cmd = IVE_CMD_VIDEO_CTL; + sCtlIp.e_sub_cmd = IVE_CMD_CTL_GETVERSION; + + sCtlIp.u4_size = sizeof(ive_ctl_getversioninfo_ip_t); + sCtlOp.u4_size = sizeof(ive_ctl_getversioninfo_op_t); + sCtlIp.pu1_version = au1Buf; + sCtlIp.u4_version_bufsize = sizeof(au1Buf); + + ive_api_function(mCodecCtx, (void *)&sCtlIp, (void *)&sCtlOp); + return; +} + +void Codec::encodeFrames(const uint8_t *data, size_t size) { + size_t frameSize = (mIvVideoColorFormat == IV_YUV_422ILE) ? (mWidth * mHeight * 2) + : ((mWidth * mHeight * 3) / 2); + ive_video_encode_ip_t sEncodeIp{}; + ive_video_encode_op_t sEncodeOp{}; + uint8_t header[kHeaderLength]; + iv_raw_buf_t *psInpRawBuf = &sEncodeIp.s_inp_buf; + sEncodeIp.s_out_buf.pv_buf = header; + sEncodeIp.s_out_buf.u4_bytes = 0; + sEncodeIp.s_out_buf.u4_bufsize = kHeaderLength; + sEncodeIp.u4_size = sizeof(ive_video_encode_ip_t); + sEncodeOp.u4_size = sizeof(ive_video_encode_op_t); + + sEncodeIp.e_cmd = IVE_CMD_VIDEO_ENCODE; + sEncodeIp.pv_bufs = nullptr; + sEncodeIp.pv_mb_info = nullptr; + sEncodeIp.pv_pic_info = nullptr; + sEncodeIp.u4_mb_info_type = 0; + sEncodeIp.u4_pic_info_type = 0; + sEncodeIp.u4_is_last = 0; + sEncodeOp.s_out_buf.pv_buf = nullptr; + + /* Initialize color formats */ + memset(psInpRawBuf, 0, sizeof(iv_raw_buf_t)); + psInpRawBuf->u4_size = sizeof(iv_raw_buf_t); + psInpRawBuf->e_color_fmt = mIvVideoColorFormat; + + ive_api_function(mCodecCtx, &sEncodeIp, &sEncodeOp); + size_t numFrame = 0; + while (size > 0) { + uint8_t *tmpData = (uint8_t *)malloc(frameSize); + size_t bytesConsumed = std::min(size, frameSize); + if (bytesConsumed < frameSize) { + memset(&tmpData[bytesConsumed], data[0], frameSize - bytesConsumed); + } + memcpy(tmpData, data, bytesConsumed); + setEncParams(psInpRawBuf, tmpData); + uint64_t OutputBufferSize = (frameSize / kCompressionRatio); + uint8_t *OutputBuffer = (uint8_t *)malloc(OutputBufferSize); + sEncodeIp.s_out_buf.pv_buf = OutputBuffer; + sEncodeIp.s_out_buf.u4_bufsize = OutputBufferSize; + if (mIsForceIdrEnabled) { + if (numFrame == mForceIdrInterval) { + setFrameType(IV_IDR_FRAME); + } + } + if (mIsDynamicBitRateChangeEnabled) { + if (numFrame == mDynamicBitRateInterval) { + if (data[0] & 0x01) { + mBitrate *= 2; + } else { + mBitrate /= 2; + } + setBitRate(); + } + } + if (mIsDynamicFrameRateChangeEnabled) { + if (numFrame == mDynamicFrameRateInterval) { + if (size > 1 && data[1] & 0x01) { + mFrameRate *= 2; + } else { + mFrameRate /= 2; + } + setFrameRate(); + } + } + ive_api_function(mCodecCtx, &sEncodeIp, &sEncodeOp); + ++numFrame; + data += bytesConsumed; + size -= bytesConsumed; + free(tmpData); + free(OutputBuffer); + } +} + +void Codec::setEncParams(iv_raw_buf_t *psInpRawBuf, const uint8_t *data) { + switch (mIvVideoColorFormat) { + case IV_YUV_420SP_UV: + [[fallthrough]]; + case IV_YUV_420SP_VU: { + uint8_t *yPlane = const_cast(data); + uint8_t *uPlane = const_cast(data + (mWidth * mHeight)); + int32_t yStride = mWidth; + int32_t uStride = mWidth / 2; + psInpRawBuf->apv_bufs[0] = yPlane; + psInpRawBuf->apv_bufs[1] = uPlane; + + psInpRawBuf->au4_wd[0] = mWidth; + psInpRawBuf->au4_wd[1] = mWidth; + + psInpRawBuf->au4_ht[0] = mHeight; + psInpRawBuf->au4_ht[1] = mHeight / 2; + + psInpRawBuf->au4_strd[0] = yStride; + psInpRawBuf->au4_strd[1] = uStride; + break; + } + case IV_YUV_422ILE: { + uint8_t *yPlane = const_cast(data); + psInpRawBuf->apv_bufs[0] = yPlane; + + psInpRawBuf->au4_wd[0] = mWidth * 2; + + psInpRawBuf->au4_ht[0] = mHeight; + + psInpRawBuf->au4_strd[0] = mWidth * 2; + break; + } + case IV_YUV_420P: + [[fallthrough]]; + default: { + uint8_t *yPlane = const_cast(data); + uint8_t *uPlane = const_cast(data + (mWidth * mHeight)); + uint8_t *vPlane = const_cast(data + ((mWidth * mHeight) * 5) / 4); + int32_t yStride = mWidth; + int32_t uStride = mWidth / 2; + int32_t vStride = mWidth / 2; + + psInpRawBuf->apv_bufs[0] = yPlane; + psInpRawBuf->apv_bufs[1] = uPlane; + psInpRawBuf->apv_bufs[2] = vPlane; + + psInpRawBuf->au4_wd[0] = mWidth; + psInpRawBuf->au4_wd[1] = mWidth / 2; + psInpRawBuf->au4_wd[2] = mWidth / 2; + + psInpRawBuf->au4_ht[0] = mHeight; + psInpRawBuf->au4_ht[1] = mHeight / 2; + psInpRawBuf->au4_ht[2] = mHeight / 2; + + psInpRawBuf->au4_strd[0] = yStride; + psInpRawBuf->au4_strd[1] = uStride; + psInpRawBuf->au4_strd[2] = vStride; + break; + } + } + return; +} + +void Codec::deInitEncoder() { + iv_mem_rec_t *ps_mem_rec = mMemRecords; + for (size_t i = 0; i < mNumMemRecords; ++i) { + if (ps_mem_rec) { + free(ps_mem_rec->pv_base); + } + ++ps_mem_rec; + } + if (mMemRecords) { + free(mMemRecords); + } + mCodecCtx = nullptr; + return; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < IDX_LAST) { + return 0; + } + Codec *codec = new Codec(); + if (codec->initEncoder(&data, &size)) { + codec->encodeFrames(data, size); + } + delete codec; + return 0; +}