| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2018 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | //#define LOG_NDEBUG 0 | 
|  | 18 | #define LOG_TAG "C2SoftAvcEnc" | 
|  | 19 | #include <log/log.h> | 
|  | 20 | #include <utils/misc.h> | 
|  | 21 |  | 
|  | 22 | #include <media/hardware/VideoAPI.h> | 
|  | 23 | #include <media/stagefright/MediaDefs.h> | 
|  | 24 | #include <media/stagefright/MediaErrors.h> | 
|  | 25 | #include <media/stagefright/MetaData.h> | 
|  | 26 | #include <media/stagefright/foundation/AUtils.h> | 
|  | 27 |  | 
|  | 28 | #include <C2Debug.h> | 
|  | 29 | #include <C2PlatformSupport.h> | 
|  | 30 | #include <Codec2BufferUtils.h> | 
|  | 31 | #include <SimpleC2Interface.h> | 
|  | 32 | #include <util/C2InterfaceHelper.h> | 
|  | 33 |  | 
|  | 34 | #include "C2SoftAvcEnc.h" | 
|  | 35 | #include "ih264e.h" | 
|  | 36 | #include "ih264e_error.h" | 
|  | 37 |  | 
|  | 38 | namespace android { | 
|  | 39 |  | 
| Manisha Jajoo | 9acd73d | 2019-03-12 14:08:05 +0530 | [diff] [blame] | 40 | namespace { | 
|  | 41 |  | 
|  | 42 | constexpr char COMPONENT_NAME[] = "c2.android.avc.encoder"; | 
| Harish Mahendrakar | ea0eb37 | 2019-11-21 10:33:05 -0800 | [diff] [blame] | 43 | constexpr uint32_t kMinOutBufferSize = 524288; | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 44 | void ParseGop( | 
|  | 45 | const C2StreamGopTuning::output &gop, | 
|  | 46 | uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) { | 
|  | 47 | uint32_t syncInt = 1; | 
|  | 48 | uint32_t iInt = 1; | 
|  | 49 | for (size_t i = 0; i < gop.flexCount(); ++i) { | 
|  | 50 | const C2GopLayerStruct &layer = gop.m.values[i]; | 
|  | 51 | if (layer.count == UINT32_MAX) { | 
|  | 52 | syncInt = 0; | 
|  | 53 | } else if (syncInt <= UINT32_MAX / (layer.count + 1)) { | 
|  | 54 | syncInt *= (layer.count + 1); | 
|  | 55 | } | 
|  | 56 | if ((layer.type_ & I_FRAME) == 0) { | 
|  | 57 | if (layer.count == UINT32_MAX) { | 
|  | 58 | iInt = 0; | 
|  | 59 | } else if (iInt <= UINT32_MAX / (layer.count + 1)) { | 
|  | 60 | iInt *= (layer.count + 1); | 
|  | 61 | } | 
|  | 62 | } | 
|  | 63 | if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) { | 
|  | 64 | *maxBframes = layer.count; | 
|  | 65 | } | 
|  | 66 | } | 
|  | 67 | if (syncInterval) { | 
|  | 68 | *syncInterval = syncInt; | 
|  | 69 | } | 
|  | 70 | if (iInterval) { | 
|  | 71 | *iInterval = iInt; | 
|  | 72 | } | 
|  | 73 | } | 
|  | 74 |  | 
| Manisha Jajoo | 9acd73d | 2019-03-12 14:08:05 +0530 | [diff] [blame] | 75 | }  // namespace | 
|  | 76 |  | 
|  | 77 | class C2SoftAvcEnc::IntfImpl : public SimpleInterface<void>::BaseParams { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 78 | public: | 
|  | 79 | explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) | 
| Manisha Jajoo | 9acd73d | 2019-03-12 14:08:05 +0530 | [diff] [blame] | 80 | : SimpleInterface<void>::BaseParams( | 
|  | 81 | helper, | 
|  | 82 | COMPONENT_NAME, | 
|  | 83 | C2Component::KIND_ENCODER, | 
|  | 84 | C2Component::DOMAIN_VIDEO, | 
|  | 85 | MEDIA_MIMETYPE_VIDEO_AVC) { | 
|  | 86 | noPrivateBuffers(); // TODO: account for our buffers here | 
|  | 87 | noInputReferences(); | 
|  | 88 | noOutputReferences(); | 
| Manisha Jajoo | 9acd73d | 2019-03-12 14:08:05 +0530 | [diff] [blame] | 89 | noTimeStretch(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 90 | setDerivedInstance(this); | 
|  | 91 |  | 
|  | 92 | addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 93 | DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 94 | .withConstValue(new C2StreamUsageTuning::input( | 
|  | 95 | 0u, (uint64_t)C2MemoryUsage::CPU_READ)) | 
|  | 96 | .build()); | 
|  | 97 |  | 
|  | 98 | addParameter( | 
| Manisha Jajoo | 9acd73d | 2019-03-12 14:08:05 +0530 | [diff] [blame] | 99 | DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) | 
|  | 100 | .withConstValue(new C2ComponentAttributesSetting( | 
|  | 101 | C2Component::ATTRIB_IS_TEMPORAL)) | 
|  | 102 | .build()); | 
|  | 103 |  | 
|  | 104 | addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 105 | DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) | 
| Harish Mahendrakar | bb40ea8 | 2020-04-07 01:35:52 +0530 | [diff] [blame] | 106 | .withDefault(new C2StreamPictureSizeInfo::input(0u, 16, 16)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 107 | .withFields({ | 
|  | 108 | C2F(mSize, width).inRange(2, 2560, 2), | 
|  | 109 | C2F(mSize, height).inRange(2, 2560, 2), | 
|  | 110 | }) | 
|  | 111 | .withSetter(SizeSetter) | 
|  | 112 | .build()); | 
|  | 113 |  | 
|  | 114 | addParameter( | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 115 | DefineParam(mGop, C2_PARAMKEY_GOP) | 
|  | 116 | .withDefault(C2StreamGopTuning::output::AllocShared( | 
|  | 117 | 0 /* flexCount */, 0u /* stream */)) | 
|  | 118 | .withFields({C2F(mGop, m.values[0].type_).any(), | 
|  | 119 | C2F(mGop, m.values[0].count).any()}) | 
|  | 120 | .withSetter(GopSetter) | 
|  | 121 | .build()); | 
|  | 122 |  | 
|  | 123 | addParameter( | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 124 | DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY) | 
|  | 125 | .withDefault(new C2PortActualDelayTuning::input(DEFAULT_B_FRAMES)) | 
|  | 126 | .withFields({C2F(mActualInputDelay, value).inRange(0, MAX_B_FRAMES)}) | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 127 | .calculatedAs(InputDelaySetter, mGop) | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 128 | .build()); | 
|  | 129 |  | 
|  | 130 | addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 131 | DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE) | 
| Harish Mahendrakar | bb40ea8 | 2020-04-07 01:35:52 +0530 | [diff] [blame] | 132 | .withDefault(new C2StreamFrameRateInfo::output(0u, 1.)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 133 | // TODO: More restriction? | 
|  | 134 | .withFields({C2F(mFrameRate, value).greaterThan(0.)}) | 
|  | 135 | .withSetter(Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps) | 
|  | 136 | .build()); | 
|  | 137 |  | 
|  | 138 | addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 139 | DefineParam(mBitrate, C2_PARAMKEY_BITRATE) | 
|  | 140 | .withDefault(new C2StreamBitrateInfo::output(0u, 64000)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 141 | .withFields({C2F(mBitrate, value).inRange(4096, 12000000)}) | 
|  | 142 | .withSetter(BitrateSetter) | 
|  | 143 | .build()); | 
|  | 144 |  | 
|  | 145 | addParameter( | 
|  | 146 | DefineParam(mIntraRefresh, C2_PARAMKEY_INTRA_REFRESH) | 
|  | 147 | .withDefault(new C2StreamIntraRefreshTuning::output( | 
|  | 148 | 0u, C2Config::INTRA_REFRESH_DISABLED, 0.)) | 
|  | 149 | .withFields({ | 
|  | 150 | C2F(mIntraRefresh, mode).oneOf({ | 
|  | 151 | C2Config::INTRA_REFRESH_DISABLED, C2Config::INTRA_REFRESH_ARBITRARY }), | 
|  | 152 | C2F(mIntraRefresh, period).any() | 
|  | 153 | }) | 
|  | 154 | .withSetter(IntraRefreshSetter) | 
|  | 155 | .build()); | 
|  | 156 |  | 
|  | 157 | addParameter( | 
|  | 158 | DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) | 
|  | 159 | .withDefault(new C2StreamProfileLevelInfo::output( | 
|  | 160 | 0u, PROFILE_AVC_CONSTRAINED_BASELINE, LEVEL_AVC_4_1)) | 
|  | 161 | .withFields({ | 
|  | 162 | C2F(mProfileLevel, profile).oneOf({ | 
|  | 163 | PROFILE_AVC_BASELINE, | 
|  | 164 | PROFILE_AVC_CONSTRAINED_BASELINE, | 
|  | 165 | PROFILE_AVC_MAIN, | 
|  | 166 | }), | 
|  | 167 | C2F(mProfileLevel, level).oneOf({ | 
|  | 168 | LEVEL_AVC_1, | 
|  | 169 | LEVEL_AVC_1B, | 
|  | 170 | LEVEL_AVC_1_1, | 
|  | 171 | LEVEL_AVC_1_2, | 
|  | 172 | LEVEL_AVC_1_3, | 
|  | 173 | LEVEL_AVC_2, | 
|  | 174 | LEVEL_AVC_2_1, | 
|  | 175 | LEVEL_AVC_2_2, | 
|  | 176 | LEVEL_AVC_3, | 
|  | 177 | LEVEL_AVC_3_1, | 
|  | 178 | LEVEL_AVC_3_2, | 
|  | 179 | LEVEL_AVC_4, | 
|  | 180 | LEVEL_AVC_4_1, | 
|  | 181 | LEVEL_AVC_4_2, | 
|  | 182 | LEVEL_AVC_5, | 
|  | 183 | }), | 
|  | 184 | }) | 
|  | 185 | .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate) | 
|  | 186 | .build()); | 
|  | 187 |  | 
|  | 188 | addParameter( | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 189 | DefineParam(mQuantization, C2_PARAMKEY_QUANTIZATION) | 
|  | 190 | .withDefault(new C2StreamQuantizationInfo::output(0u, | 
|  | 191 | DEFAULT_QP_MAX, DEFAULT_QP_MIN, | 
|  | 192 | DEFAULT_QP_MAX, DEFAULT_QP_MIN, | 
|  | 193 | DEFAULT_QP_MAX, DEFAULT_QP_MIN)) | 
|  | 194 | .withFields({ | 
|  | 195 | C2F(mQuantization, iMax).inRange(1, 51), | 
|  | 196 | C2F(mQuantization, iMin).inRange(1, 51), | 
|  | 197 | C2F(mQuantization, pMax).inRange(1, 51), | 
|  | 198 | C2F(mQuantization, pMin).inRange(1, 51), | 
|  | 199 | C2F(mQuantization, bMax).inRange(1, 51), | 
|  | 200 | C2F(mQuantization, bMin).inRange(1, 51), | 
|  | 201 | }) | 
|  | 202 | .withSetter(QuantizationSetter) | 
|  | 203 | .build()); | 
|  | 204 |  | 
|  | 205 | addParameter( | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 206 | DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME) | 
|  | 207 | .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE)) | 
|  | 208 | .withFields({C2F(mRequestSync, value).oneOf({ C2_FALSE, C2_TRUE }) }) | 
|  | 209 | .withSetter(Setter<decltype(*mRequestSync)>::NonStrictValueWithNoDeps) | 
|  | 210 | .build()); | 
|  | 211 |  | 
|  | 212 | addParameter( | 
|  | 213 | DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL) | 
|  | 214 | .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000)) | 
|  | 215 | .withFields({C2F(mSyncFramePeriod, value).any()}) | 
|  | 216 | .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps) | 
|  | 217 | .build()); | 
|  | 218 | } | 
|  | 219 |  | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 220 | static C2R InputDelaySetter( | 
|  | 221 | bool mayBlock, | 
|  | 222 | C2P<C2PortActualDelayTuning::input> &me, | 
|  | 223 | const C2P<C2StreamGopTuning::output> &gop) { | 
|  | 224 | (void)mayBlock; | 
|  | 225 | uint32_t maxBframes = 0; | 
|  | 226 | ParseGop(gop.v, nullptr, nullptr, &maxBframes); | 
|  | 227 | me.set().value = maxBframes; | 
|  | 228 | return C2R::Ok(); | 
|  | 229 | } | 
|  | 230 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 231 | static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) { | 
|  | 232 | (void)mayBlock; | 
|  | 233 | C2R res = C2R::Ok(); | 
|  | 234 | if (me.v.value <= 4096) { | 
|  | 235 | me.set().value = 4096; | 
|  | 236 | } | 
|  | 237 | return res; | 
|  | 238 | } | 
|  | 239 |  | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 240 | static C2R QuantizationSetter(bool mayBlock, C2P<C2StreamQuantizationInfo::output> &me) { | 
|  | 241 | (void)mayBlock; | 
|  | 242 | (void)me; | 
|  | 243 | C2R res = C2R::Ok(); | 
|  | 244 |  | 
|  | 245 | ALOGV("QuantizationSetter enters max/min i %d/%d p %d/%d b %d/%d", | 
|  | 246 | me.v.iMax, me.v.iMin, me.v.pMax, me.v.pMin, me.v.bMax, me.v.bMin); | 
|  | 247 |  | 
|  | 248 | // bounds checking | 
|  | 249 | constexpr int qp_lowest = 1; | 
|  | 250 | constexpr int qp_highest = 51; | 
|  | 251 |  | 
|  | 252 | if (me.v.iMax < qp_lowest) { | 
|  | 253 | me.set().iMax = qp_lowest; | 
|  | 254 | } else if (me.v.iMax > qp_highest) { | 
|  | 255 | me.set().iMax = qp_highest; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | if (me.v.iMin < qp_lowest) { | 
|  | 259 | me.set().iMin = qp_lowest; | 
|  | 260 | } else if (me.v.iMin > qp_highest) { | 
|  | 261 | me.set().iMin = qp_highest; | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | if (me.v.pMax < qp_lowest) { | 
|  | 265 | me.set().pMax = qp_lowest; | 
|  | 266 | } else if (me.v.pMax > qp_highest) { | 
|  | 267 | me.set().pMax = qp_highest; | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | if (me.v.pMin < qp_lowest) { | 
|  | 271 | me.set().pMin = qp_lowest; | 
|  | 272 | } else if (me.v.pMin > qp_highest) { | 
|  | 273 | me.set().pMin = qp_highest; | 
|  | 274 | } | 
|  | 275 |  | 
|  | 276 | if (me.v.bMax < qp_lowest) { | 
|  | 277 | me.set().bMax = qp_lowest; | 
|  | 278 | } else if (me.v.bMax > qp_highest) { | 
|  | 279 | me.set().bMax = qp_highest; | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | if (me.v.bMin < qp_lowest) { | 
|  | 283 | me.set().bMin = qp_lowest; | 
|  | 284 | } else if (me.v.bMin > qp_highest) { | 
|  | 285 | me.set().bMin = qp_highest; | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | // consistency checking, e.g. min<max | 
|  | 289 | // | 
|  | 290 | if (me.v.iMax < me.v.iMin) { | 
|  | 291 | me.set().iMax = me.v.iMin; | 
|  | 292 | } | 
|  | 293 | if (me.v.pMax < me.v.pMin) { | 
|  | 294 | me.set().pMax = me.v.pMin; | 
|  | 295 | } | 
|  | 296 | if (me.v.bMax < me.v.bMin) { | 
|  | 297 | me.set().bMax = me.v.bMin; | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | // TODO: enforce any sort of i_max < p_max < b_max? | 
|  | 301 |  | 
|  | 302 | return res; | 
|  | 303 | } | 
|  | 304 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 305 | static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe, | 
|  | 306 | C2P<C2StreamPictureSizeInfo::input> &me) { | 
|  | 307 | (void)mayBlock; | 
|  | 308 | C2R res = C2R::Ok(); | 
|  | 309 | if (!me.F(me.v.width).supportsAtAll(me.v.width)) { | 
|  | 310 | res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width))); | 
|  | 311 | me.set().width = oldMe.v.width; | 
|  | 312 | } | 
|  | 313 | if (!me.F(me.v.height).supportsAtAll(me.v.height)) { | 
|  | 314 | res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height))); | 
|  | 315 | me.set().height = oldMe.v.height; | 
|  | 316 | } | 
|  | 317 | return res; | 
|  | 318 | } | 
|  | 319 |  | 
|  | 320 | static C2R ProfileLevelSetter( | 
|  | 321 | bool mayBlock, | 
|  | 322 | C2P<C2StreamProfileLevelInfo::output> &me, | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 323 | const C2P<C2StreamPictureSizeInfo::input> &size, | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 324 | const C2P<C2StreamFrameRateInfo::output> &frameRate, | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 325 | const C2P<C2StreamBitrateInfo::output> &bitrate) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 326 | (void)mayBlock; | 
|  | 327 | if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) { | 
|  | 328 | me.set().profile = PROFILE_AVC_CONSTRAINED_BASELINE; | 
|  | 329 | } | 
|  | 330 |  | 
|  | 331 | struct LevelLimits { | 
|  | 332 | C2Config::level_t level; | 
|  | 333 | float mbsPerSec; | 
|  | 334 | uint64_t mbs; | 
|  | 335 | uint32_t bitrate; | 
|  | 336 | }; | 
|  | 337 | constexpr LevelLimits kLimits[] = { | 
|  | 338 | { LEVEL_AVC_1,     1485,    99,     64000 }, | 
|  | 339 | // Decoder does not properly handle level 1b. | 
|  | 340 | // { LEVEL_AVC_1B,    1485,   99,   128000 }, | 
|  | 341 | { LEVEL_AVC_1_1,   3000,   396,    192000 }, | 
|  | 342 | { LEVEL_AVC_1_2,   6000,   396,    384000 }, | 
|  | 343 | { LEVEL_AVC_1_3,  11880,   396,    768000 }, | 
|  | 344 | { LEVEL_AVC_2,    11880,   396,   2000000 }, | 
|  | 345 | { LEVEL_AVC_2_1,  19800,   792,   4000000 }, | 
|  | 346 | { LEVEL_AVC_2_2,  20250,  1620,   4000000 }, | 
|  | 347 | { LEVEL_AVC_3,    40500,  1620,  10000000 }, | 
|  | 348 | { LEVEL_AVC_3_1, 108000,  3600,  14000000 }, | 
|  | 349 | { LEVEL_AVC_3_2, 216000,  5120,  20000000 }, | 
|  | 350 | { LEVEL_AVC_4,   245760,  8192,  20000000 }, | 
|  | 351 | { LEVEL_AVC_4_1, 245760,  8192,  50000000 }, | 
|  | 352 | { LEVEL_AVC_4_2, 522240,  8704,  50000000 }, | 
|  | 353 | { LEVEL_AVC_5,   589824, 22080, 135000000 }, | 
|  | 354 | }; | 
|  | 355 |  | 
|  | 356 | uint64_t mbs = uint64_t((size.v.width + 15) / 16) * ((size.v.height + 15) / 16); | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 357 | float mbsPerSec = float(mbs) * frameRate.v.value; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 358 |  | 
|  | 359 | // Check if the supplied level meets the MB / bitrate requirements. If | 
|  | 360 | // not, update the level with the lowest level meeting the requirements. | 
|  | 361 |  | 
|  | 362 | bool found = false; | 
|  | 363 | // By default needsUpdate = false in case the supplied level does meet | 
|  | 364 | // the requirements. For Level 1b, we want to update the level anyway, | 
|  | 365 | // so we set it to true in that case. | 
|  | 366 | bool needsUpdate = (me.v.level == LEVEL_AVC_1B); | 
|  | 367 | for (const LevelLimits &limit : kLimits) { | 
|  | 368 | if (mbs <= limit.mbs && mbsPerSec <= limit.mbsPerSec && | 
|  | 369 | bitrate.v.value <= limit.bitrate) { | 
|  | 370 | // This is the lowest level that meets the requirements, and if | 
|  | 371 | // we haven't seen the supplied level yet, that means we don't | 
|  | 372 | // need the update. | 
|  | 373 | if (needsUpdate) { | 
|  | 374 | ALOGD("Given level %x does not cover current configuration: " | 
|  | 375 | "adjusting to %x", me.v.level, limit.level); | 
|  | 376 | me.set().level = limit.level; | 
|  | 377 | } | 
|  | 378 | found = true; | 
|  | 379 | break; | 
|  | 380 | } | 
|  | 381 | if (me.v.level == limit.level) { | 
|  | 382 | // We break out of the loop when the lowest feasible level is | 
|  | 383 | // found. The fact that we're here means that our level doesn't | 
|  | 384 | // meet the requirement and needs to be updated. | 
|  | 385 | needsUpdate = true; | 
|  | 386 | } | 
|  | 387 | } | 
|  | 388 | if (!found) { | 
|  | 389 | // We set to the highest supported level. | 
|  | 390 | me.set().level = LEVEL_AVC_5; | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | return C2R::Ok(); | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | static C2R IntraRefreshSetter(bool mayBlock, C2P<C2StreamIntraRefreshTuning::output> &me) { | 
|  | 397 | (void)mayBlock; | 
|  | 398 | C2R res = C2R::Ok(); | 
|  | 399 | if (me.v.period < 1) { | 
|  | 400 | me.set().mode = C2Config::INTRA_REFRESH_DISABLED; | 
|  | 401 | me.set().period = 0; | 
|  | 402 | } else { | 
|  | 403 | // only support arbitrary mode (cyclic in our case) | 
|  | 404 | me.set().mode = C2Config::INTRA_REFRESH_ARBITRARY; | 
|  | 405 | } | 
|  | 406 | return res; | 
|  | 407 | } | 
|  | 408 |  | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 409 | static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) { | 
|  | 410 | (void)mayBlock; | 
|  | 411 | for (size_t i = 0; i < me.v.flexCount(); ++i) { | 
|  | 412 | const C2GopLayerStruct &layer = me.v.m.values[0]; | 
|  | 413 | if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) | 
|  | 414 | && layer.count > MAX_B_FRAMES) { | 
|  | 415 | me.set().m.values[i].count = MAX_B_FRAMES; | 
|  | 416 | } | 
|  | 417 | } | 
|  | 418 | return C2R::Ok(); | 
|  | 419 | } | 
|  | 420 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 421 | IV_PROFILE_T getProfile_l() const { | 
|  | 422 | switch (mProfileLevel->profile) { | 
|  | 423 | case PROFILE_AVC_CONSTRAINED_BASELINE:  [[fallthrough]]; | 
|  | 424 | case PROFILE_AVC_BASELINE: return IV_PROFILE_BASE; | 
|  | 425 | case PROFILE_AVC_MAIN:     return IV_PROFILE_MAIN; | 
|  | 426 | default: | 
|  | 427 | ALOGD("Unrecognized profile: %x", mProfileLevel->profile); | 
|  | 428 | return IV_PROFILE_DEFAULT; | 
|  | 429 | } | 
|  | 430 | } | 
|  | 431 |  | 
|  | 432 | UWORD32 getLevel_l() const { | 
|  | 433 | struct Level { | 
|  | 434 | C2Config::level_t c2Level; | 
|  | 435 | UWORD32 avcLevel; | 
|  | 436 | }; | 
|  | 437 | constexpr Level levels[] = { | 
|  | 438 | { LEVEL_AVC_1,   10 }, | 
|  | 439 | { LEVEL_AVC_1B,   9 }, | 
|  | 440 | { LEVEL_AVC_1_1, 11 }, | 
|  | 441 | { LEVEL_AVC_1_2, 12 }, | 
|  | 442 | { LEVEL_AVC_1_3, 13 }, | 
|  | 443 | { LEVEL_AVC_2,   20 }, | 
|  | 444 | { LEVEL_AVC_2_1, 21 }, | 
|  | 445 | { LEVEL_AVC_2_2, 22 }, | 
|  | 446 | { LEVEL_AVC_3,   30 }, | 
|  | 447 | { LEVEL_AVC_3_1, 31 }, | 
|  | 448 | { LEVEL_AVC_3_2, 32 }, | 
|  | 449 | { LEVEL_AVC_4,   40 }, | 
|  | 450 | { LEVEL_AVC_4_1, 41 }, | 
|  | 451 | { LEVEL_AVC_4_2, 42 }, | 
|  | 452 | { LEVEL_AVC_5,   50 }, | 
|  | 453 | }; | 
|  | 454 | for (const Level &level : levels) { | 
|  | 455 | if (mProfileLevel->level == level.c2Level) { | 
|  | 456 | return level.avcLevel; | 
|  | 457 | } | 
|  | 458 | } | 
|  | 459 | ALOGD("Unrecognized level: %x", mProfileLevel->level); | 
|  | 460 | return 41; | 
|  | 461 | } | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 462 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 463 | uint32_t getSyncFramePeriod_l() const { | 
|  | 464 | if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) { | 
|  | 465 | return 0; | 
|  | 466 | } | 
|  | 467 | double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value; | 
|  | 468 | return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.); | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | // unsafe getters | 
|  | 472 | std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; } | 
|  | 473 | std::shared_ptr<C2StreamIntraRefreshTuning::output> getIntraRefresh_l() const { return mIntraRefresh; } | 
|  | 474 | std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; } | 
|  | 475 | std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; } | 
|  | 476 | std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; } | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 477 | std::shared_ptr<C2StreamGopTuning::output> getGop_l() const { return mGop; } | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 478 | std::shared_ptr<C2StreamQuantizationInfo::output> getQuantization_l() const { return mQuantization; } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 479 |  | 
|  | 480 | private: | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 481 | std::shared_ptr<C2StreamUsageTuning::input> mUsage; | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 482 | std::shared_ptr<C2StreamPictureSizeInfo::input> mSize; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 483 | std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate; | 
|  | 484 | std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync; | 
|  | 485 | std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh; | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 486 | std::shared_ptr<C2StreamBitrateInfo::output> mBitrate; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 487 | std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel; | 
|  | 488 | std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod; | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 489 | std::shared_ptr<C2StreamGopTuning::output> mGop; | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 490 | std::shared_ptr<C2StreamQuantizationInfo::output> mQuantization; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 491 | }; | 
|  | 492 |  | 
|  | 493 | #define ive_api_function  ih264e_api_function | 
|  | 494 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 495 | namespace { | 
|  | 496 |  | 
|  | 497 | // From external/libavc/encoder/ih264e_bitstream.h | 
|  | 498 | constexpr uint32_t MIN_STREAM_SIZE = 0x800; | 
|  | 499 |  | 
|  | 500 | static size_t GetCPUCoreCount() { | 
|  | 501 | long cpuCoreCount = 1; | 
|  | 502 | #if defined(_SC_NPROCESSORS_ONLN) | 
|  | 503 | cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); | 
|  | 504 | #else | 
|  | 505 | // _SC_NPROC_ONLN must be defined... | 
|  | 506 | cpuCoreCount = sysconf(_SC_NPROC_ONLN); | 
|  | 507 | #endif | 
|  | 508 | CHECK(cpuCoreCount >= 1); | 
|  | 509 | ALOGV("Number of CPU cores: %ld", cpuCoreCount); | 
|  | 510 | return (size_t)cpuCoreCount; | 
|  | 511 | } | 
|  | 512 |  | 
|  | 513 | }  // namespace | 
|  | 514 |  | 
|  | 515 | C2SoftAvcEnc::C2SoftAvcEnc( | 
|  | 516 | const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl) | 
|  | 517 | : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), | 
|  | 518 | mIntf(intfImpl), | 
|  | 519 | mIvVideoColorFormat(IV_YUV_420P), | 
|  | 520 | mAVCEncProfile(IV_PROFILE_BASE), | 
|  | 521 | mAVCEncLevel(41), | 
|  | 522 | mStarted(false), | 
|  | 523 | mSawInputEOS(false), | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 524 | mSignalledError(false), | 
|  | 525 | mCodecCtx(nullptr), | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 526 | mOutBlock(nullptr), | 
| Harish Mahendrakar | ea0eb37 | 2019-11-21 10:33:05 -0800 | [diff] [blame] | 527 | mOutBufferSize(kMinOutBufferSize) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 528 |  | 
|  | 529 | // If dump is enabled, then open create an empty file | 
|  | 530 | GENERATE_FILE_NAMES(); | 
|  | 531 | CREATE_DUMP_FILE(mInFile); | 
|  | 532 | CREATE_DUMP_FILE(mOutFile); | 
|  | 533 |  | 
|  | 534 | initEncParams(); | 
|  | 535 | } | 
|  | 536 |  | 
|  | 537 | C2SoftAvcEnc::~C2SoftAvcEnc() { | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 538 | onRelease(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 539 | } | 
|  | 540 |  | 
|  | 541 | c2_status_t C2SoftAvcEnc::onInit() { | 
|  | 542 | return C2_OK; | 
|  | 543 | } | 
|  | 544 |  | 
|  | 545 | c2_status_t C2SoftAvcEnc::onStop() { | 
|  | 546 | return C2_OK; | 
|  | 547 | } | 
|  | 548 |  | 
|  | 549 | void C2SoftAvcEnc::onReset() { | 
|  | 550 | // TODO: use IVE_CMD_CTL_RESET? | 
|  | 551 | releaseEncoder(); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 552 | if (mOutBlock) { | 
|  | 553 | mOutBlock.reset(); | 
|  | 554 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 555 | initEncParams(); | 
|  | 556 | } | 
|  | 557 |  | 
|  | 558 | void C2SoftAvcEnc::onRelease() { | 
|  | 559 | releaseEncoder(); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 560 | if (mOutBlock) { | 
|  | 561 | mOutBlock.reset(); | 
|  | 562 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 563 | } | 
|  | 564 |  | 
|  | 565 | c2_status_t C2SoftAvcEnc::onFlush_sm() { | 
|  | 566 | // TODO: use IVE_CMD_CTL_FLUSH? | 
|  | 567 | return C2_OK; | 
|  | 568 | } | 
|  | 569 |  | 
|  | 570 | void  C2SoftAvcEnc::initEncParams() { | 
|  | 571 | mCodecCtx = nullptr; | 
|  | 572 | mMemRecords = nullptr; | 
|  | 573 | mNumMemRecords = DEFAULT_MEM_REC_CNT; | 
|  | 574 | mHeaderGenerated = 0; | 
|  | 575 | mNumCores = GetCPUCoreCount(); | 
|  | 576 | mArch = DEFAULT_ARCH; | 
|  | 577 | mSliceMode = DEFAULT_SLICE_MODE; | 
|  | 578 | mSliceParam = DEFAULT_SLICE_PARAM; | 
|  | 579 | mHalfPelEnable = DEFAULT_HPEL; | 
|  | 580 | mIInterval = DEFAULT_I_INTERVAL; | 
|  | 581 | mIDRInterval = DEFAULT_IDR_INTERVAL; | 
|  | 582 | mDisableDeblkLevel = DEFAULT_DISABLE_DEBLK_LEVEL; | 
|  | 583 | mEnableFastSad = DEFAULT_ENABLE_FAST_SAD; | 
|  | 584 | mEnableAltRef = DEFAULT_ENABLE_ALT_REF; | 
|  | 585 | mEncSpeed = DEFAULT_ENC_SPEED; | 
|  | 586 | mIntra4x4 = DEFAULT_INTRA4x4; | 
|  | 587 | mConstrainedIntraFlag = DEFAULT_CONSTRAINED_INTRA; | 
|  | 588 | mPSNREnable = DEFAULT_PSNR_ENABLE; | 
|  | 589 | mReconEnable = DEFAULT_RECON_ENABLE; | 
|  | 590 | mEntropyMode = DEFAULT_ENTROPY_MODE; | 
|  | 591 | mBframes = DEFAULT_B_FRAMES; | 
|  | 592 |  | 
|  | 593 | gettimeofday(&mTimeStart, nullptr); | 
|  | 594 | gettimeofday(&mTimeEnd, nullptr); | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | c2_status_t C2SoftAvcEnc::setDimensions() { | 
|  | 598 | ive_ctl_set_dimensions_ip_t s_dimensions_ip; | 
|  | 599 | ive_ctl_set_dimensions_op_t s_dimensions_op; | 
|  | 600 | IV_STATUS_T status; | 
|  | 601 |  | 
|  | 602 | s_dimensions_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 603 | s_dimensions_ip.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS; | 
|  | 604 | s_dimensions_ip.u4_ht = mSize->height; | 
|  | 605 | s_dimensions_ip.u4_wd = mSize->width; | 
|  | 606 |  | 
|  | 607 | s_dimensions_ip.u4_timestamp_high = -1; | 
|  | 608 | s_dimensions_ip.u4_timestamp_low = -1; | 
|  | 609 |  | 
|  | 610 | s_dimensions_ip.u4_size = sizeof(ive_ctl_set_dimensions_ip_t); | 
|  | 611 | s_dimensions_op.u4_size = sizeof(ive_ctl_set_dimensions_op_t); | 
|  | 612 |  | 
|  | 613 | status = ive_api_function(mCodecCtx, &s_dimensions_ip, &s_dimensions_op); | 
|  | 614 | if (status != IV_SUCCESS) { | 
|  | 615 | ALOGE("Unable to set frame dimensions = 0x%x\n", | 
|  | 616 | s_dimensions_op.u4_error_code); | 
|  | 617 | return C2_CORRUPTED; | 
|  | 618 | } | 
|  | 619 | return C2_OK; | 
|  | 620 | } | 
|  | 621 |  | 
|  | 622 | c2_status_t C2SoftAvcEnc::setNumCores() { | 
|  | 623 | IV_STATUS_T status; | 
|  | 624 | ive_ctl_set_num_cores_ip_t s_num_cores_ip; | 
|  | 625 | ive_ctl_set_num_cores_op_t s_num_cores_op; | 
|  | 626 | s_num_cores_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 627 | s_num_cores_ip.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES; | 
|  | 628 | s_num_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_CORES); | 
|  | 629 | s_num_cores_ip.u4_timestamp_high = -1; | 
|  | 630 | s_num_cores_ip.u4_timestamp_low = -1; | 
|  | 631 | s_num_cores_ip.u4_size = sizeof(ive_ctl_set_num_cores_ip_t); | 
|  | 632 |  | 
|  | 633 | s_num_cores_op.u4_size = sizeof(ive_ctl_set_num_cores_op_t); | 
|  | 634 |  | 
|  | 635 | status = ive_api_function( | 
|  | 636 | mCodecCtx, (void *) &s_num_cores_ip, (void *) &s_num_cores_op); | 
|  | 637 | if (status != IV_SUCCESS) { | 
|  | 638 | ALOGE("Unable to set processor params = 0x%x\n", | 
|  | 639 | s_num_cores_op.u4_error_code); | 
|  | 640 | return C2_CORRUPTED; | 
|  | 641 | } | 
|  | 642 | return C2_OK; | 
|  | 643 | } | 
|  | 644 |  | 
|  | 645 | c2_status_t C2SoftAvcEnc::setFrameRate() { | 
|  | 646 | ive_ctl_set_frame_rate_ip_t s_frame_rate_ip; | 
|  | 647 | ive_ctl_set_frame_rate_op_t s_frame_rate_op; | 
|  | 648 | IV_STATUS_T status; | 
|  | 649 |  | 
|  | 650 | s_frame_rate_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 651 | s_frame_rate_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE; | 
|  | 652 |  | 
|  | 653 | s_frame_rate_ip.u4_src_frame_rate = mFrameRate->value + 0.5; | 
|  | 654 | s_frame_rate_ip.u4_tgt_frame_rate = mFrameRate->value + 0.5; | 
|  | 655 |  | 
|  | 656 | s_frame_rate_ip.u4_timestamp_high = -1; | 
|  | 657 | s_frame_rate_ip.u4_timestamp_low = -1; | 
|  | 658 |  | 
|  | 659 | s_frame_rate_ip.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t); | 
|  | 660 | s_frame_rate_op.u4_size = sizeof(ive_ctl_set_frame_rate_op_t); | 
|  | 661 |  | 
|  | 662 | status = ive_api_function(mCodecCtx, &s_frame_rate_ip, &s_frame_rate_op); | 
|  | 663 | if (status != IV_SUCCESS) { | 
|  | 664 | ALOGE("Unable to set frame rate = 0x%x\n", | 
|  | 665 | s_frame_rate_op.u4_error_code); | 
|  | 666 | return C2_CORRUPTED; | 
|  | 667 | } | 
|  | 668 | return C2_OK; | 
|  | 669 | } | 
|  | 670 |  | 
|  | 671 | c2_status_t C2SoftAvcEnc::setIpeParams() { | 
|  | 672 | ive_ctl_set_ipe_params_ip_t s_ipe_params_ip; | 
|  | 673 | ive_ctl_set_ipe_params_op_t s_ipe_params_op; | 
|  | 674 | IV_STATUS_T status; | 
|  | 675 |  | 
|  | 676 | s_ipe_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 677 | s_ipe_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS; | 
|  | 678 |  | 
|  | 679 | s_ipe_params_ip.u4_enable_intra_4x4 = mIntra4x4; | 
|  | 680 | s_ipe_params_ip.u4_enc_speed_preset = mEncSpeed; | 
|  | 681 | s_ipe_params_ip.u4_constrained_intra_pred = mConstrainedIntraFlag; | 
|  | 682 |  | 
|  | 683 | s_ipe_params_ip.u4_timestamp_high = -1; | 
|  | 684 | s_ipe_params_ip.u4_timestamp_low = -1; | 
|  | 685 |  | 
|  | 686 | s_ipe_params_ip.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t); | 
|  | 687 | s_ipe_params_op.u4_size = sizeof(ive_ctl_set_ipe_params_op_t); | 
|  | 688 |  | 
|  | 689 | status = ive_api_function(mCodecCtx, &s_ipe_params_ip, &s_ipe_params_op); | 
|  | 690 | if (status != IV_SUCCESS) { | 
|  | 691 | ALOGE("Unable to set ipe params = 0x%x\n", | 
|  | 692 | s_ipe_params_op.u4_error_code); | 
|  | 693 | return C2_CORRUPTED; | 
|  | 694 | } | 
|  | 695 | return C2_OK; | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | c2_status_t C2SoftAvcEnc::setBitRate() { | 
|  | 699 | ive_ctl_set_bitrate_ip_t s_bitrate_ip; | 
|  | 700 | ive_ctl_set_bitrate_op_t s_bitrate_op; | 
|  | 701 | IV_STATUS_T status; | 
|  | 702 |  | 
|  | 703 | s_bitrate_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 704 | s_bitrate_ip.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE; | 
|  | 705 |  | 
|  | 706 | s_bitrate_ip.u4_target_bitrate = mBitrate->value; | 
|  | 707 |  | 
|  | 708 | s_bitrate_ip.u4_timestamp_high = -1; | 
|  | 709 | s_bitrate_ip.u4_timestamp_low = -1; | 
|  | 710 |  | 
|  | 711 | s_bitrate_ip.u4_size = sizeof(ive_ctl_set_bitrate_ip_t); | 
|  | 712 | s_bitrate_op.u4_size = sizeof(ive_ctl_set_bitrate_op_t); | 
|  | 713 |  | 
|  | 714 | status = ive_api_function(mCodecCtx, &s_bitrate_ip, &s_bitrate_op); | 
|  | 715 | if (status != IV_SUCCESS) { | 
|  | 716 | ALOGE("Unable to set bit rate = 0x%x\n", s_bitrate_op.u4_error_code); | 
|  | 717 | return C2_CORRUPTED; | 
|  | 718 | } | 
|  | 719 | return C2_OK; | 
|  | 720 | } | 
|  | 721 |  | 
|  | 722 | c2_status_t C2SoftAvcEnc::setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type) { | 
|  | 723 | ive_ctl_set_frame_type_ip_t s_frame_type_ip; | 
|  | 724 | ive_ctl_set_frame_type_op_t s_frame_type_op; | 
|  | 725 | IV_STATUS_T status; | 
|  | 726 | s_frame_type_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 727 | s_frame_type_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE; | 
|  | 728 |  | 
|  | 729 | s_frame_type_ip.e_frame_type = e_frame_type; | 
|  | 730 |  | 
|  | 731 | s_frame_type_ip.u4_timestamp_high = -1; | 
|  | 732 | s_frame_type_ip.u4_timestamp_low = -1; | 
|  | 733 |  | 
|  | 734 | s_frame_type_ip.u4_size = sizeof(ive_ctl_set_frame_type_ip_t); | 
|  | 735 | s_frame_type_op.u4_size = sizeof(ive_ctl_set_frame_type_op_t); | 
|  | 736 |  | 
|  | 737 | status = ive_api_function(mCodecCtx, &s_frame_type_ip, &s_frame_type_op); | 
|  | 738 | if (status != IV_SUCCESS) { | 
|  | 739 | ALOGE("Unable to set frame type = 0x%x\n", | 
|  | 740 | s_frame_type_op.u4_error_code); | 
|  | 741 | return C2_CORRUPTED; | 
|  | 742 | } | 
|  | 743 | return C2_OK; | 
|  | 744 | } | 
|  | 745 |  | 
|  | 746 | c2_status_t C2SoftAvcEnc::setQp() { | 
|  | 747 | ive_ctl_set_qp_ip_t s_qp_ip; | 
|  | 748 | ive_ctl_set_qp_op_t s_qp_op; | 
|  | 749 | IV_STATUS_T status; | 
|  | 750 |  | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 751 | // set the defaults | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 752 | s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 753 | s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP; | 
|  | 754 |  | 
|  | 755 | s_qp_ip.u4_i_qp = DEFAULT_I_QP; | 
|  | 756 | s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX; | 
|  | 757 | s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN; | 
|  | 758 |  | 
|  | 759 | s_qp_ip.u4_p_qp = DEFAULT_P_QP; | 
|  | 760 | s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX; | 
|  | 761 | s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN; | 
|  | 762 |  | 
|  | 763 | s_qp_ip.u4_b_qp = DEFAULT_P_QP; | 
|  | 764 | s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX; | 
|  | 765 | s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN; | 
|  | 766 |  | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 767 | // parameter parsing ensured proper range 1..51, so only worry about ordering | 
|  | 768 | bool valid = true; | 
|  | 769 | if (mQuantization->iMax < mQuantization->iMin) valid = false; | 
|  | 770 | if (mQuantization->pMax < mQuantization->pMin) valid = false; | 
|  | 771 | if (mQuantization->bMax < mQuantization->bMin) valid = false; | 
|  | 772 |  | 
|  | 773 | if (valid) { | 
|  | 774 | s_qp_ip.u4_i_qp_max = mQuantization->iMax; | 
|  | 775 | s_qp_ip.u4_i_qp_min = mQuantization->iMin; | 
|  | 776 | s_qp_ip.u4_p_qp_max = mQuantization->pMax; | 
|  | 777 | s_qp_ip.u4_p_qp_min = mQuantization->pMin; | 
|  | 778 | s_qp_ip.u4_b_qp_max = mQuantization->bMax; | 
|  | 779 | s_qp_ip.u4_b_qp_min = mQuantization->bMin; | 
|  | 780 | } | 
|  | 781 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 782 | s_qp_ip.u4_timestamp_high = -1; | 
|  | 783 | s_qp_ip.u4_timestamp_low = -1; | 
|  | 784 |  | 
|  | 785 | s_qp_ip.u4_size = sizeof(ive_ctl_set_qp_ip_t); | 
|  | 786 | s_qp_op.u4_size = sizeof(ive_ctl_set_qp_op_t); | 
|  | 787 |  | 
|  | 788 | status = ive_api_function(mCodecCtx, &s_qp_ip, &s_qp_op); | 
|  | 789 | if (status != IV_SUCCESS) { | 
|  | 790 | ALOGE("Unable to set qp 0x%x\n", s_qp_op.u4_error_code); | 
|  | 791 | return C2_CORRUPTED; | 
|  | 792 | } | 
|  | 793 | return C2_OK; | 
|  | 794 | } | 
|  | 795 |  | 
|  | 796 | c2_status_t C2SoftAvcEnc::setEncMode(IVE_ENC_MODE_T e_enc_mode) { | 
|  | 797 | IV_STATUS_T status; | 
|  | 798 | ive_ctl_set_enc_mode_ip_t s_enc_mode_ip; | 
|  | 799 | ive_ctl_set_enc_mode_op_t s_enc_mode_op; | 
|  | 800 |  | 
|  | 801 | s_enc_mode_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 802 | s_enc_mode_ip.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE; | 
|  | 803 |  | 
|  | 804 | s_enc_mode_ip.e_enc_mode = e_enc_mode; | 
|  | 805 |  | 
|  | 806 | s_enc_mode_ip.u4_timestamp_high = -1; | 
|  | 807 | s_enc_mode_ip.u4_timestamp_low = -1; | 
|  | 808 |  | 
|  | 809 | s_enc_mode_ip.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t); | 
|  | 810 | s_enc_mode_op.u4_size = sizeof(ive_ctl_set_enc_mode_op_t); | 
|  | 811 |  | 
|  | 812 | status = ive_api_function(mCodecCtx, &s_enc_mode_ip, &s_enc_mode_op); | 
|  | 813 | if (status != IV_SUCCESS) { | 
|  | 814 | ALOGE("Unable to set in header encode mode = 0x%x\n", | 
|  | 815 | s_enc_mode_op.u4_error_code); | 
|  | 816 | return C2_CORRUPTED; | 
|  | 817 | } | 
|  | 818 | return C2_OK; | 
|  | 819 | } | 
|  | 820 |  | 
|  | 821 | c2_status_t C2SoftAvcEnc::setVbvParams() { | 
|  | 822 | ive_ctl_set_vbv_params_ip_t s_vbv_ip; | 
|  | 823 | ive_ctl_set_vbv_params_op_t s_vbv_op; | 
|  | 824 | IV_STATUS_T status; | 
|  | 825 |  | 
|  | 826 | s_vbv_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 827 | s_vbv_ip.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS; | 
|  | 828 |  | 
|  | 829 | s_vbv_ip.u4_vbv_buf_size = 0; | 
|  | 830 | s_vbv_ip.u4_vbv_buffer_delay = 1000; | 
|  | 831 |  | 
|  | 832 | s_vbv_ip.u4_timestamp_high = -1; | 
|  | 833 | s_vbv_ip.u4_timestamp_low = -1; | 
|  | 834 |  | 
|  | 835 | s_vbv_ip.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t); | 
|  | 836 | s_vbv_op.u4_size = sizeof(ive_ctl_set_vbv_params_op_t); | 
|  | 837 |  | 
|  | 838 | status = ive_api_function(mCodecCtx, &s_vbv_ip, &s_vbv_op); | 
|  | 839 | if (status != IV_SUCCESS) { | 
|  | 840 | ALOGE("Unable to set VBV params = 0x%x\n", s_vbv_op.u4_error_code); | 
|  | 841 | return C2_CORRUPTED; | 
|  | 842 | } | 
|  | 843 | return C2_OK; | 
|  | 844 | } | 
|  | 845 |  | 
|  | 846 | c2_status_t C2SoftAvcEnc::setAirParams() { | 
|  | 847 | ive_ctl_set_air_params_ip_t s_air_ip; | 
|  | 848 | ive_ctl_set_air_params_op_t s_air_op; | 
|  | 849 | IV_STATUS_T status; | 
|  | 850 |  | 
|  | 851 | s_air_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 852 | s_air_ip.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS; | 
|  | 853 |  | 
|  | 854 | s_air_ip.e_air_mode = | 
|  | 855 | (mIntraRefresh->mode == C2Config::INTRA_REFRESH_DISABLED || mIntraRefresh->period < 1) | 
|  | 856 | ? IVE_AIR_MODE_NONE : IVE_AIR_MODE_CYCLIC; | 
|  | 857 | s_air_ip.u4_air_refresh_period = mIntraRefresh->period; | 
|  | 858 |  | 
|  | 859 | s_air_ip.u4_timestamp_high = -1; | 
|  | 860 | s_air_ip.u4_timestamp_low = -1; | 
|  | 861 |  | 
|  | 862 | s_air_ip.u4_size = sizeof(ive_ctl_set_air_params_ip_t); | 
|  | 863 | s_air_op.u4_size = sizeof(ive_ctl_set_air_params_op_t); | 
|  | 864 |  | 
|  | 865 | status = ive_api_function(mCodecCtx, &s_air_ip, &s_air_op); | 
|  | 866 | if (status != IV_SUCCESS) { | 
|  | 867 | ALOGE("Unable to set air params = 0x%x\n", s_air_op.u4_error_code); | 
|  | 868 | return C2_CORRUPTED; | 
|  | 869 | } | 
|  | 870 | return C2_OK; | 
|  | 871 | } | 
|  | 872 |  | 
|  | 873 | c2_status_t C2SoftAvcEnc::setMeParams() { | 
|  | 874 | IV_STATUS_T status; | 
|  | 875 | ive_ctl_set_me_params_ip_t s_me_params_ip; | 
|  | 876 | ive_ctl_set_me_params_op_t s_me_params_op; | 
|  | 877 |  | 
|  | 878 | s_me_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 879 | s_me_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS; | 
|  | 880 |  | 
|  | 881 | s_me_params_ip.u4_enable_fast_sad = mEnableFastSad; | 
|  | 882 | s_me_params_ip.u4_enable_alt_ref = mEnableAltRef; | 
|  | 883 |  | 
|  | 884 | s_me_params_ip.u4_enable_hpel = mHalfPelEnable; | 
|  | 885 | s_me_params_ip.u4_enable_qpel = DEFAULT_QPEL; | 
|  | 886 | s_me_params_ip.u4_me_speed_preset = DEFAULT_ME_SPEED; | 
|  | 887 | s_me_params_ip.u4_srch_rng_x = DEFAULT_SRCH_RNG_X; | 
|  | 888 | s_me_params_ip.u4_srch_rng_y = DEFAULT_SRCH_RNG_Y; | 
|  | 889 |  | 
|  | 890 | s_me_params_ip.u4_timestamp_high = -1; | 
|  | 891 | s_me_params_ip.u4_timestamp_low = -1; | 
|  | 892 |  | 
|  | 893 | s_me_params_ip.u4_size = sizeof(ive_ctl_set_me_params_ip_t); | 
|  | 894 | s_me_params_op.u4_size = sizeof(ive_ctl_set_me_params_op_t); | 
|  | 895 |  | 
|  | 896 | status = ive_api_function(mCodecCtx, &s_me_params_ip, &s_me_params_op); | 
|  | 897 | if (status != IV_SUCCESS) { | 
|  | 898 | ALOGE("Unable to set me params = 0x%x\n", s_me_params_op.u4_error_code); | 
|  | 899 | return C2_CORRUPTED; | 
|  | 900 | } | 
|  | 901 | return C2_OK; | 
|  | 902 | } | 
|  | 903 |  | 
|  | 904 | c2_status_t C2SoftAvcEnc::setGopParams() { | 
|  | 905 | IV_STATUS_T status; | 
|  | 906 | ive_ctl_set_gop_params_ip_t s_gop_params_ip; | 
|  | 907 | ive_ctl_set_gop_params_op_t s_gop_params_op; | 
|  | 908 |  | 
|  | 909 | s_gop_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 910 | s_gop_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS; | 
|  | 911 |  | 
|  | 912 | s_gop_params_ip.u4_i_frm_interval = mIInterval; | 
|  | 913 | s_gop_params_ip.u4_idr_frm_interval = mIDRInterval; | 
|  | 914 |  | 
|  | 915 | s_gop_params_ip.u4_timestamp_high = -1; | 
|  | 916 | s_gop_params_ip.u4_timestamp_low = -1; | 
|  | 917 |  | 
|  | 918 | s_gop_params_ip.u4_size = sizeof(ive_ctl_set_gop_params_ip_t); | 
|  | 919 | s_gop_params_op.u4_size = sizeof(ive_ctl_set_gop_params_op_t); | 
|  | 920 |  | 
|  | 921 | status = ive_api_function(mCodecCtx, &s_gop_params_ip, &s_gop_params_op); | 
|  | 922 | if (status != IV_SUCCESS) { | 
|  | 923 | ALOGE("Unable to set GOP params = 0x%x\n", | 
|  | 924 | s_gop_params_op.u4_error_code); | 
|  | 925 | return C2_CORRUPTED; | 
|  | 926 | } | 
|  | 927 | return C2_OK; | 
|  | 928 | } | 
|  | 929 |  | 
|  | 930 | c2_status_t C2SoftAvcEnc::setProfileParams() { | 
|  | 931 | IntfImpl::Lock lock = mIntf->lock(); | 
|  | 932 |  | 
|  | 933 | IV_STATUS_T status; | 
|  | 934 | ive_ctl_set_profile_params_ip_t s_profile_params_ip; | 
|  | 935 | ive_ctl_set_profile_params_op_t s_profile_params_op; | 
|  | 936 |  | 
|  | 937 | s_profile_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 938 | s_profile_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS; | 
|  | 939 |  | 
|  | 940 | s_profile_params_ip.e_profile = mIntf->getProfile_l(); | 
| Harish Mahendrakar | 8725ae0 | 2018-08-31 10:33:56 -0700 | [diff] [blame] | 941 | if (s_profile_params_ip.e_profile == IV_PROFILE_BASE) { | 
|  | 942 | s_profile_params_ip.u4_entropy_coding_mode = 0; | 
|  | 943 | } else { | 
|  | 944 | s_profile_params_ip.u4_entropy_coding_mode = 1; | 
|  | 945 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 946 | s_profile_params_ip.u4_timestamp_high = -1; | 
|  | 947 | s_profile_params_ip.u4_timestamp_low = -1; | 
|  | 948 |  | 
|  | 949 | s_profile_params_ip.u4_size = sizeof(ive_ctl_set_profile_params_ip_t); | 
|  | 950 | s_profile_params_op.u4_size = sizeof(ive_ctl_set_profile_params_op_t); | 
|  | 951 | lock.unlock(); | 
|  | 952 |  | 
|  | 953 | status = ive_api_function(mCodecCtx, &s_profile_params_ip, &s_profile_params_op); | 
|  | 954 | if (status != IV_SUCCESS) { | 
|  | 955 | ALOGE("Unable to set profile params = 0x%x\n", | 
|  | 956 | s_profile_params_op.u4_error_code); | 
|  | 957 | return C2_CORRUPTED; | 
|  | 958 | } | 
|  | 959 | return C2_OK; | 
|  | 960 | } | 
|  | 961 |  | 
|  | 962 | c2_status_t C2SoftAvcEnc::setDeblockParams() { | 
|  | 963 | IV_STATUS_T status; | 
|  | 964 | ive_ctl_set_deblock_params_ip_t s_deblock_params_ip; | 
|  | 965 | ive_ctl_set_deblock_params_op_t s_deblock_params_op; | 
|  | 966 |  | 
|  | 967 | s_deblock_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 968 | s_deblock_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS; | 
|  | 969 |  | 
|  | 970 | s_deblock_params_ip.u4_disable_deblock_level = mDisableDeblkLevel; | 
|  | 971 |  | 
|  | 972 | s_deblock_params_ip.u4_timestamp_high = -1; | 
|  | 973 | s_deblock_params_ip.u4_timestamp_low = -1; | 
|  | 974 |  | 
|  | 975 | s_deblock_params_ip.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t); | 
|  | 976 | s_deblock_params_op.u4_size = sizeof(ive_ctl_set_deblock_params_op_t); | 
|  | 977 |  | 
|  | 978 | status = ive_api_function(mCodecCtx, &s_deblock_params_ip, &s_deblock_params_op); | 
|  | 979 | if (status != IV_SUCCESS) { | 
|  | 980 | ALOGE("Unable to enable/disable deblock params = 0x%x\n", | 
|  | 981 | s_deblock_params_op.u4_error_code); | 
|  | 982 | return C2_CORRUPTED; | 
|  | 983 | } | 
|  | 984 | return C2_OK; | 
|  | 985 | } | 
|  | 986 |  | 
|  | 987 | void C2SoftAvcEnc::logVersion() { | 
|  | 988 | ive_ctl_getversioninfo_ip_t s_ctl_ip; | 
|  | 989 | ive_ctl_getversioninfo_op_t s_ctl_op; | 
|  | 990 | UWORD8 au1_buf[512]; | 
|  | 991 | IV_STATUS_T status; | 
|  | 992 |  | 
|  | 993 | s_ctl_ip.e_cmd = IVE_CMD_VIDEO_CTL; | 
|  | 994 | s_ctl_ip.e_sub_cmd = IVE_CMD_CTL_GETVERSION; | 
|  | 995 | s_ctl_ip.u4_size = sizeof(ive_ctl_getversioninfo_ip_t); | 
|  | 996 | s_ctl_op.u4_size = sizeof(ive_ctl_getversioninfo_op_t); | 
|  | 997 | s_ctl_ip.pu1_version = au1_buf; | 
|  | 998 | s_ctl_ip.u4_version_bufsize = sizeof(au1_buf); | 
|  | 999 |  | 
|  | 1000 | status = ive_api_function(mCodecCtx, (void *) &s_ctl_ip, (void *) &s_ctl_op); | 
|  | 1001 |  | 
|  | 1002 | if (status != IV_SUCCESS) { | 
|  | 1003 | ALOGE("Error in getting version: 0x%x", s_ctl_op.u4_error_code); | 
|  | 1004 | } else { | 
|  | 1005 | ALOGV("Ittiam encoder version: %s", (char *)s_ctl_ip.pu1_version); | 
|  | 1006 | } | 
|  | 1007 | return; | 
|  | 1008 | } | 
|  | 1009 |  | 
|  | 1010 | c2_status_t C2SoftAvcEnc::initEncoder() { | 
|  | 1011 | IV_STATUS_T status; | 
|  | 1012 | WORD32 level; | 
|  | 1013 |  | 
|  | 1014 | CHECK(!mStarted); | 
|  | 1015 |  | 
|  | 1016 | c2_status_t errType = C2_OK; | 
|  | 1017 |  | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 1018 | std::shared_ptr<C2StreamGopTuning::output> gop; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1019 | { | 
|  | 1020 | IntfImpl::Lock lock = mIntf->lock(); | 
|  | 1021 | mSize = mIntf->getSize_l(); | 
|  | 1022 | mBitrate = mIntf->getBitrate_l(); | 
|  | 1023 | mFrameRate = mIntf->getFrameRate_l(); | 
|  | 1024 | mIntraRefresh = mIntf->getIntraRefresh_l(); | 
|  | 1025 | mAVCEncLevel = mIntf->getLevel_l(); | 
|  | 1026 | mIInterval = mIntf->getSyncFramePeriod_l(); | 
|  | 1027 | mIDRInterval = mIntf->getSyncFramePeriod_l(); | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 1028 | gop = mIntf->getGop_l(); | 
| Ray Essick | 825104d | 2021-03-04 13:29:57 -0800 | [diff] [blame^] | 1029 | mQuantization = mIntf->getQuantization_l(); | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 1030 | } | 
|  | 1031 | if (gop && gop->flexCount() > 0) { | 
|  | 1032 | uint32_t syncInterval = 1; | 
|  | 1033 | uint32_t iInterval = 1; | 
|  | 1034 | uint32_t maxBframes = 0; | 
|  | 1035 | ParseGop(*gop, &syncInterval, &iInterval, &maxBframes); | 
|  | 1036 | if (syncInterval > 0) { | 
|  | 1037 | ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval); | 
|  | 1038 | mIDRInterval = syncInterval; | 
|  | 1039 | } | 
|  | 1040 | if (iInterval > 0) { | 
|  | 1041 | ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval); | 
|  | 1042 | mIInterval = iInterval; | 
|  | 1043 | } | 
|  | 1044 | if (mBframes != maxBframes) { | 
|  | 1045 | ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes); | 
|  | 1046 | mBframes = maxBframes; | 
|  | 1047 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1048 | } | 
|  | 1049 | uint32_t width = mSize->width; | 
|  | 1050 | uint32_t height = mSize->height; | 
|  | 1051 |  | 
|  | 1052 | mStride = width; | 
|  | 1053 |  | 
| Harish Mahendrakar | ea0eb37 | 2019-11-21 10:33:05 -0800 | [diff] [blame] | 1054 | // Assume worst case output buffer size to be equal to number of bytes in input | 
|  | 1055 | mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize); | 
|  | 1056 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1057 | // TODO | 
|  | 1058 | mIvVideoColorFormat = IV_YUV_420P; | 
|  | 1059 |  | 
| Wonsik Kim | e1c360a | 2019-05-22 10:38:58 -0700 | [diff] [blame] | 1060 | ALOGD("Params width %d height %d level %d colorFormat %d bframes %d", width, | 
|  | 1061 | height, mAVCEncLevel, mIvVideoColorFormat, mBframes); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1062 |  | 
|  | 1063 | /* Getting Number of MemRecords */ | 
|  | 1064 | { | 
|  | 1065 | iv_num_mem_rec_ip_t s_num_mem_rec_ip; | 
|  | 1066 | iv_num_mem_rec_op_t s_num_mem_rec_op; | 
|  | 1067 |  | 
|  | 1068 | s_num_mem_rec_ip.u4_size = sizeof(iv_num_mem_rec_ip_t); | 
|  | 1069 | s_num_mem_rec_op.u4_size = sizeof(iv_num_mem_rec_op_t); | 
|  | 1070 |  | 
|  | 1071 | s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; | 
|  | 1072 |  | 
|  | 1073 | status = ive_api_function(nullptr, &s_num_mem_rec_ip, &s_num_mem_rec_op); | 
|  | 1074 |  | 
|  | 1075 | if (status != IV_SUCCESS) { | 
|  | 1076 | ALOGE("Get number of memory records failed = 0x%x\n", | 
|  | 1077 | s_num_mem_rec_op.u4_error_code); | 
|  | 1078 | return C2_CORRUPTED; | 
|  | 1079 | } | 
|  | 1080 |  | 
|  | 1081 | mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; | 
|  | 1082 | } | 
|  | 1083 |  | 
|  | 1084 | /* Allocate array to hold memory records */ | 
|  | 1085 | if (mNumMemRecords > SIZE_MAX / sizeof(iv_mem_rec_t)) { | 
|  | 1086 | ALOGE("requested memory size is too big."); | 
|  | 1087 | return C2_CORRUPTED; | 
|  | 1088 | } | 
|  | 1089 | mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t)); | 
|  | 1090 | if (nullptr == mMemRecords) { | 
|  | 1091 | ALOGE("Unable to allocate memory for hold memory records: Size %zu", | 
|  | 1092 | mNumMemRecords * sizeof(iv_mem_rec_t)); | 
|  | 1093 | mSignalledError = true; | 
|  | 1094 | return C2_CORRUPTED; | 
|  | 1095 | } | 
|  | 1096 |  | 
|  | 1097 | { | 
|  | 1098 | iv_mem_rec_t *ps_mem_rec; | 
|  | 1099 | ps_mem_rec = mMemRecords; | 
|  | 1100 | for (size_t i = 0; i < mNumMemRecords; i++) { | 
|  | 1101 | ps_mem_rec->u4_size = sizeof(iv_mem_rec_t); | 
|  | 1102 | ps_mem_rec->pv_base = nullptr; | 
|  | 1103 | ps_mem_rec->u4_mem_size = 0; | 
|  | 1104 | ps_mem_rec->u4_mem_alignment = 0; | 
|  | 1105 | ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE; | 
|  | 1106 |  | 
|  | 1107 | ps_mem_rec++; | 
|  | 1108 | } | 
|  | 1109 | } | 
|  | 1110 |  | 
|  | 1111 | /* Getting MemRecords Attributes */ | 
|  | 1112 | { | 
|  | 1113 | iv_fill_mem_rec_ip_t s_fill_mem_rec_ip; | 
|  | 1114 | iv_fill_mem_rec_op_t s_fill_mem_rec_op; | 
|  | 1115 |  | 
|  | 1116 | s_fill_mem_rec_ip.u4_size = sizeof(iv_fill_mem_rec_ip_t); | 
|  | 1117 | s_fill_mem_rec_op.u4_size = sizeof(iv_fill_mem_rec_op_t); | 
|  | 1118 |  | 
|  | 1119 | s_fill_mem_rec_ip.e_cmd = IV_CMD_FILL_NUM_MEM_REC; | 
|  | 1120 | s_fill_mem_rec_ip.ps_mem_rec = mMemRecords; | 
|  | 1121 | s_fill_mem_rec_ip.u4_num_mem_rec = mNumMemRecords; | 
|  | 1122 | s_fill_mem_rec_ip.u4_max_wd = width; | 
|  | 1123 | s_fill_mem_rec_ip.u4_max_ht = height; | 
|  | 1124 | s_fill_mem_rec_ip.u4_max_level = mAVCEncLevel; | 
|  | 1125 | s_fill_mem_rec_ip.e_color_format = DEFAULT_INP_COLOR_FORMAT; | 
|  | 1126 | s_fill_mem_rec_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; | 
|  | 1127 | s_fill_mem_rec_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; | 
|  | 1128 | s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; | 
|  | 1129 | s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; | 
|  | 1130 |  | 
|  | 1131 | status = ive_api_function(nullptr, &s_fill_mem_rec_ip, &s_fill_mem_rec_op); | 
|  | 1132 |  | 
|  | 1133 | if (status != IV_SUCCESS) { | 
|  | 1134 | ALOGE("Fill memory records failed = 0x%x\n", | 
|  | 1135 | s_fill_mem_rec_op.u4_error_code); | 
|  | 1136 | return C2_CORRUPTED; | 
|  | 1137 | } | 
|  | 1138 | } | 
|  | 1139 |  | 
|  | 1140 | /* Allocating Memory for Mem Records */ | 
|  | 1141 | { | 
|  | 1142 | WORD32 total_size; | 
|  | 1143 | iv_mem_rec_t *ps_mem_rec; | 
|  | 1144 | total_size = 0; | 
|  | 1145 | ps_mem_rec = mMemRecords; | 
|  | 1146 |  | 
|  | 1147 | for (size_t i = 0; i < mNumMemRecords; i++) { | 
|  | 1148 | ps_mem_rec->pv_base = ive_aligned_malloc( | 
|  | 1149 | ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); | 
|  | 1150 | if (ps_mem_rec->pv_base == nullptr) { | 
|  | 1151 | ALOGE("Allocation failure for mem record id %zu size %u\n", i, | 
|  | 1152 | ps_mem_rec->u4_mem_size); | 
|  | 1153 | return C2_CORRUPTED; | 
|  | 1154 |  | 
|  | 1155 | } | 
|  | 1156 | total_size += ps_mem_rec->u4_mem_size; | 
|  | 1157 |  | 
|  | 1158 | ps_mem_rec++; | 
|  | 1159 | } | 
|  | 1160 | } | 
|  | 1161 |  | 
|  | 1162 | /* Codec Instance Creation */ | 
|  | 1163 | { | 
|  | 1164 | ive_init_ip_t s_init_ip; | 
|  | 1165 | ive_init_op_t s_init_op; | 
|  | 1166 |  | 
|  | 1167 | mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; | 
|  | 1168 | mCodecCtx->u4_size = sizeof(iv_obj_t); | 
|  | 1169 | mCodecCtx->pv_fxns = (void *)ive_api_function; | 
|  | 1170 |  | 
|  | 1171 | s_init_ip.u4_size = sizeof(ive_init_ip_t); | 
|  | 1172 | s_init_op.u4_size = sizeof(ive_init_op_t); | 
|  | 1173 |  | 
|  | 1174 | s_init_ip.e_cmd = IV_CMD_INIT; | 
|  | 1175 | s_init_ip.u4_num_mem_rec = mNumMemRecords; | 
|  | 1176 | s_init_ip.ps_mem_rec = mMemRecords; | 
|  | 1177 | s_init_ip.u4_max_wd = width; | 
|  | 1178 | s_init_ip.u4_max_ht = height; | 
|  | 1179 | s_init_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; | 
|  | 1180 | s_init_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; | 
|  | 1181 | s_init_ip.u4_max_level = mAVCEncLevel; | 
|  | 1182 | s_init_ip.e_inp_color_fmt = mIvVideoColorFormat; | 
|  | 1183 |  | 
|  | 1184 | if (mReconEnable || mPSNREnable) { | 
|  | 1185 | s_init_ip.u4_enable_recon = 1; | 
|  | 1186 | } else { | 
|  | 1187 | s_init_ip.u4_enable_recon = 0; | 
|  | 1188 | } | 
|  | 1189 | s_init_ip.e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT; | 
|  | 1190 | s_init_ip.e_rc_mode = DEFAULT_RC_MODE; | 
|  | 1191 | s_init_ip.u4_max_framerate = DEFAULT_MAX_FRAMERATE; | 
|  | 1192 | s_init_ip.u4_max_bitrate = DEFAULT_MAX_BITRATE; | 
|  | 1193 | s_init_ip.u4_num_bframes = mBframes; | 
|  | 1194 | s_init_ip.e_content_type = IV_PROGRESSIVE; | 
|  | 1195 | s_init_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; | 
|  | 1196 | s_init_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; | 
|  | 1197 | s_init_ip.e_slice_mode = mSliceMode; | 
|  | 1198 | s_init_ip.u4_slice_param = mSliceParam; | 
|  | 1199 | s_init_ip.e_arch = mArch; | 
|  | 1200 | s_init_ip.e_soc = DEFAULT_SOC; | 
|  | 1201 |  | 
|  | 1202 | status = ive_api_function(mCodecCtx, &s_init_ip, &s_init_op); | 
|  | 1203 |  | 
|  | 1204 | if (status != IV_SUCCESS) { | 
|  | 1205 | ALOGE("Init encoder failed = 0x%x\n", s_init_op.u4_error_code); | 
|  | 1206 | return C2_CORRUPTED; | 
|  | 1207 | } | 
|  | 1208 | } | 
|  | 1209 |  | 
|  | 1210 | /* Get Codec Version */ | 
|  | 1211 | logVersion(); | 
|  | 1212 |  | 
|  | 1213 | /* set processor details */ | 
|  | 1214 | setNumCores(); | 
|  | 1215 |  | 
|  | 1216 | /* Video control Set Frame dimensions */ | 
|  | 1217 | setDimensions(); | 
|  | 1218 |  | 
|  | 1219 | /* Video control Set Frame rates */ | 
|  | 1220 | setFrameRate(); | 
|  | 1221 |  | 
|  | 1222 | /* Video control Set IPE Params */ | 
|  | 1223 | setIpeParams(); | 
|  | 1224 |  | 
|  | 1225 | /* Video control Set Bitrate */ | 
|  | 1226 | setBitRate(); | 
|  | 1227 |  | 
|  | 1228 | /* Video control Set QP */ | 
|  | 1229 | setQp(); | 
|  | 1230 |  | 
|  | 1231 | /* Video control Set AIR params */ | 
|  | 1232 | setAirParams(); | 
|  | 1233 |  | 
|  | 1234 | /* Video control Set VBV params */ | 
|  | 1235 | setVbvParams(); | 
|  | 1236 |  | 
|  | 1237 | /* Video control Set Motion estimation params */ | 
|  | 1238 | setMeParams(); | 
|  | 1239 |  | 
|  | 1240 | /* Video control Set GOP params */ | 
|  | 1241 | setGopParams(); | 
|  | 1242 |  | 
|  | 1243 | /* Video control Set Deblock params */ | 
|  | 1244 | setDeblockParams(); | 
|  | 1245 |  | 
|  | 1246 | /* Video control Set Profile params */ | 
|  | 1247 | setProfileParams(); | 
|  | 1248 |  | 
|  | 1249 | /* Video control Set in Encode header mode */ | 
|  | 1250 | setEncMode(IVE_ENC_MODE_HEADER); | 
|  | 1251 |  | 
|  | 1252 | ALOGV("init_codec successfull"); | 
|  | 1253 |  | 
|  | 1254 | mSpsPpsHeaderReceived = false; | 
|  | 1255 | mStarted = true; | 
|  | 1256 |  | 
|  | 1257 | return C2_OK; | 
|  | 1258 | } | 
|  | 1259 |  | 
|  | 1260 | c2_status_t C2SoftAvcEnc::releaseEncoder() { | 
|  | 1261 | IV_STATUS_T status = IV_SUCCESS; | 
|  | 1262 | iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip; | 
|  | 1263 | iv_retrieve_mem_rec_op_t s_retrieve_mem_op; | 
|  | 1264 | iv_mem_rec_t *ps_mem_rec; | 
|  | 1265 |  | 
|  | 1266 | if (!mStarted) { | 
|  | 1267 | return C2_OK; | 
|  | 1268 | } | 
|  | 1269 |  | 
|  | 1270 | s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t); | 
|  | 1271 | s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t); | 
|  | 1272 | s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC; | 
|  | 1273 | s_retrieve_mem_ip.ps_mem_rec = mMemRecords; | 
|  | 1274 |  | 
|  | 1275 | status = ive_api_function(mCodecCtx, &s_retrieve_mem_ip, &s_retrieve_mem_op); | 
|  | 1276 |  | 
|  | 1277 | if (status != IV_SUCCESS) { | 
|  | 1278 | ALOGE("Unable to retrieve memory records = 0x%x\n", | 
|  | 1279 | s_retrieve_mem_op.u4_error_code); | 
|  | 1280 | return C2_CORRUPTED; | 
|  | 1281 | } | 
|  | 1282 |  | 
|  | 1283 | /* Free memory records */ | 
|  | 1284 | ps_mem_rec = mMemRecords; | 
|  | 1285 | for (size_t i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) { | 
|  | 1286 | if (ps_mem_rec) ive_aligned_free(ps_mem_rec->pv_base); | 
|  | 1287 | else { | 
|  | 1288 | ALOGE("memory record is null."); | 
|  | 1289 | return C2_CORRUPTED; | 
|  | 1290 | } | 
|  | 1291 | ps_mem_rec++; | 
|  | 1292 | } | 
|  | 1293 |  | 
|  | 1294 | if (mMemRecords) free(mMemRecords); | 
|  | 1295 |  | 
|  | 1296 | // clear other pointers into the space being free()d | 
|  | 1297 | mCodecCtx = nullptr; | 
|  | 1298 |  | 
|  | 1299 | mStarted = false; | 
|  | 1300 |  | 
|  | 1301 | return C2_OK; | 
|  | 1302 | } | 
|  | 1303 |  | 
|  | 1304 | c2_status_t C2SoftAvcEnc::setEncodeArgs( | 
|  | 1305 | ive_video_encode_ip_t *ps_encode_ip, | 
|  | 1306 | ive_video_encode_op_t *ps_encode_op, | 
|  | 1307 | const C2GraphicView *const input, | 
|  | 1308 | uint8_t *base, | 
|  | 1309 | uint32_t capacity, | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1310 | uint64_t workIndex) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1311 | iv_raw_buf_t *ps_inp_raw_buf; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1312 | memset(ps_encode_ip, 0, sizeof(*ps_encode_ip)); | 
|  | 1313 | memset(ps_encode_op, 0, sizeof(*ps_encode_op)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1314 |  | 
|  | 1315 | ps_inp_raw_buf = &ps_encode_ip->s_inp_buf; | 
|  | 1316 | ps_encode_ip->s_out_buf.pv_buf = base; | 
|  | 1317 | ps_encode_ip->s_out_buf.u4_bytes = 0; | 
|  | 1318 | ps_encode_ip->s_out_buf.u4_bufsize = capacity; | 
|  | 1319 | ps_encode_ip->u4_size = sizeof(ive_video_encode_ip_t); | 
|  | 1320 | ps_encode_op->u4_size = sizeof(ive_video_encode_op_t); | 
|  | 1321 |  | 
|  | 1322 | ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE; | 
|  | 1323 | ps_encode_ip->pv_bufs = nullptr; | 
|  | 1324 | ps_encode_ip->pv_mb_info = nullptr; | 
|  | 1325 | ps_encode_ip->pv_pic_info = nullptr; | 
|  | 1326 | ps_encode_ip->u4_mb_info_type = 0; | 
|  | 1327 | ps_encode_ip->u4_pic_info_type = 0; | 
|  | 1328 | ps_encode_ip->u4_is_last = 0; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1329 | ps_encode_ip->u4_timestamp_high = workIndex >> 32; | 
|  | 1330 | ps_encode_ip->u4_timestamp_low = workIndex & 0xFFFFFFFF; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1331 | ps_encode_op->s_out_buf.pv_buf = nullptr; | 
|  | 1332 |  | 
|  | 1333 | /* Initialize color formats */ | 
|  | 1334 | memset(ps_inp_raw_buf, 0, sizeof(iv_raw_buf_t)); | 
|  | 1335 | ps_inp_raw_buf->u4_size = sizeof(iv_raw_buf_t); | 
|  | 1336 | ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat; | 
|  | 1337 | if (input == nullptr) { | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1338 | if (mSawInputEOS) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1339 | ps_encode_ip->u4_is_last = 1; | 
|  | 1340 | } | 
|  | 1341 | return C2_OK; | 
|  | 1342 | } | 
|  | 1343 |  | 
|  | 1344 | if (input->width() < mSize->width || | 
|  | 1345 | input->height() < mSize->height) { | 
|  | 1346 | /* Expect width height to be configured */ | 
|  | 1347 | ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", input->width(), | 
|  | 1348 | mSize->width, input->height(), mSize->height); | 
|  | 1349 | return C2_BAD_VALUE; | 
|  | 1350 | } | 
|  | 1351 | ALOGV("width = %d, height = %d", input->width(), input->height()); | 
|  | 1352 | const C2PlanarLayout &layout = input->layout(); | 
|  | 1353 | uint8_t *yPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]); | 
|  | 1354 | uint8_t *uPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]); | 
|  | 1355 | uint8_t *vPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_V]); | 
|  | 1356 | int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc; | 
|  | 1357 | int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc; | 
|  | 1358 | int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc; | 
|  | 1359 |  | 
|  | 1360 | uint32_t width = mSize->width; | 
|  | 1361 | uint32_t height = mSize->height; | 
|  | 1362 | // width and height are always even (as block size is 16x16) | 
|  | 1363 | CHECK_EQ((width & 1u), 0u); | 
|  | 1364 | CHECK_EQ((height & 1u), 0u); | 
|  | 1365 | size_t yPlaneSize = width * height; | 
|  | 1366 |  | 
|  | 1367 | switch (layout.type) { | 
|  | 1368 | case C2PlanarLayout::TYPE_RGB: | 
|  | 1369 | [[fallthrough]]; | 
|  | 1370 | case C2PlanarLayout::TYPE_RGBA: { | 
|  | 1371 | ALOGV("yPlaneSize = %zu", yPlaneSize); | 
|  | 1372 | MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2); | 
|  | 1373 | mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer); | 
|  | 1374 | yPlane = conversionBuffer.data(); | 
|  | 1375 | uPlane = yPlane + yPlaneSize; | 
|  | 1376 | vPlane = uPlane + yPlaneSize / 4; | 
|  | 1377 | yStride = width; | 
|  | 1378 | uStride = vStride = yStride / 2; | 
|  | 1379 | ConvertRGBToPlanarYUV(yPlane, yStride, height, conversionBuffer.size(), *input); | 
|  | 1380 | break; | 
|  | 1381 | } | 
|  | 1382 | case C2PlanarLayout::TYPE_YUV: { | 
|  | 1383 | if (!IsYUV420(*input)) { | 
|  | 1384 | ALOGE("input is not YUV420"); | 
|  | 1385 | return C2_BAD_VALUE; | 
|  | 1386 | } | 
|  | 1387 |  | 
|  | 1388 | if (layout.planes[layout.PLANE_Y].colInc == 1 | 
|  | 1389 | && layout.planes[layout.PLANE_U].colInc == 1 | 
|  | 1390 | && layout.planes[layout.PLANE_V].colInc == 1 | 
|  | 1391 | && uStride == vStride | 
|  | 1392 | && yStride == 2 * vStride) { | 
|  | 1393 | // I420 compatible - already set up above | 
|  | 1394 | break; | 
|  | 1395 | } | 
|  | 1396 |  | 
|  | 1397 | // copy to I420 | 
|  | 1398 | yStride = width; | 
|  | 1399 | uStride = vStride = yStride / 2; | 
|  | 1400 | MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2); | 
|  | 1401 | mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer); | 
|  | 1402 | MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, yStride, height); | 
|  | 1403 | status_t err = ImageCopy(conversionBuffer.data(), &img, *input); | 
|  | 1404 | if (err != OK) { | 
|  | 1405 | ALOGE("Buffer conversion failed: %d", err); | 
|  | 1406 | return C2_BAD_VALUE; | 
|  | 1407 | } | 
|  | 1408 | yPlane = conversionBuffer.data(); | 
|  | 1409 | uPlane = yPlane + yPlaneSize; | 
|  | 1410 | vPlane = uPlane + yPlaneSize / 4; | 
|  | 1411 | break; | 
|  | 1412 |  | 
|  | 1413 | } | 
|  | 1414 |  | 
|  | 1415 | case C2PlanarLayout::TYPE_YUVA: | 
|  | 1416 | ALOGE("YUVA plane type is not supported"); | 
|  | 1417 | return C2_BAD_VALUE; | 
|  | 1418 |  | 
|  | 1419 | default: | 
|  | 1420 | ALOGE("Unrecognized plane type: %d", layout.type); | 
|  | 1421 | return C2_BAD_VALUE; | 
|  | 1422 | } | 
|  | 1423 |  | 
|  | 1424 | switch (mIvVideoColorFormat) { | 
|  | 1425 | case IV_YUV_420P: | 
|  | 1426 | { | 
|  | 1427 | // input buffer is supposed to be const but Ittiam API wants bare pointer. | 
|  | 1428 | ps_inp_raw_buf->apv_bufs[0] = yPlane; | 
|  | 1429 | ps_inp_raw_buf->apv_bufs[1] = uPlane; | 
|  | 1430 | ps_inp_raw_buf->apv_bufs[2] = vPlane; | 
|  | 1431 |  | 
|  | 1432 | ps_inp_raw_buf->au4_wd[0] = input->width(); | 
|  | 1433 | ps_inp_raw_buf->au4_wd[1] = input->width() / 2; | 
|  | 1434 | ps_inp_raw_buf->au4_wd[2] = input->width() / 2; | 
|  | 1435 |  | 
|  | 1436 | ps_inp_raw_buf->au4_ht[0] = input->height(); | 
|  | 1437 | ps_inp_raw_buf->au4_ht[1] = input->height() / 2; | 
|  | 1438 | ps_inp_raw_buf->au4_ht[2] = input->height() / 2; | 
|  | 1439 |  | 
|  | 1440 | ps_inp_raw_buf->au4_strd[0] = yStride; | 
|  | 1441 | ps_inp_raw_buf->au4_strd[1] = uStride; | 
|  | 1442 | ps_inp_raw_buf->au4_strd[2] = vStride; | 
|  | 1443 | break; | 
|  | 1444 | } | 
|  | 1445 |  | 
|  | 1446 | case IV_YUV_422ILE: | 
|  | 1447 | { | 
|  | 1448 | // TODO | 
|  | 1449 | // ps_inp_raw_buf->apv_bufs[0] = pu1_buf; | 
|  | 1450 | // ps_inp_raw_buf->au4_wd[0] = mWidth * 2; | 
|  | 1451 | // ps_inp_raw_buf->au4_ht[0] = mHeight; | 
|  | 1452 | // ps_inp_raw_buf->au4_strd[0] = mStride * 2; | 
|  | 1453 | break; | 
|  | 1454 | } | 
|  | 1455 |  | 
|  | 1456 | case IV_YUV_420SP_UV: | 
|  | 1457 | case IV_YUV_420SP_VU: | 
|  | 1458 | default: | 
|  | 1459 | { | 
|  | 1460 | ps_inp_raw_buf->apv_bufs[0] = yPlane; | 
|  | 1461 | ps_inp_raw_buf->apv_bufs[1] = uPlane; | 
|  | 1462 |  | 
|  | 1463 | ps_inp_raw_buf->au4_wd[0] = input->width(); | 
|  | 1464 | ps_inp_raw_buf->au4_wd[1] = input->width(); | 
|  | 1465 |  | 
|  | 1466 | ps_inp_raw_buf->au4_ht[0] = input->height(); | 
|  | 1467 | ps_inp_raw_buf->au4_ht[1] = input->height() / 2; | 
|  | 1468 |  | 
|  | 1469 | ps_inp_raw_buf->au4_strd[0] = yStride; | 
|  | 1470 | ps_inp_raw_buf->au4_strd[1] = uStride; | 
|  | 1471 | break; | 
|  | 1472 | } | 
|  | 1473 | } | 
|  | 1474 | return C2_OK; | 
|  | 1475 | } | 
|  | 1476 |  | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1477 | void C2SoftAvcEnc::finishWork(uint64_t workIndex, const std::unique_ptr<C2Work> &work, | 
|  | 1478 | ive_video_encode_op_t *ps_encode_op) { | 
|  | 1479 | std::shared_ptr<C2Buffer> buffer = | 
|  | 1480 | createLinearBuffer(mOutBlock, 0, ps_encode_op->s_out_buf.u4_bytes); | 
|  | 1481 | if (IV_IDR_FRAME == ps_encode_op->u4_encoded_frame_type) { | 
|  | 1482 | ALOGV("IDR frame produced"); | 
|  | 1483 | buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>( | 
|  | 1484 | 0u /* stream id */, C2Config::SYNC_FRAME)); | 
|  | 1485 | } | 
|  | 1486 | mOutBlock = nullptr; | 
|  | 1487 |  | 
|  | 1488 | auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) { | 
|  | 1489 | work->worklets.front()->output.flags = (C2FrameData::flags_t)0; | 
|  | 1490 | work->worklets.front()->output.buffers.clear(); | 
|  | 1491 | work->worklets.front()->output.buffers.push_back(buffer); | 
|  | 1492 | work->worklets.front()->output.ordinal = work->input.ordinal; | 
|  | 1493 | work->workletsProcessed = 1u; | 
|  | 1494 | }; | 
|  | 1495 | if (work && c2_cntr64_t(workIndex) == work->input.ordinal.frameIndex) { | 
|  | 1496 | fillWork(work); | 
|  | 1497 | if (mSawInputEOS) { | 
|  | 1498 | work->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM; | 
|  | 1499 | } | 
|  | 1500 | } else { | 
|  | 1501 | finish(workIndex, fillWork); | 
|  | 1502 | } | 
|  | 1503 | } | 
|  | 1504 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1505 | void C2SoftAvcEnc::process( | 
|  | 1506 | const std::unique_ptr<C2Work> &work, | 
|  | 1507 | const std::shared_ptr<C2BlockPool> &pool) { | 
|  | 1508 | // Initialize output work | 
|  | 1509 | work->result = C2_OK; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1510 | work->workletsProcessed = 0u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1511 | work->worklets.front()->output.flags = work->input.flags; | 
|  | 1512 |  | 
|  | 1513 | IV_STATUS_T status; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1514 | WORD32 timeDelay = 0; | 
|  | 1515 | WORD32 timeTaken = 0; | 
|  | 1516 | uint64_t workIndex = work->input.ordinal.frameIndex.peekull(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1517 |  | 
|  | 1518 | // Initialize encoder if not already initialized | 
|  | 1519 | if (mCodecCtx == nullptr) { | 
|  | 1520 | if (C2_OK != initEncoder()) { | 
|  | 1521 | ALOGE("Failed to initialize encoder"); | 
|  | 1522 | mSignalledError = true; | 
|  | 1523 | work->result = C2_CORRUPTED; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1524 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1525 | return; | 
|  | 1526 | } | 
|  | 1527 | } | 
|  | 1528 | if (mSignalledError) { | 
|  | 1529 | return; | 
|  | 1530 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1531 | // while (!mSawOutputEOS && !outQueue.empty()) { | 
|  | 1532 | c2_status_t error; | 
|  | 1533 | ive_video_encode_ip_t s_encode_ip; | 
|  | 1534 | ive_video_encode_op_t s_encode_op; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1535 | memset(&s_encode_op, 0, sizeof(s_encode_op)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1536 |  | 
|  | 1537 | if (!mSpsPpsHeaderReceived) { | 
|  | 1538 | constexpr uint32_t kHeaderLength = MIN_STREAM_SIZE; | 
|  | 1539 | uint8_t header[kHeaderLength]; | 
|  | 1540 | error = setEncodeArgs( | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1541 | &s_encode_ip, &s_encode_op, nullptr, header, kHeaderLength, workIndex); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1542 | if (error != C2_OK) { | 
|  | 1543 | ALOGE("setEncodeArgs failed: %d", error); | 
|  | 1544 | mSignalledError = true; | 
|  | 1545 | work->result = C2_CORRUPTED; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1546 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1547 | return; | 
|  | 1548 | } | 
|  | 1549 | status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); | 
|  | 1550 |  | 
|  | 1551 | if (IV_SUCCESS != status) { | 
|  | 1552 | ALOGE("Encode header failed = 0x%x\n", | 
|  | 1553 | s_encode_op.u4_error_code); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1554 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1555 | return; | 
|  | 1556 | } else { | 
|  | 1557 | ALOGV("Bytes Generated in header %d\n", | 
|  | 1558 | s_encode_op.s_out_buf.u4_bytes); | 
|  | 1559 | } | 
|  | 1560 |  | 
|  | 1561 | mSpsPpsHeaderReceived = true; | 
|  | 1562 |  | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 1563 | std::unique_ptr<C2StreamInitDataInfo::output> csd = | 
|  | 1564 | C2StreamInitDataInfo::output::AllocUnique(s_encode_op.s_out_buf.u4_bytes, 0u); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1565 | if (!csd) { | 
|  | 1566 | ALOGE("CSD allocation failed"); | 
|  | 1567 | mSignalledError = true; | 
|  | 1568 | work->result = C2_NO_MEMORY; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1569 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1570 | return; | 
|  | 1571 | } | 
|  | 1572 | memcpy(csd->m.value, header, s_encode_op.s_out_buf.u4_bytes); | 
|  | 1573 | work->worklets.front()->output.configUpdate.push_back(std::move(csd)); | 
|  | 1574 |  | 
|  | 1575 | DUMP_TO_FILE( | 
|  | 1576 | mOutFile, csd->m.value, csd->flexCount()); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1577 | if (work->input.buffers.empty()) { | 
|  | 1578 | work->workletsProcessed = 1u; | 
|  | 1579 | return; | 
|  | 1580 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1581 | } | 
|  | 1582 |  | 
|  | 1583 | // handle dynamic config parameters | 
|  | 1584 | { | 
|  | 1585 | IntfImpl::Lock lock = mIntf->lock(); | 
|  | 1586 | std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh = mIntf->getIntraRefresh_l(); | 
|  | 1587 | std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l(); | 
|  | 1588 | std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l(); | 
|  | 1589 | lock.unlock(); | 
|  | 1590 |  | 
|  | 1591 | if (bitrate != mBitrate) { | 
|  | 1592 | mBitrate = bitrate; | 
|  | 1593 | setBitRate(); | 
|  | 1594 | } | 
|  | 1595 |  | 
|  | 1596 | if (intraRefresh != mIntraRefresh) { | 
|  | 1597 | mIntraRefresh = intraRefresh; | 
|  | 1598 | setAirParams(); | 
|  | 1599 | } | 
|  | 1600 |  | 
|  | 1601 | if (requestSync != mRequestSync) { | 
|  | 1602 | // we can handle IDR immediately | 
|  | 1603 | if (requestSync->value) { | 
|  | 1604 | // unset request | 
|  | 1605 | C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE); | 
|  | 1606 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
|  | 1607 | mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures); | 
|  | 1608 | ALOGV("Got sync request"); | 
|  | 1609 | setFrameType(IV_IDR_FRAME); | 
|  | 1610 | } | 
|  | 1611 | mRequestSync = requestSync; | 
|  | 1612 | } | 
|  | 1613 | } | 
|  | 1614 |  | 
|  | 1615 | if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { | 
|  | 1616 | mSawInputEOS = true; | 
|  | 1617 | } | 
|  | 1618 |  | 
|  | 1619 | /* In normal mode, store inputBufferInfo and this will be returned | 
|  | 1620 | when encoder consumes this input */ | 
|  | 1621 | // if (!mInputDataIsMeta && (inputBufferInfo != NULL)) { | 
|  | 1622 | //     for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) { | 
|  | 1623 | //         if (NULL == mInputBufferInfo[i]) { | 
|  | 1624 | //             mInputBufferInfo[i] = inputBufferInfo; | 
|  | 1625 | //             break; | 
|  | 1626 | //         } | 
|  | 1627 | //     } | 
|  | 1628 | // } | 
|  | 1629 | std::shared_ptr<const C2GraphicView> view; | 
|  | 1630 | std::shared_ptr<C2Buffer> inputBuffer; | 
|  | 1631 | if (!work->input.buffers.empty()) { | 
|  | 1632 | inputBuffer = work->input.buffers[0]; | 
|  | 1633 | view = std::make_shared<const C2GraphicView>( | 
|  | 1634 | inputBuffer->data().graphicBlocks().front().map().get()); | 
|  | 1635 | if (view->error() != C2_OK) { | 
|  | 1636 | ALOGE("graphic view map err = %d", view->error()); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1637 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1638 | return; | 
|  | 1639 | } | 
|  | 1640 | } | 
|  | 1641 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1642 | do { | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1643 | if (mSawInputEOS && work->input.buffers.empty()) break; | 
|  | 1644 | if (!mOutBlock) { | 
|  | 1645 | C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, | 
|  | 1646 | C2MemoryUsage::CPU_WRITE}; | 
|  | 1647 | // TODO: error handling, proper usage, etc. | 
|  | 1648 | c2_status_t err = | 
|  | 1649 | pool->fetchLinearBlock(mOutBufferSize, usage, &mOutBlock); | 
|  | 1650 | if (err != C2_OK) { | 
|  | 1651 | ALOGE("fetch linear block err = %d", err); | 
|  | 1652 | work->result = err; | 
|  | 1653 | work->workletsProcessed = 1u; | 
|  | 1654 | return; | 
|  | 1655 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1656 | } | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1657 | C2WriteView wView = mOutBlock->map().get(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1658 | if (wView.error() != C2_OK) { | 
|  | 1659 | ALOGE("write view map err = %d", wView.error()); | 
|  | 1660 | work->result = wView.error(); | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1661 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1662 | return; | 
|  | 1663 | } | 
|  | 1664 |  | 
|  | 1665 | error = setEncodeArgs( | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1666 | &s_encode_ip, &s_encode_op, view.get(), wView.base(), wView.capacity(), workIndex); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1667 | if (error != C2_OK) { | 
|  | 1668 | ALOGE("setEncodeArgs failed : %d", error); | 
|  | 1669 | mSignalledError = true; | 
|  | 1670 | work->result = error; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1671 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1672 | return; | 
|  | 1673 | } | 
|  | 1674 |  | 
|  | 1675 | // DUMP_TO_FILE( | 
|  | 1676 | //         mInFile, s_encode_ip.s_inp_buf.apv_bufs[0], | 
|  | 1677 | //         (mHeight * mStride * 3 / 2)); | 
|  | 1678 |  | 
|  | 1679 | GETTIME(&mTimeStart, nullptr); | 
|  | 1680 | /* Compute time elapsed between end of previous decode() | 
|  | 1681 | * to start of current decode() */ | 
|  | 1682 | TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); | 
|  | 1683 | status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); | 
|  | 1684 |  | 
|  | 1685 | if (IV_SUCCESS != status) { | 
|  | 1686 | if ((s_encode_op.u4_error_code & 0xFF) == IH264E_BITSTREAM_BUFFER_OVERFLOW) { | 
|  | 1687 | // TODO: use IVE_CMD_CTL_GETBUFINFO for proper max input size? | 
|  | 1688 | mOutBufferSize *= 2; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1689 | mOutBlock.reset(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1690 | continue; | 
|  | 1691 | } | 
|  | 1692 | ALOGE("Encode Frame failed = 0x%x\n", | 
|  | 1693 | s_encode_op.u4_error_code); | 
|  | 1694 | mSignalledError = true; | 
|  | 1695 | work->result = C2_CORRUPTED; | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1696 | work->workletsProcessed = 1u; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1697 | return; | 
|  | 1698 | } | 
|  | 1699 | } while (IV_SUCCESS != status); | 
|  | 1700 |  | 
|  | 1701 | // Hold input buffer reference | 
|  | 1702 | if (inputBuffer) { | 
|  | 1703 | mBuffers[s_encode_ip.s_inp_buf.apv_bufs[0]] = inputBuffer; | 
|  | 1704 | } | 
|  | 1705 |  | 
|  | 1706 | GETTIME(&mTimeEnd, nullptr); | 
|  | 1707 | /* Compute time taken for decode() */ | 
|  | 1708 | TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); | 
|  | 1709 |  | 
|  | 1710 | ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, | 
|  | 1711 | s_encode_op.s_out_buf.u4_bytes); | 
|  | 1712 |  | 
|  | 1713 | void *freed = s_encode_op.s_inp_buf.apv_bufs[0]; | 
|  | 1714 | /* If encoder frees up an input buffer, mark it as free */ | 
|  | 1715 | if (freed != nullptr) { | 
|  | 1716 | if (mBuffers.count(freed) == 0u) { | 
|  | 1717 | ALOGD("buffer not tracked"); | 
|  | 1718 | } else { | 
|  | 1719 | // Release input buffer reference | 
|  | 1720 | mBuffers.erase(freed); | 
|  | 1721 | mConversionBuffersInUse.erase(freed); | 
|  | 1722 | } | 
|  | 1723 | } | 
|  | 1724 |  | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1725 | if (s_encode_op.output_present) { | 
|  | 1726 | if (!s_encode_op.s_out_buf.u4_bytes) { | 
|  | 1727 | ALOGE("Error: Output present but bytes generated is zero"); | 
|  | 1728 | mSignalledError = true; | 
|  | 1729 | work->result = C2_CORRUPTED; | 
|  | 1730 | work->workletsProcessed = 1u; | 
|  | 1731 | return; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1732 | } | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1733 | uint64_t workId = ((uint64_t)s_encode_op.u4_timestamp_high << 32) | | 
|  | 1734 | s_encode_op.u4_timestamp_low; | 
|  | 1735 | finishWork(workId, work, &s_encode_op); | 
|  | 1736 | } | 
|  | 1737 | if (mSawInputEOS) { | 
|  | 1738 | drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work); | 
|  | 1739 | } | 
|  | 1740 | } | 
|  | 1741 |  | 
|  | 1742 | c2_status_t C2SoftAvcEnc::drainInternal( | 
|  | 1743 | uint32_t drainMode, | 
|  | 1744 | const std::shared_ptr<C2BlockPool> &pool, | 
|  | 1745 | const std::unique_ptr<C2Work> &work) { | 
|  | 1746 |  | 
|  | 1747 | if (drainMode == NO_DRAIN) { | 
|  | 1748 | ALOGW("drain with NO_DRAIN: no-op"); | 
|  | 1749 | return C2_OK; | 
|  | 1750 | } | 
|  | 1751 | if (drainMode == DRAIN_CHAIN) { | 
|  | 1752 | ALOGW("DRAIN_CHAIN not supported"); | 
|  | 1753 | return C2_OMITTED; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1754 | } | 
|  | 1755 |  | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1756 | while (true) { | 
|  | 1757 | if (!mOutBlock) { | 
|  | 1758 | C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, | 
|  | 1759 | C2MemoryUsage::CPU_WRITE}; | 
|  | 1760 | // TODO: error handling, proper usage, etc. | 
|  | 1761 | c2_status_t err = | 
|  | 1762 | pool->fetchLinearBlock(mOutBufferSize, usage, &mOutBlock); | 
|  | 1763 | if (err != C2_OK) { | 
|  | 1764 | ALOGE("fetch linear block err = %d", err); | 
|  | 1765 | work->result = err; | 
|  | 1766 | work->workletsProcessed = 1u; | 
|  | 1767 | return err; | 
|  | 1768 | } | 
|  | 1769 | } | 
|  | 1770 | C2WriteView wView = mOutBlock->map().get(); | 
|  | 1771 | if (wView.error()) { | 
|  | 1772 | ALOGE("graphic view map failed %d", wView.error()); | 
|  | 1773 | return C2_CORRUPTED; | 
|  | 1774 | } | 
|  | 1775 | ive_video_encode_ip_t s_encode_ip; | 
|  | 1776 | ive_video_encode_op_t s_encode_op; | 
|  | 1777 | if (C2_OK != setEncodeArgs(&s_encode_ip, &s_encode_op, nullptr, | 
|  | 1778 | wView.base(), wView.capacity(), 0)) { | 
|  | 1779 | ALOGE("setEncodeArgs failed for drainInternal"); | 
|  | 1780 | mSignalledError = true; | 
|  | 1781 | work->result = C2_CORRUPTED; | 
|  | 1782 | work->workletsProcessed = 1u; | 
|  | 1783 | return C2_CORRUPTED; | 
|  | 1784 | } | 
|  | 1785 | (void)ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); | 
|  | 1786 |  | 
|  | 1787 | void *freed = s_encode_op.s_inp_buf.apv_bufs[0]; | 
|  | 1788 | /* If encoder frees up an input buffer, mark it as free */ | 
|  | 1789 | if (freed != nullptr) { | 
|  | 1790 | if (mBuffers.count(freed) == 0u) { | 
|  | 1791 | ALOGD("buffer not tracked"); | 
|  | 1792 | } else { | 
|  | 1793 | // Release input buffer reference | 
|  | 1794 | mBuffers.erase(freed); | 
|  | 1795 | mConversionBuffersInUse.erase(freed); | 
|  | 1796 | } | 
|  | 1797 | } | 
|  | 1798 |  | 
|  | 1799 | if (s_encode_op.output_present) { | 
|  | 1800 | uint64_t workId = ((uint64_t)s_encode_op.u4_timestamp_high << 32) | | 
|  | 1801 | s_encode_op.u4_timestamp_low; | 
|  | 1802 | finishWork(workId, work, &s_encode_op); | 
|  | 1803 | } else { | 
|  | 1804 | if (work->workletsProcessed != 1u) { | 
|  | 1805 | work->worklets.front()->output.flags = work->input.flags; | 
|  | 1806 | work->worklets.front()->output.ordinal = work->input.ordinal; | 
|  | 1807 | work->worklets.front()->output.buffers.clear(); | 
|  | 1808 | work->workletsProcessed = 1u; | 
|  | 1809 | } | 
|  | 1810 | break; | 
|  | 1811 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1812 | } | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1813 |  | 
|  | 1814 | return C2_OK; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1815 | } | 
|  | 1816 |  | 
|  | 1817 | c2_status_t C2SoftAvcEnc::drain( | 
|  | 1818 | uint32_t drainMode, | 
|  | 1819 | const std::shared_ptr<C2BlockPool> &pool) { | 
| Manisha Jajoo | 26b946d | 2019-03-15 18:15:11 +0530 | [diff] [blame] | 1820 | return drainInternal(drainMode, pool, nullptr); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1821 | } | 
|  | 1822 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1823 | class C2SoftAvcEncFactory : public C2ComponentFactory { | 
|  | 1824 | public: | 
|  | 1825 | C2SoftAvcEncFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>( | 
|  | 1826 | GetCodec2PlatformComponentStore()->getParamReflector())) { | 
|  | 1827 | } | 
|  | 1828 |  | 
|  | 1829 | virtual c2_status_t createComponent( | 
|  | 1830 | c2_node_id_t id, | 
|  | 1831 | std::shared_ptr<C2Component>* const component, | 
|  | 1832 | std::function<void(C2Component*)> deleter) override { | 
|  | 1833 | *component = std::shared_ptr<C2Component>( | 
|  | 1834 | new C2SoftAvcEnc(COMPONENT_NAME, | 
|  | 1835 | id, | 
|  | 1836 | std::make_shared<C2SoftAvcEnc::IntfImpl>(mHelper)), | 
|  | 1837 | deleter); | 
|  | 1838 | return C2_OK; | 
|  | 1839 | } | 
|  | 1840 |  | 
|  | 1841 | virtual c2_status_t createInterface( | 
|  | 1842 | c2_node_id_t id, | 
|  | 1843 | std::shared_ptr<C2ComponentInterface>* const interface, | 
|  | 1844 | std::function<void(C2ComponentInterface*)> deleter) override { | 
|  | 1845 | *interface = std::shared_ptr<C2ComponentInterface>( | 
|  | 1846 | new SimpleInterface<C2SoftAvcEnc::IntfImpl>( | 
|  | 1847 | COMPONENT_NAME, id, std::make_shared<C2SoftAvcEnc::IntfImpl>(mHelper)), | 
|  | 1848 | deleter); | 
|  | 1849 | return C2_OK; | 
|  | 1850 | } | 
|  | 1851 |  | 
|  | 1852 | virtual ~C2SoftAvcEncFactory() override = default; | 
|  | 1853 |  | 
|  | 1854 | private: | 
|  | 1855 | std::shared_ptr<C2ReflectorHelper> mHelper; | 
|  | 1856 | }; | 
|  | 1857 |  | 
|  | 1858 | }  // namespace android | 
|  | 1859 |  | 
| Cindy Zhou | f6c0c3c | 2020-12-02 10:53:40 -0800 | [diff] [blame] | 1860 | __attribute__((cfi_canonical_jump_table)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1861 | extern "C" ::C2ComponentFactory* CreateCodec2Factory() { | 
|  | 1862 | ALOGV("in %s", __func__); | 
|  | 1863 | return new ::android::C2SoftAvcEncFactory(); | 
|  | 1864 | } | 
|  | 1865 |  | 
| Cindy Zhou | f6c0c3c | 2020-12-02 10:53:40 -0800 | [diff] [blame] | 1866 | __attribute__((cfi_canonical_jump_table)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1867 | extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { | 
|  | 1868 | ALOGV("in %s", __func__); | 
|  | 1869 | delete factory; | 
|  | 1870 | } |