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