| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2017 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 "C2SoftAvcDec" | 
|  | 19 | #include <log/log.h> | 
|  | 20 |  | 
|  | 21 | #include <media/stagefright/foundation/MediaDefs.h> | 
|  | 22 |  | 
|  | 23 | #include <C2Debug.h> | 
|  | 24 | #include <C2PlatformSupport.h> | 
|  | 25 | #include <Codec2Mapper.h> | 
|  | 26 | #include <SimpleC2Interface.h> | 
|  | 27 |  | 
|  | 28 | #include "C2SoftAvcDec.h" | 
|  | 29 | #include "ih264d.h" | 
|  | 30 |  | 
|  | 31 | namespace android { | 
|  | 32 |  | 
|  | 33 | namespace { | 
| Harish Mahendrakar | e55c471 | 2019-07-26 12:32:13 -0700 | [diff] [blame] | 34 | constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 35 | constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder"; | 
| Harish Mahendrakar | 343be8a | 2019-08-01 12:38:58 -0700 | [diff] [blame] | 36 | constexpr uint32_t kDefaultOutputDelay = 8; | 
|  | 37 | constexpr uint32_t kMaxOutputDelay = 16; | 
| Harish Mahendrakar | fd65f91 | 2020-04-02 05:45:05 +0530 | [diff] [blame] | 38 | constexpr uint32_t kMinInputBytes = 4; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 39 | }  // namespace | 
|  | 40 |  | 
|  | 41 | class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams { | 
|  | 42 | public: | 
|  | 43 | explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) | 
|  | 44 | : SimpleInterface<void>::BaseParams( | 
|  | 45 | helper, | 
|  | 46 | COMPONENT_NAME, | 
|  | 47 | C2Component::KIND_DECODER, | 
|  | 48 | C2Component::DOMAIN_VIDEO, | 
|  | 49 | MEDIA_MIMETYPE_VIDEO_AVC) { | 
|  | 50 | noPrivateBuffers(); // TODO: account for our buffers here | 
|  | 51 | noInputReferences(); | 
|  | 52 | noOutputReferences(); | 
|  | 53 | noInputLatency(); | 
|  | 54 | noTimeStretch(); | 
|  | 55 |  | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 56 | // TODO: Proper support for reorder depth. | 
|  | 57 | addParameter( | 
|  | 58 | DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY) | 
| Harish Mahendrakar | 343be8a | 2019-08-01 12:38:58 -0700 | [diff] [blame] | 59 | .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay)) | 
|  | 60 | .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)}) | 
|  | 61 | .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps) | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 62 | .build()); | 
|  | 63 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 64 | // TODO: output latency and reordering | 
|  | 65 |  | 
|  | 66 | addParameter( | 
|  | 67 | DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) | 
|  | 68 | .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL)) | 
|  | 69 | .build()); | 
|  | 70 |  | 
|  | 71 | // coded and output picture size is the same for this codec | 
|  | 72 | addParameter( | 
|  | 73 | DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) | 
|  | 74 | .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240)) | 
|  | 75 | .withFields({ | 
|  | 76 | C2F(mSize, width).inRange(2, 4080, 2), | 
|  | 77 | C2F(mSize, height).inRange(2, 4080, 2), | 
|  | 78 | }) | 
|  | 79 | .withSetter(SizeSetter) | 
|  | 80 | .build()); | 
|  | 81 |  | 
|  | 82 | addParameter( | 
|  | 83 | DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE) | 
|  | 84 | .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240)) | 
|  | 85 | .withFields({ | 
|  | 86 | C2F(mSize, width).inRange(2, 4080, 2), | 
|  | 87 | C2F(mSize, height).inRange(2, 4080, 2), | 
|  | 88 | }) | 
|  | 89 | .withSetter(MaxPictureSizeSetter, mSize) | 
|  | 90 | .build()); | 
|  | 91 |  | 
|  | 92 | addParameter( | 
|  | 93 | DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) | 
|  | 94 | .withDefault(new C2StreamProfileLevelInfo::input(0u, | 
|  | 95 | C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, C2Config::LEVEL_AVC_5_2)) | 
|  | 96 | .withFields({ | 
|  | 97 | C2F(mProfileLevel, profile).oneOf({ | 
|  | 98 | C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, | 
|  | 99 | C2Config::PROFILE_AVC_BASELINE, | 
|  | 100 | C2Config::PROFILE_AVC_MAIN, | 
|  | 101 | C2Config::PROFILE_AVC_CONSTRAINED_HIGH, | 
|  | 102 | C2Config::PROFILE_AVC_PROGRESSIVE_HIGH, | 
|  | 103 | C2Config::PROFILE_AVC_HIGH}), | 
|  | 104 | C2F(mProfileLevel, level).oneOf({ | 
|  | 105 | C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, C2Config::LEVEL_AVC_1_1, | 
|  | 106 | C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3, | 
|  | 107 | C2Config::LEVEL_AVC_2, C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2, | 
|  | 108 | C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2, | 
|  | 109 | C2Config::LEVEL_AVC_4, C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2, | 
|  | 110 | C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, C2Config::LEVEL_AVC_5_2 | 
|  | 111 | }) | 
|  | 112 | }) | 
|  | 113 | .withSetter(ProfileLevelSetter, mSize) | 
|  | 114 | .build()); | 
|  | 115 |  | 
|  | 116 | addParameter( | 
|  | 117 | DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) | 
| Harish Mahendrakar | e55c471 | 2019-07-26 12:32:13 -0700 | [diff] [blame] | 118 | .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 119 | .withFields({ | 
|  | 120 | C2F(mMaxInputSize, value).any(), | 
|  | 121 | }) | 
|  | 122 | .calculatedAs(MaxInputSizeSetter, mMaxSize) | 
|  | 123 | .build()); | 
|  | 124 |  | 
|  | 125 | C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() }; | 
|  | 126 | std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo = | 
|  | 127 | C2StreamColorInfo::output::AllocShared( | 
|  | 128 | 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420); | 
|  | 129 | memcpy(defaultColorInfo->m.locations, locations, sizeof(locations)); | 
|  | 130 |  | 
|  | 131 | defaultColorInfo = | 
|  | 132 | C2StreamColorInfo::output::AllocShared( | 
|  | 133 | { C2ChromaOffsetStruct::ITU_YUV_420_0() }, | 
|  | 134 | 0u, 8u /* bitDepth */, C2Color::YUV_420); | 
|  | 135 | helper->addStructDescriptors<C2ChromaOffsetStruct>(); | 
|  | 136 |  | 
|  | 137 | addParameter( | 
|  | 138 | DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO) | 
|  | 139 | .withConstValue(defaultColorInfo) | 
|  | 140 | .build()); | 
|  | 141 |  | 
|  | 142 | addParameter( | 
|  | 143 | DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) | 
|  | 144 | .withDefault(new C2StreamColorAspectsTuning::output( | 
|  | 145 | 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, | 
|  | 146 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) | 
|  | 147 | .withFields({ | 
|  | 148 | C2F(mDefaultColorAspects, range).inRange( | 
|  | 149 | C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER), | 
|  | 150 | C2F(mDefaultColorAspects, primaries).inRange( | 
|  | 151 | C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), | 
|  | 152 | C2F(mDefaultColorAspects, transfer).inRange( | 
|  | 153 | C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER), | 
|  | 154 | C2F(mDefaultColorAspects, matrix).inRange( | 
|  | 155 | C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER) | 
|  | 156 | }) | 
|  | 157 | .withSetter(DefaultColorAspectsSetter) | 
|  | 158 | .build()); | 
|  | 159 |  | 
|  | 160 | addParameter( | 
|  | 161 | DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS) | 
|  | 162 | .withDefault(new C2StreamColorAspectsInfo::input( | 
|  | 163 | 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED, | 
|  | 164 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) | 
|  | 165 | .withFields({ | 
|  | 166 | C2F(mCodedColorAspects, range).inRange( | 
|  | 167 | C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER), | 
|  | 168 | C2F(mCodedColorAspects, primaries).inRange( | 
|  | 169 | C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), | 
|  | 170 | C2F(mCodedColorAspects, transfer).inRange( | 
|  | 171 | C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER), | 
|  | 172 | C2F(mCodedColorAspects, matrix).inRange( | 
|  | 173 | C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER) | 
|  | 174 | }) | 
|  | 175 | .withSetter(CodedColorAspectsSetter) | 
|  | 176 | .build()); | 
|  | 177 |  | 
|  | 178 | addParameter( | 
|  | 179 | DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS) | 
|  | 180 | .withDefault(new C2StreamColorAspectsInfo::output( | 
|  | 181 | 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, | 
|  | 182 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) | 
|  | 183 | .withFields({ | 
|  | 184 | C2F(mColorAspects, range).inRange( | 
|  | 185 | C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER), | 
|  | 186 | C2F(mColorAspects, primaries).inRange( | 
|  | 187 | C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), | 
|  | 188 | C2F(mColorAspects, transfer).inRange( | 
|  | 189 | C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER), | 
|  | 190 | C2F(mColorAspects, matrix).inRange( | 
|  | 191 | C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER) | 
|  | 192 | }) | 
|  | 193 | .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects) | 
|  | 194 | .build()); | 
|  | 195 |  | 
|  | 196 | // TODO: support more formats? | 
|  | 197 | addParameter( | 
|  | 198 | DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT) | 
|  | 199 | .withConstValue(new C2StreamPixelFormatInfo::output( | 
|  | 200 | 0u, HAL_PIXEL_FORMAT_YCBCR_420_888)) | 
|  | 201 | .build()); | 
|  | 202 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 203 | static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe, | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 204 | C2P<C2StreamPictureSizeInfo::output> &me) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 205 | (void)mayBlock; | 
|  | 206 | C2R res = C2R::Ok(); | 
|  | 207 | if (!me.F(me.v.width).supportsAtAll(me.v.width)) { | 
|  | 208 | res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width))); | 
|  | 209 | me.set().width = oldMe.v.width; | 
|  | 210 | } | 
|  | 211 | if (!me.F(me.v.height).supportsAtAll(me.v.height)) { | 
|  | 212 | res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height))); | 
|  | 213 | me.set().height = oldMe.v.height; | 
|  | 214 | } | 
|  | 215 | return res; | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me, | 
|  | 219 | const C2P<C2StreamPictureSizeInfo::output> &size) { | 
|  | 220 | (void)mayBlock; | 
|  | 221 | // TODO: get max width/height from the size's field helpers vs. hardcoding | 
|  | 222 | me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4080u); | 
|  | 223 | me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4080u); | 
|  | 224 | return C2R::Ok(); | 
|  | 225 | } | 
|  | 226 |  | 
|  | 227 | static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me, | 
|  | 228 | const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) { | 
|  | 229 | (void)mayBlock; | 
|  | 230 | // assume compression ratio of 2 | 
| Harish Mahendrakar | e55c471 | 2019-07-26 12:32:13 -0700 | [diff] [blame] | 231 | me.set().value = c2_max((((maxSize.v.width + 15) / 16) | 
|  | 232 | * ((maxSize.v.height + 15) / 16) * 192), kMinInputBufferSize); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 233 | return C2R::Ok(); | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me, | 
|  | 237 | const C2P<C2StreamPictureSizeInfo::output> &size) { | 
|  | 238 | (void)mayBlock; | 
|  | 239 | (void)size; | 
|  | 240 | (void)me;  // TODO: validate | 
|  | 241 | return C2R::Ok(); | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) { | 
|  | 245 | (void)mayBlock; | 
|  | 246 | if (me.v.range > C2Color::RANGE_OTHER) { | 
|  | 247 | me.set().range = C2Color::RANGE_OTHER; | 
|  | 248 | } | 
|  | 249 | if (me.v.primaries > C2Color::PRIMARIES_OTHER) { | 
|  | 250 | me.set().primaries = C2Color::PRIMARIES_OTHER; | 
|  | 251 | } | 
|  | 252 | if (me.v.transfer > C2Color::TRANSFER_OTHER) { | 
|  | 253 | me.set().transfer = C2Color::TRANSFER_OTHER; | 
|  | 254 | } | 
|  | 255 | if (me.v.matrix > C2Color::MATRIX_OTHER) { | 
|  | 256 | me.set().matrix = C2Color::MATRIX_OTHER; | 
|  | 257 | } | 
|  | 258 | return C2R::Ok(); | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) { | 
|  | 262 | (void)mayBlock; | 
|  | 263 | if (me.v.range > C2Color::RANGE_OTHER) { | 
|  | 264 | me.set().range = C2Color::RANGE_OTHER; | 
|  | 265 | } | 
|  | 266 | if (me.v.primaries > C2Color::PRIMARIES_OTHER) { | 
|  | 267 | me.set().primaries = C2Color::PRIMARIES_OTHER; | 
|  | 268 | } | 
|  | 269 | if (me.v.transfer > C2Color::TRANSFER_OTHER) { | 
|  | 270 | me.set().transfer = C2Color::TRANSFER_OTHER; | 
|  | 271 | } | 
|  | 272 | if (me.v.matrix > C2Color::MATRIX_OTHER) { | 
|  | 273 | me.set().matrix = C2Color::MATRIX_OTHER; | 
|  | 274 | } | 
|  | 275 | return C2R::Ok(); | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me, | 
|  | 279 | const C2P<C2StreamColorAspectsTuning::output> &def, | 
|  | 280 | const C2P<C2StreamColorAspectsInfo::input> &coded) { | 
|  | 281 | (void)mayBlock; | 
|  | 282 | // take default values for all unspecified fields, and coded values for specified ones | 
|  | 283 | me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range; | 
|  | 284 | me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED | 
|  | 285 | ? def.v.primaries : coded.v.primaries; | 
|  | 286 | me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED | 
|  | 287 | ? def.v.transfer : coded.v.transfer; | 
|  | 288 | me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix; | 
|  | 289 | return C2R::Ok(); | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() { | 
|  | 293 | return mColorAspects; | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | private: | 
|  | 297 | std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel; | 
|  | 298 | std::shared_ptr<C2StreamPictureSizeInfo::output> mSize; | 
|  | 299 | std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize; | 
|  | 300 | std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize; | 
|  | 301 | std::shared_ptr<C2StreamColorInfo::output> mColorInfo; | 
|  | 302 | std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects; | 
|  | 303 | std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects; | 
|  | 304 | std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects; | 
|  | 305 | std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat; | 
|  | 306 | }; | 
|  | 307 |  | 
|  | 308 | static size_t getCpuCoreCount() { | 
|  | 309 | long cpuCoreCount = 1; | 
|  | 310 | #if defined(_SC_NPROCESSORS_ONLN) | 
|  | 311 | cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); | 
|  | 312 | #else | 
|  | 313 | // _SC_NPROC_ONLN must be defined... | 
|  | 314 | cpuCoreCount = sysconf(_SC_NPROC_ONLN); | 
|  | 315 | #endif | 
|  | 316 | CHECK(cpuCoreCount >= 1); | 
|  | 317 | ALOGV("Number of CPU cores: %ld", cpuCoreCount); | 
|  | 318 | return (size_t)cpuCoreCount; | 
|  | 319 | } | 
|  | 320 |  | 
|  | 321 | static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { | 
|  | 322 | (void) ctxt; | 
|  | 323 | return memalign(alignment, size); | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | static void ivd_aligned_free(void *ctxt, void *mem) { | 
|  | 327 | (void) ctxt; | 
|  | 328 | free(mem); | 
|  | 329 | } | 
|  | 330 |  | 
|  | 331 | C2SoftAvcDec::C2SoftAvcDec( | 
|  | 332 | const char *name, | 
|  | 333 | c2_node_id_t id, | 
|  | 334 | const std::shared_ptr<IntfImpl> &intfImpl) | 
|  | 335 | : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), | 
|  | 336 | mIntf(intfImpl), | 
|  | 337 | mDecHandle(nullptr), | 
|  | 338 | mOutBufferFlush(nullptr), | 
|  | 339 | mIvColorFormat(IV_YUV_420P), | 
| Harish Mahendrakar | 343be8a | 2019-08-01 12:38:58 -0700 | [diff] [blame] | 340 | mOutputDelay(kDefaultOutputDelay), | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 341 | mWidth(320), | 
|  | 342 | mHeight(240), | 
| Rakesh Kumar | 4ec85ae | 2019-02-13 00:50:07 +0530 | [diff] [blame] | 343 | mHeaderDecoded(false), | 
|  | 344 | mOutIndex(0u) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 345 | GENERATE_FILE_NAMES(); | 
|  | 346 | CREATE_DUMP_FILE(mInFile); | 
|  | 347 | } | 
|  | 348 |  | 
|  | 349 | C2SoftAvcDec::~C2SoftAvcDec() { | 
|  | 350 | onRelease(); | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | c2_status_t C2SoftAvcDec::onInit() { | 
|  | 354 | status_t err = initDecoder(); | 
|  | 355 | return err == OK ? C2_OK : C2_CORRUPTED; | 
|  | 356 | } | 
|  | 357 |  | 
|  | 358 | c2_status_t C2SoftAvcDec::onStop() { | 
|  | 359 | if (OK != resetDecoder()) return C2_CORRUPTED; | 
|  | 360 | resetPlugin(); | 
|  | 361 | return C2_OK; | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 | void C2SoftAvcDec::onReset() { | 
|  | 365 | (void) onStop(); | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | void C2SoftAvcDec::onRelease() { | 
|  | 369 | (void) deleteDecoder(); | 
|  | 370 | if (mOutBufferFlush) { | 
|  | 371 | ivd_aligned_free(nullptr, mOutBufferFlush); | 
|  | 372 | mOutBufferFlush = nullptr; | 
|  | 373 | } | 
|  | 374 | if (mOutBlock) { | 
|  | 375 | mOutBlock.reset(); | 
|  | 376 | } | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | c2_status_t C2SoftAvcDec::onFlush_sm() { | 
|  | 380 | if (OK != setFlushMode()) return C2_CORRUPTED; | 
|  | 381 |  | 
|  | 382 | uint32_t bufferSize = mStride * mHeight * 3 / 2; | 
|  | 383 | mOutBufferFlush = (uint8_t *)ivd_aligned_malloc(nullptr, 128, bufferSize); | 
|  | 384 | if (!mOutBufferFlush) { | 
|  | 385 | ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize); | 
|  | 386 | return C2_NO_MEMORY; | 
|  | 387 | } | 
|  | 388 |  | 
|  | 389 | while (true) { | 
|  | 390 | ivd_video_decode_ip_t s_decode_ip; | 
|  | 391 | ivd_video_decode_op_t s_decode_op; | 
|  | 392 |  | 
|  | 393 | setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0); | 
|  | 394 | (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); | 
|  | 395 | if (0 == s_decode_op.u4_output_present) { | 
|  | 396 | resetPlugin(); | 
|  | 397 | break; | 
|  | 398 | } | 
|  | 399 | } | 
|  | 400 |  | 
|  | 401 | if (mOutBufferFlush) { | 
|  | 402 | ivd_aligned_free(nullptr, mOutBufferFlush); | 
|  | 403 | mOutBufferFlush = nullptr; | 
|  | 404 | } | 
|  | 405 |  | 
|  | 406 | return C2_OK; | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | status_t C2SoftAvcDec::createDecoder() { | 
|  | 410 | ivdext_create_ip_t s_create_ip; | 
|  | 411 | ivdext_create_op_t s_create_op; | 
|  | 412 |  | 
|  | 413 | s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); | 
|  | 414 | s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; | 
|  | 415 | s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; | 
|  | 416 | s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; | 
|  | 417 | s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; | 
|  | 418 | s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; | 
|  | 419 | s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr; | 
|  | 420 | s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); | 
|  | 421 | IV_API_CALL_STATUS_T status = ivdec_api_function(nullptr, | 
|  | 422 | &s_create_ip, | 
|  | 423 | &s_create_op); | 
|  | 424 | if (status != IV_SUCCESS) { | 
|  | 425 | ALOGE("error in %s: 0x%x", __func__, | 
|  | 426 | s_create_op.s_ivd_create_op_t.u4_error_code); | 
|  | 427 | return UNKNOWN_ERROR; | 
|  | 428 | } | 
|  | 429 | mDecHandle = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; | 
|  | 430 | mDecHandle->pv_fxns = (void *)ivdec_api_function; | 
|  | 431 | mDecHandle->u4_size = sizeof(iv_obj_t); | 
|  | 432 |  | 
|  | 433 | return OK; | 
|  | 434 | } | 
|  | 435 |  | 
|  | 436 | status_t C2SoftAvcDec::setNumCores() { | 
|  | 437 | ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip; | 
|  | 438 | ivdext_ctl_set_num_cores_op_t s_set_num_cores_op; | 
|  | 439 |  | 
|  | 440 | s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); | 
|  | 441 | s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 442 | s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; | 
|  | 443 | s_set_num_cores_ip.u4_num_cores = mNumCores; | 
|  | 444 | s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); | 
|  | 445 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 446 | &s_set_num_cores_ip, | 
|  | 447 | &s_set_num_cores_op); | 
|  | 448 | if (IV_SUCCESS != status) { | 
|  | 449 | ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code); | 
|  | 450 | return UNKNOWN_ERROR; | 
|  | 451 | } | 
|  | 452 |  | 
|  | 453 | return OK; | 
|  | 454 | } | 
|  | 455 |  | 
|  | 456 | status_t C2SoftAvcDec::setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode) { | 
|  | 457 | ivd_ctl_set_config_ip_t s_set_dyn_params_ip; | 
|  | 458 | ivd_ctl_set_config_op_t s_set_dyn_params_op; | 
|  | 459 |  | 
|  | 460 | s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); | 
|  | 461 | s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 462 | s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; | 
|  | 463 | s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride; | 
|  | 464 | s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE; | 
|  | 465 | s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; | 
|  | 466 | s_set_dyn_params_ip.e_vid_dec_mode = dec_mode; | 
|  | 467 | s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t); | 
|  | 468 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 469 | &s_set_dyn_params_ip, | 
|  | 470 | &s_set_dyn_params_op); | 
|  | 471 | if (status != IV_SUCCESS) { | 
|  | 472 | ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code); | 
|  | 473 | return UNKNOWN_ERROR; | 
|  | 474 | } | 
|  | 475 |  | 
|  | 476 | return OK; | 
|  | 477 | } | 
|  | 478 |  | 
|  | 479 | void C2SoftAvcDec::getVersion() { | 
|  | 480 | ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip; | 
|  | 481 | ivd_ctl_getversioninfo_op_t s_get_versioninfo_op; | 
|  | 482 | UWORD8 au1_buf[512]; | 
|  | 483 |  | 
|  | 484 | s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); | 
|  | 485 | s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 486 | s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; | 
|  | 487 | s_get_versioninfo_ip.pv_version_buffer = au1_buf; | 
|  | 488 | s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf); | 
|  | 489 | s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); | 
|  | 490 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 491 | &s_get_versioninfo_ip, | 
|  | 492 | &s_get_versioninfo_op); | 
|  | 493 | if (status != IV_SUCCESS) { | 
|  | 494 | ALOGD("error in %s: 0x%x", __func__, | 
|  | 495 | s_get_versioninfo_op.u4_error_code); | 
|  | 496 | } else { | 
|  | 497 | ALOGV("ittiam decoder version number: %s", | 
|  | 498 | (char *) s_get_versioninfo_ip.pv_version_buffer); | 
|  | 499 | } | 
|  | 500 | } | 
|  | 501 |  | 
|  | 502 | status_t C2SoftAvcDec::initDecoder() { | 
|  | 503 | if (OK != createDecoder()) return UNKNOWN_ERROR; | 
|  | 504 | mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES); | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 505 | mStride = ALIGN32(mWidth); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 506 | mSignalledError = false; | 
|  | 507 | resetPlugin(); | 
|  | 508 | (void) setNumCores(); | 
|  | 509 | if (OK != setParams(mStride, IVD_DECODE_FRAME)) return UNKNOWN_ERROR; | 
|  | 510 | (void) getVersion(); | 
|  | 511 |  | 
|  | 512 | return OK; | 
|  | 513 | } | 
|  | 514 |  | 
|  | 515 | bool C2SoftAvcDec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip, | 
|  | 516 | ivd_video_decode_op_t *ps_decode_op, | 
|  | 517 | C2ReadView *inBuffer, | 
|  | 518 | C2GraphicView *outBuffer, | 
|  | 519 | size_t inOffset, | 
|  | 520 | size_t inSize, | 
|  | 521 | uint32_t tsMarker) { | 
|  | 522 | uint32_t displayStride = mStride; | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 523 | if (outBuffer) { | 
|  | 524 | C2PlanarLayout layout; | 
|  | 525 | layout = outBuffer->layout(); | 
|  | 526 | displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc; | 
|  | 527 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 528 | uint32_t displayHeight = mHeight; | 
|  | 529 | size_t lumaSize = displayStride * displayHeight; | 
|  | 530 | size_t chromaSize = lumaSize >> 2; | 
|  | 531 |  | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 532 | if (mStride != displayStride) { | 
|  | 533 | mStride = displayStride; | 
|  | 534 | if (OK != setParams(mStride, IVD_DECODE_FRAME)) return false; | 
|  | 535 | } | 
|  | 536 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 537 | ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t); | 
|  | 538 | ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE; | 
|  | 539 | if (inBuffer) { | 
|  | 540 | ps_decode_ip->u4_ts = tsMarker; | 
|  | 541 | ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset); | 
|  | 542 | ps_decode_ip->u4_num_Bytes = inSize; | 
|  | 543 | } else { | 
|  | 544 | ps_decode_ip->u4_ts = 0; | 
|  | 545 | ps_decode_ip->pv_stream_buffer = nullptr; | 
|  | 546 | ps_decode_ip->u4_num_Bytes = 0; | 
|  | 547 | } | 
|  | 548 | ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize; | 
|  | 549 | ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize; | 
|  | 550 | ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize; | 
|  | 551 | if (outBuffer) { | 
| Jason Macnak | af3aead | 2020-04-30 17:41:53 -0700 | [diff] [blame] | 552 | if (outBuffer->height() < displayHeight) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 553 | ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)", | 
|  | 554 | outBuffer->width(), outBuffer->height(), displayStride, displayHeight); | 
|  | 555 | return false; | 
|  | 556 | } | 
|  | 557 | ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y]; | 
|  | 558 | ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U]; | 
|  | 559 | ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V]; | 
|  | 560 | } else { | 
|  | 561 | ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferFlush; | 
|  | 562 | ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferFlush + lumaSize; | 
|  | 563 | ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferFlush + lumaSize + chromaSize; | 
|  | 564 | } | 
|  | 565 | ps_decode_ip->s_out_buffer.u4_num_bufs = 3; | 
|  | 566 | ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t); | 
|  | 567 |  | 
|  | 568 | return true; | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | bool C2SoftAvcDec::getVuiParams() { | 
|  | 572 | ivdext_ctl_get_vui_params_ip_t s_get_vui_params_ip; | 
|  | 573 | ivdext_ctl_get_vui_params_op_t s_get_vui_params_op; | 
|  | 574 |  | 
|  | 575 | s_get_vui_params_ip.u4_size = sizeof(ivdext_ctl_get_vui_params_ip_t); | 
|  | 576 | s_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 577 | s_get_vui_params_ip.e_sub_cmd = | 
|  | 578 | (IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_GET_VUI_PARAMS; | 
|  | 579 | s_get_vui_params_op.u4_size = sizeof(ivdext_ctl_get_vui_params_op_t); | 
|  | 580 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 581 | &s_get_vui_params_ip, | 
|  | 582 | &s_get_vui_params_op); | 
|  | 583 | if (status != IV_SUCCESS) { | 
|  | 584 | ALOGD("error in %s: 0x%x", __func__, s_get_vui_params_op.u4_error_code); | 
|  | 585 | return false; | 
|  | 586 | } | 
|  | 587 |  | 
|  | 588 | VuiColorAspects vuiColorAspects; | 
|  | 589 | vuiColorAspects.primaries = s_get_vui_params_op.u1_colour_primaries; | 
|  | 590 | vuiColorAspects.transfer = s_get_vui_params_op.u1_tfr_chars; | 
|  | 591 | vuiColorAspects.coeffs = s_get_vui_params_op.u1_matrix_coeffs; | 
|  | 592 | vuiColorAspects.fullRange = s_get_vui_params_op.u1_video_full_range_flag; | 
|  | 593 |  | 
|  | 594 | // convert vui aspects to C2 values if changed | 
|  | 595 | if (!(vuiColorAspects == mBitstreamColorAspects)) { | 
|  | 596 | mBitstreamColorAspects = vuiColorAspects; | 
|  | 597 | ColorAspects sfAspects; | 
|  | 598 | C2StreamColorAspectsInfo::input codedAspects = { 0u }; | 
|  | 599 | ColorUtils::convertIsoColorAspectsToCodecAspects( | 
|  | 600 | vuiColorAspects.primaries, vuiColorAspects.transfer, vuiColorAspects.coeffs, | 
|  | 601 | vuiColorAspects.fullRange, sfAspects); | 
|  | 602 | if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) { | 
|  | 603 | codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED; | 
|  | 604 | } | 
|  | 605 | if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) { | 
|  | 606 | codedAspects.range = C2Color::RANGE_UNSPECIFIED; | 
|  | 607 | } | 
|  | 608 | if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) { | 
|  | 609 | codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED; | 
|  | 610 | } | 
|  | 611 | if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) { | 
|  | 612 | codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED; | 
|  | 613 | } | 
|  | 614 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
|  | 615 | (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures); | 
|  | 616 | } | 
|  | 617 | return true; | 
|  | 618 | } | 
|  | 619 |  | 
|  | 620 | status_t C2SoftAvcDec::setFlushMode() { | 
|  | 621 | ivd_ctl_flush_ip_t s_set_flush_ip; | 
|  | 622 | ivd_ctl_flush_op_t s_set_flush_op; | 
|  | 623 |  | 
|  | 624 | s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); | 
|  | 625 | s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 626 | s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; | 
|  | 627 | s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); | 
|  | 628 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 629 | &s_set_flush_ip, | 
|  | 630 | &s_set_flush_op); | 
|  | 631 | if (status != IV_SUCCESS) { | 
|  | 632 | ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code); | 
|  | 633 | return UNKNOWN_ERROR; | 
|  | 634 | } | 
|  | 635 |  | 
|  | 636 | return OK; | 
|  | 637 | } | 
|  | 638 |  | 
|  | 639 | status_t C2SoftAvcDec::resetDecoder() { | 
|  | 640 | ivd_ctl_reset_ip_t s_reset_ip; | 
|  | 641 | ivd_ctl_reset_op_t s_reset_op; | 
|  | 642 |  | 
|  | 643 | s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); | 
|  | 644 | s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL; | 
|  | 645 | s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET; | 
|  | 646 | s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t); | 
|  | 647 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 648 | &s_reset_ip, | 
|  | 649 | &s_reset_op); | 
|  | 650 | if (IV_SUCCESS != status) { | 
|  | 651 | ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code); | 
|  | 652 | return UNKNOWN_ERROR; | 
|  | 653 | } | 
|  | 654 | mStride = 0; | 
|  | 655 | (void) setNumCores(); | 
|  | 656 | mSignalledError = false; | 
|  | 657 | mHeaderDecoded = false; | 
|  | 658 |  | 
|  | 659 | return OK; | 
|  | 660 | } | 
|  | 661 |  | 
|  | 662 | void C2SoftAvcDec::resetPlugin() { | 
|  | 663 | mSignalledOutputEos = false; | 
|  | 664 | gettimeofday(&mTimeStart, nullptr); | 
|  | 665 | gettimeofday(&mTimeEnd, nullptr); | 
|  | 666 | } | 
|  | 667 |  | 
|  | 668 | status_t C2SoftAvcDec::deleteDecoder() { | 
|  | 669 | if (mDecHandle) { | 
|  | 670 | ivdext_delete_ip_t s_delete_ip; | 
|  | 671 | ivdext_delete_op_t s_delete_op; | 
|  | 672 |  | 
|  | 673 | s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); | 
|  | 674 | s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; | 
|  | 675 | s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); | 
|  | 676 | IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, | 
|  | 677 | &s_delete_ip, | 
|  | 678 | &s_delete_op); | 
|  | 679 | if (status != IV_SUCCESS) { | 
|  | 680 | ALOGE("error in %s: 0x%x", __func__, | 
|  | 681 | s_delete_op.s_ivd_delete_op_t.u4_error_code); | 
|  | 682 | return UNKNOWN_ERROR; | 
|  | 683 | } | 
|  | 684 | mDecHandle = nullptr; | 
|  | 685 | } | 
|  | 686 |  | 
|  | 687 | return OK; | 
|  | 688 | } | 
|  | 689 |  | 
|  | 690 | static void fillEmptyWork(const std::unique_ptr<C2Work> &work) { | 
|  | 691 | uint32_t flags = 0; | 
|  | 692 | if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { | 
|  | 693 | flags |= C2FrameData::FLAG_END_OF_STREAM; | 
|  | 694 | ALOGV("signalling eos"); | 
|  | 695 | } | 
|  | 696 | work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; | 
|  | 697 | work->worklets.front()->output.buffers.clear(); | 
|  | 698 | work->worklets.front()->output.ordinal = work->input.ordinal; | 
|  | 699 | work->workletsProcessed = 1u; | 
|  | 700 | } | 
|  | 701 |  | 
|  | 702 | void C2SoftAvcDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) { | 
|  | 703 | std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock), | 
|  | 704 | C2Rect(mWidth, mHeight)); | 
|  | 705 | mOutBlock = nullptr; | 
|  | 706 | { | 
|  | 707 | IntfImpl::Lock lock = mIntf->lock(); | 
|  | 708 | buffer->setInfo(mIntf->getColorAspects_l()); | 
|  | 709 | } | 
|  | 710 |  | 
| Rakesh Kumar | 4ec85ae | 2019-02-13 00:50:07 +0530 | [diff] [blame] | 711 | class FillWork { | 
|  | 712 | public: | 
|  | 713 | FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal, | 
|  | 714 | const std::shared_ptr<C2Buffer>& buffer) | 
|  | 715 | : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {} | 
|  | 716 | ~FillWork() = default; | 
|  | 717 |  | 
|  | 718 | void operator()(const std::unique_ptr<C2Work>& work) { | 
|  | 719 | work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags; | 
|  | 720 | work->worklets.front()->output.buffers.clear(); | 
|  | 721 | work->worklets.front()->output.ordinal = mOrdinal; | 
|  | 722 | work->workletsProcessed = 1u; | 
|  | 723 | work->result = C2_OK; | 
|  | 724 | if (mBuffer) { | 
|  | 725 | work->worklets.front()->output.buffers.push_back(mBuffer); | 
|  | 726 | } | 
|  | 727 | ALOGV("timestamp = %lld, index = %lld, w/%s buffer", | 
|  | 728 | mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(), | 
|  | 729 | mBuffer ? "" : "o"); | 
|  | 730 | } | 
|  | 731 |  | 
|  | 732 | private: | 
|  | 733 | const uint32_t mFlags; | 
|  | 734 | const C2WorkOrdinalStruct mOrdinal; | 
|  | 735 | const std::shared_ptr<C2Buffer> mBuffer; | 
|  | 736 | }; | 
|  | 737 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 738 | auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) { | 
|  | 739 | work->worklets.front()->output.flags = (C2FrameData::flags_t)0; | 
|  | 740 | work->worklets.front()->output.buffers.clear(); | 
|  | 741 | work->worklets.front()->output.buffers.push_back(buffer); | 
|  | 742 | work->worklets.front()->output.ordinal = work->input.ordinal; | 
|  | 743 | work->workletsProcessed = 1u; | 
|  | 744 | }; | 
|  | 745 | if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) { | 
| Rakesh Kumar | 4ec85ae | 2019-02-13 00:50:07 +0530 | [diff] [blame] | 746 | bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0); | 
|  | 747 | // TODO: Check if cloneAndSend can be avoided by tracking number of frames remaining | 
|  | 748 | if (eos) { | 
|  | 749 | if (buffer) { | 
|  | 750 | mOutIndex = index; | 
|  | 751 | C2WorkOrdinalStruct outOrdinal = work->input.ordinal; | 
|  | 752 | cloneAndSend( | 
|  | 753 | mOutIndex, work, | 
|  | 754 | FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); | 
|  | 755 | buffer.reset(); | 
|  | 756 | } | 
|  | 757 | } else { | 
|  | 758 | fillWork(work); | 
|  | 759 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 760 | } else { | 
|  | 761 | finish(index, fillWork); | 
|  | 762 | } | 
|  | 763 | } | 
|  | 764 |  | 
|  | 765 | c2_status_t C2SoftAvcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) { | 
|  | 766 | if (!mDecHandle) { | 
|  | 767 | ALOGE("not supposed to be here, invalid decoder context"); | 
|  | 768 | return C2_CORRUPTED; | 
|  | 769 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 770 | if (mOutBlock && | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 771 | (mOutBlock->width() != ALIGN32(mWidth) || mOutBlock->height() != mHeight)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 772 | mOutBlock.reset(); | 
|  | 773 | } | 
|  | 774 | if (!mOutBlock) { | 
|  | 775 | uint32_t format = HAL_PIXEL_FORMAT_YV12; | 
|  | 776 | C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 777 | c2_status_t err = | 
|  | 778 | pool->fetchGraphicBlock(ALIGN32(mWidth), mHeight, format, usage, &mOutBlock); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 779 | if (err != C2_OK) { | 
|  | 780 | ALOGE("fetchGraphicBlock for Output failed with status %d", err); | 
|  | 781 | return err; | 
|  | 782 | } | 
|  | 783 | ALOGV("provided (%dx%d) required (%dx%d)", | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 784 | mOutBlock->width(), mOutBlock->height(), ALIGN32(mWidth), mHeight); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 785 | } | 
|  | 786 |  | 
|  | 787 | return C2_OK; | 
|  | 788 | } | 
|  | 789 |  | 
|  | 790 | // TODO: can overall error checking be improved? | 
|  | 791 | // TODO: allow configuration of color format and usage for graphic buffers instead | 
|  | 792 | //       of hard coding them to HAL_PIXEL_FORMAT_YV12 | 
|  | 793 | // TODO: pass coloraspects information to surface | 
|  | 794 | // TODO: test support for dynamic change in resolution | 
|  | 795 | // TODO: verify if the decoder sent back all frames | 
|  | 796 | void C2SoftAvcDec::process( | 
|  | 797 | const std::unique_ptr<C2Work> &work, | 
|  | 798 | const std::shared_ptr<C2BlockPool> &pool) { | 
|  | 799 | // Initialize output work | 
|  | 800 | work->result = C2_OK; | 
|  | 801 | work->workletsProcessed = 0u; | 
|  | 802 | work->worklets.front()->output.flags = work->input.flags; | 
|  | 803 | if (mSignalledError || mSignalledOutputEos) { | 
|  | 804 | work->result = C2_BAD_VALUE; | 
|  | 805 | return; | 
|  | 806 | } | 
|  | 807 |  | 
|  | 808 | size_t inOffset = 0u; | 
|  | 809 | size_t inSize = 0u; | 
|  | 810 | uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF; | 
|  | 811 | C2ReadView rView = mDummyReadView; | 
|  | 812 | if (!work->input.buffers.empty()) { | 
|  | 813 | rView = work->input.buffers[0]->data().linearBlocks().front().map().get(); | 
|  | 814 | inSize = rView.capacity(); | 
|  | 815 | if (inSize && rView.error()) { | 
|  | 816 | ALOGE("read view map failed %d", rView.error()); | 
|  | 817 | work->result = rView.error(); | 
|  | 818 | return; | 
|  | 819 | } | 
|  | 820 | } | 
|  | 821 | bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0); | 
|  | 822 | bool hasPicture = false; | 
|  | 823 |  | 
|  | 824 | ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", | 
|  | 825 | inSize, (int)work->input.ordinal.timestamp.peeku(), | 
|  | 826 | (int)work->input.ordinal.frameIndex.peeku(), work->input.flags); | 
|  | 827 | size_t inPos = 0; | 
| Harish Mahendrakar | fd65f91 | 2020-04-02 05:45:05 +0530 | [diff] [blame] | 828 | while (inPos < inSize && inSize - inPos >= kMinInputBytes) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 829 | if (C2_OK != ensureDecoderState(pool)) { | 
|  | 830 | mSignalledError = true; | 
|  | 831 | work->workletsProcessed = 1u; | 
|  | 832 | work->result = C2_CORRUPTED; | 
|  | 833 | return; | 
|  | 834 | } | 
|  | 835 |  | 
|  | 836 | ivd_video_decode_ip_t s_decode_ip; | 
|  | 837 | ivd_video_decode_op_t s_decode_op; | 
|  | 838 | { | 
|  | 839 | C2GraphicView wView = mOutBlock->map().get(); | 
|  | 840 | if (wView.error()) { | 
|  | 841 | ALOGE("graphic view map failed %d", wView.error()); | 
|  | 842 | work->result = wView.error(); | 
|  | 843 | return; | 
|  | 844 | } | 
|  | 845 | if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView, | 
|  | 846 | inOffset + inPos, inSize - inPos, workIndex)) { | 
|  | 847 | mSignalledError = true; | 
|  | 848 | work->workletsProcessed = 1u; | 
|  | 849 | work->result = C2_CORRUPTED; | 
|  | 850 | return; | 
|  | 851 | } | 
|  | 852 |  | 
|  | 853 | if (false == mHeaderDecoded) { | 
|  | 854 | /* Decode header and get dimensions */ | 
|  | 855 | setParams(mStride, IVD_DECODE_HEADER); | 
|  | 856 | } | 
|  | 857 |  | 
|  | 858 | WORD32 delay; | 
|  | 859 | GETTIME(&mTimeStart, nullptr); | 
|  | 860 | TIME_DIFF(mTimeEnd, mTimeStart, delay); | 
|  | 861 | (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); | 
|  | 862 | WORD32 decodeTime; | 
|  | 863 | GETTIME(&mTimeEnd, nullptr); | 
|  | 864 | TIME_DIFF(mTimeStart, mTimeEnd, decodeTime); | 
|  | 865 | ALOGV("decodeTime=%6d delay=%6d numBytes=%6d", decodeTime, delay, | 
|  | 866 | s_decode_op.u4_num_bytes_consumed); | 
|  | 867 | } | 
| Harish Mahendrakar | 8f98eee | 2019-04-16 11:34:33 -0700 | [diff] [blame] | 868 | if (IVD_MEM_ALLOC_FAILED == (s_decode_op.u4_error_code & IVD_ERROR_MASK)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 869 | ALOGE("allocation failure in decoder"); | 
|  | 870 | mSignalledError = true; | 
|  | 871 | work->workletsProcessed = 1u; | 
|  | 872 | work->result = C2_CORRUPTED; | 
|  | 873 | return; | 
| Harish Mahendrakar | 8f98eee | 2019-04-16 11:34:33 -0700 | [diff] [blame] | 874 | } else if (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_decode_op.u4_error_code & IVD_ERROR_MASK)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 875 | ALOGE("unsupported resolution : %dx%d", mWidth, mHeight); | 
|  | 876 | mSignalledError = true; | 
|  | 877 | work->workletsProcessed = 1u; | 
|  | 878 | work->result = C2_CORRUPTED; | 
|  | 879 | return; | 
| Harish Mahendrakar | 8f98eee | 2019-04-16 11:34:33 -0700 | [diff] [blame] | 880 | } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & IVD_ERROR_MASK)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 881 | ALOGV("resolution changed"); | 
|  | 882 | drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work); | 
|  | 883 | resetDecoder(); | 
|  | 884 | resetPlugin(); | 
|  | 885 | work->workletsProcessed = 0u; | 
|  | 886 |  | 
|  | 887 | /* Decode header and get new dimensions */ | 
|  | 888 | setParams(mStride, IVD_DECODE_HEADER); | 
|  | 889 | (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); | 
| Harish Mahendrakar | 8f98eee | 2019-04-16 11:34:33 -0700 | [diff] [blame] | 890 | } else if (IS_IVD_FATAL_ERROR(s_decode_op.u4_error_code)) { | 
|  | 891 | ALOGE("Fatal error in decoder 0x%x", s_decode_op.u4_error_code); | 
|  | 892 | mSignalledError = true; | 
|  | 893 | work->workletsProcessed = 1u; | 
|  | 894 | work->result = C2_CORRUPTED; | 
|  | 895 | return; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 896 | } | 
| Harish Mahendrakar | 343be8a | 2019-08-01 12:38:58 -0700 | [diff] [blame] | 897 | if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) { | 
|  | 898 | mOutputDelay = s_decode_op.i4_reorder_depth; | 
|  | 899 | ALOGV("New Output delay %d ", mOutputDelay); | 
|  | 900 |  | 
|  | 901 | C2PortActualDelayTuning::output outputDelay(mOutputDelay); | 
|  | 902 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
|  | 903 | c2_status_t err = | 
|  | 904 | mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures); | 
|  | 905 | if (err == OK) { | 
|  | 906 | work->worklets.front()->output.configUpdate.push_back( | 
|  | 907 | C2Param::Copy(outputDelay)); | 
|  | 908 | } else { | 
|  | 909 | ALOGE("Cannot set output delay"); | 
|  | 910 | mSignalledError = true; | 
|  | 911 | work->workletsProcessed = 1u; | 
|  | 912 | work->result = C2_CORRUPTED; | 
|  | 913 | return; | 
|  | 914 | } | 
| Harish Mahendrakar | 343be8a | 2019-08-01 12:38:58 -0700 | [diff] [blame] | 915 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 916 | if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) { | 
|  | 917 | if (mHeaderDecoded == false) { | 
|  | 918 | mHeaderDecoded = true; | 
| Harish Mahendrakar | 6a7e93d | 2019-10-18 16:27:38 -0700 | [diff] [blame] | 919 | mStride = ALIGN32(s_decode_op.u4_pic_wd); | 
|  | 920 | setParams(mStride, IVD_DECODE_FRAME); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 921 | } | 
|  | 922 | if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) { | 
|  | 923 | mWidth = s_decode_op.u4_pic_wd; | 
|  | 924 | mHeight = s_decode_op.u4_pic_ht; | 
|  | 925 | CHECK_EQ(0u, s_decode_op.u4_output_present); | 
|  | 926 |  | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 927 | C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 928 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
|  | 929 | c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures); | 
|  | 930 | if (err == OK) { | 
|  | 931 | work->worklets.front()->output.configUpdate.push_back( | 
|  | 932 | C2Param::Copy(size)); | 
|  | 933 | } else { | 
|  | 934 | ALOGE("Cannot set width and height"); | 
|  | 935 | mSignalledError = true; | 
|  | 936 | work->workletsProcessed = 1u; | 
|  | 937 | work->result = C2_CORRUPTED; | 
|  | 938 | return; | 
|  | 939 | } | 
|  | 940 | continue; | 
|  | 941 | } | 
|  | 942 | } | 
|  | 943 | (void)getVuiParams(); | 
|  | 944 | hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag); | 
|  | 945 | if (s_decode_op.u4_output_present) { | 
|  | 946 | finishWork(s_decode_op.u4_ts, work); | 
|  | 947 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 948 | inPos += s_decode_op.u4_num_bytes_consumed; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 949 | } | 
|  | 950 | if (eos) { | 
|  | 951 | drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work); | 
|  | 952 | mSignalledOutputEos = true; | 
|  | 953 | } else if (!hasPicture) { | 
|  | 954 | fillEmptyWork(work); | 
|  | 955 | } | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 956 |  | 
|  | 957 | work->input.buffers.clear(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 958 | } | 
|  | 959 |  | 
|  | 960 | c2_status_t C2SoftAvcDec::drainInternal( | 
|  | 961 | uint32_t drainMode, | 
|  | 962 | const std::shared_ptr<C2BlockPool> &pool, | 
|  | 963 | const std::unique_ptr<C2Work> &work) { | 
|  | 964 | if (drainMode == NO_DRAIN) { | 
|  | 965 | ALOGW("drain with NO_DRAIN: no-op"); | 
|  | 966 | return C2_OK; | 
|  | 967 | } | 
|  | 968 | if (drainMode == DRAIN_CHAIN) { | 
|  | 969 | ALOGW("DRAIN_CHAIN not supported"); | 
|  | 970 | return C2_OMITTED; | 
|  | 971 | } | 
|  | 972 |  | 
|  | 973 | if (OK != setFlushMode()) return C2_CORRUPTED; | 
|  | 974 | while (true) { | 
|  | 975 | if (C2_OK != ensureDecoderState(pool)) { | 
|  | 976 | mSignalledError = true; | 
|  | 977 | work->workletsProcessed = 1u; | 
|  | 978 | work->result = C2_CORRUPTED; | 
|  | 979 | return C2_CORRUPTED; | 
|  | 980 | } | 
|  | 981 | C2GraphicView wView = mOutBlock->map().get(); | 
|  | 982 | if (wView.error()) { | 
|  | 983 | ALOGE("graphic view map failed %d", wView.error()); | 
|  | 984 | return C2_CORRUPTED; | 
|  | 985 | } | 
|  | 986 | ivd_video_decode_ip_t s_decode_ip; | 
|  | 987 | ivd_video_decode_op_t s_decode_op; | 
|  | 988 | if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) { | 
|  | 989 | mSignalledError = true; | 
|  | 990 | work->workletsProcessed = 1u; | 
|  | 991 | return C2_CORRUPTED; | 
|  | 992 | } | 
|  | 993 | (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); | 
|  | 994 | if (s_decode_op.u4_output_present) { | 
|  | 995 | finishWork(s_decode_op.u4_ts, work); | 
|  | 996 | } else { | 
|  | 997 | fillEmptyWork(work); | 
|  | 998 | break; | 
|  | 999 | } | 
|  | 1000 | } | 
|  | 1001 |  | 
|  | 1002 | return C2_OK; | 
|  | 1003 | } | 
|  | 1004 |  | 
|  | 1005 | c2_status_t C2SoftAvcDec::drain( | 
|  | 1006 | uint32_t drainMode, | 
|  | 1007 | const std::shared_ptr<C2BlockPool> &pool) { | 
|  | 1008 | return drainInternal(drainMode, pool, nullptr); | 
|  | 1009 | } | 
|  | 1010 |  | 
|  | 1011 | class C2SoftAvcDecFactory : public C2ComponentFactory { | 
|  | 1012 | public: | 
|  | 1013 | C2SoftAvcDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>( | 
|  | 1014 | GetCodec2PlatformComponentStore()->getParamReflector())) { | 
|  | 1015 | } | 
|  | 1016 |  | 
|  | 1017 | virtual c2_status_t createComponent( | 
|  | 1018 | c2_node_id_t id, | 
|  | 1019 | std::shared_ptr<C2Component>* const component, | 
|  | 1020 | std::function<void(C2Component*)> deleter) override { | 
|  | 1021 | *component = std::shared_ptr<C2Component>( | 
|  | 1022 | new C2SoftAvcDec(COMPONENT_NAME, | 
|  | 1023 | id, | 
|  | 1024 | std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)), | 
|  | 1025 | deleter); | 
|  | 1026 | return C2_OK; | 
|  | 1027 | } | 
|  | 1028 |  | 
|  | 1029 | virtual c2_status_t createInterface( | 
|  | 1030 | c2_node_id_t id, | 
|  | 1031 | std::shared_ptr<C2ComponentInterface>* const interface, | 
|  | 1032 | std::function<void(C2ComponentInterface*)> deleter) override { | 
|  | 1033 | *interface = std::shared_ptr<C2ComponentInterface>( | 
|  | 1034 | new SimpleInterface<C2SoftAvcDec::IntfImpl>( | 
|  | 1035 | COMPONENT_NAME, id, std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)), | 
|  | 1036 | deleter); | 
|  | 1037 | return C2_OK; | 
|  | 1038 | } | 
|  | 1039 |  | 
|  | 1040 | virtual ~C2SoftAvcDecFactory() override = default; | 
|  | 1041 |  | 
|  | 1042 | private: | 
|  | 1043 | std::shared_ptr<C2ReflectorHelper> mHelper; | 
|  | 1044 | }; | 
|  | 1045 |  | 
|  | 1046 | }  // namespace android | 
|  | 1047 |  | 
|  | 1048 | extern "C" ::C2ComponentFactory* CreateCodec2Factory() { | 
|  | 1049 | ALOGV("in %s", __func__); | 
|  | 1050 | return new ::android::C2SoftAvcDecFactory(); | 
|  | 1051 | } | 
|  | 1052 |  | 
|  | 1053 | extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { | 
|  | 1054 | ALOGV("in %s", __func__); | 
|  | 1055 | delete factory; | 
|  | 1056 | } |