| Vignesh Venkatasubramanian | b6d383d | 2019-06-10 15:11:58 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2019 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 "C2SoftGav1Dec" | 
 | 19 | #include "C2SoftGav1Dec.h" | 
 | 20 |  | 
 | 21 | #include <C2Debug.h> | 
 | 22 | #include <C2PlatformSupport.h> | 
 | 23 | #include <SimpleC2Interface.h> | 
 | 24 | #include <log/log.h> | 
 | 25 | #include <media/stagefright/foundation/AUtils.h> | 
 | 26 | #include <media/stagefright/foundation/MediaDefs.h> | 
 | 27 |  | 
 | 28 | namespace android { | 
 | 29 |  | 
| Ray Essick | c2cc437 | 2019-08-21 14:02:28 -0700 | [diff] [blame] | 30 | // codecname set and passed in as a compile flag from Android.bp | 
 | 31 | constexpr char COMPONENT_NAME[] = CODECNAME; | 
| Vignesh Venkatasubramanian | b6d383d | 2019-06-10 15:11:58 -0700 | [diff] [blame] | 32 |  | 
 | 33 | class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams { | 
 | 34 |  public: | 
 | 35 |   explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) | 
 | 36 |       : SimpleInterface<void>::BaseParams( | 
 | 37 |             helper, COMPONENT_NAME, C2Component::KIND_DECODER, | 
 | 38 |             C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) { | 
 | 39 |     noPrivateBuffers();  // TODO: account for our buffers here. | 
 | 40 |     noInputReferences(); | 
 | 41 |     noOutputReferences(); | 
 | 42 |     noInputLatency(); | 
 | 43 |     noTimeStretch(); | 
 | 44 |  | 
 | 45 |     addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) | 
 | 46 |                      .withConstValue(new C2ComponentAttributesSetting( | 
 | 47 |                          C2Component::ATTRIB_IS_TEMPORAL)) | 
 | 48 |                      .build()); | 
 | 49 |  | 
 | 50 |     addParameter( | 
 | 51 |         DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) | 
 | 52 |             .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240)) | 
 | 53 |             .withFields({ | 
 | 54 |                 C2F(mSize, width).inRange(2, 2048, 2), | 
 | 55 |                 C2F(mSize, height).inRange(2, 2048, 2), | 
 | 56 |             }) | 
 | 57 |             .withSetter(SizeSetter) | 
 | 58 |             .build()); | 
 | 59 |  | 
 | 60 |     addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) | 
 | 61 |                      .withDefault(new C2StreamProfileLevelInfo::input( | 
 | 62 |                          0u, C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1)) | 
 | 63 |                      .withFields({C2F(mProfileLevel, profile) | 
 | 64 |                                       .oneOf({C2Config::PROFILE_AV1_0, | 
 | 65 |                                               C2Config::PROFILE_AV1_1}), | 
 | 66 |                                   C2F(mProfileLevel, level) | 
 | 67 |                                       .oneOf({ | 
 | 68 |                                           C2Config::LEVEL_AV1_2, | 
 | 69 |                                           C2Config::LEVEL_AV1_2_1, | 
 | 70 |                                           C2Config::LEVEL_AV1_2_2, | 
 | 71 |                                           C2Config::LEVEL_AV1_3, | 
 | 72 |                                           C2Config::LEVEL_AV1_3_1, | 
 | 73 |                                           C2Config::LEVEL_AV1_3_2, | 
 | 74 |                                       })}) | 
 | 75 |                      .withSetter(ProfileLevelSetter, mSize) | 
 | 76 |                      .build()); | 
 | 77 |  | 
 | 78 |     mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0); | 
 | 79 |     addParameter( | 
 | 80 |         DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO) | 
 | 81 |             .withDefault(mHdr10PlusInfoInput) | 
 | 82 |             .withFields({ | 
 | 83 |                 C2F(mHdr10PlusInfoInput, m.value).any(), | 
 | 84 |             }) | 
 | 85 |             .withSetter(Hdr10PlusInfoInputSetter) | 
 | 86 |             .build()); | 
 | 87 |  | 
 | 88 |     mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0); | 
 | 89 |     addParameter( | 
 | 90 |         DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO) | 
 | 91 |             .withDefault(mHdr10PlusInfoOutput) | 
 | 92 |             .withFields({ | 
 | 93 |                 C2F(mHdr10PlusInfoOutput, m.value).any(), | 
 | 94 |             }) | 
 | 95 |             .withSetter(Hdr10PlusInfoOutputSetter) | 
 | 96 |             .build()); | 
 | 97 |  | 
 | 98 |     addParameter( | 
 | 99 |         DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE) | 
 | 100 |             .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240)) | 
 | 101 |             .withFields({ | 
 | 102 |                 C2F(mSize, width).inRange(2, 2048, 2), | 
 | 103 |                 C2F(mSize, height).inRange(2, 2048, 2), | 
 | 104 |             }) | 
 | 105 |             .withSetter(MaxPictureSizeSetter, mSize) | 
 | 106 |             .build()); | 
 | 107 |  | 
 | 108 |     addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) | 
 | 109 |                      .withDefault(new C2StreamMaxBufferSizeInfo::input( | 
 | 110 |                          0u, 320 * 240 * 3 / 4)) | 
 | 111 |                      .withFields({ | 
 | 112 |                          C2F(mMaxInputSize, value).any(), | 
 | 113 |                      }) | 
 | 114 |                      .calculatedAs(MaxInputSizeSetter, mMaxSize) | 
 | 115 |                      .build()); | 
 | 116 |  | 
 | 117 |     C2ChromaOffsetStruct locations[1] = {C2ChromaOffsetStruct::ITU_YUV_420_0()}; | 
 | 118 |     std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo = | 
 | 119 |         C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */, | 
 | 120 |                                                C2Color::YUV_420); | 
 | 121 |     memcpy(defaultColorInfo->m.locations, locations, sizeof(locations)); | 
 | 122 |  | 
 | 123 |     defaultColorInfo = C2StreamColorInfo::output::AllocShared( | 
 | 124 |         {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */, | 
 | 125 |         C2Color::YUV_420); | 
 | 126 |     helper->addStructDescriptors<C2ChromaOffsetStruct>(); | 
 | 127 |  | 
 | 128 |     addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO) | 
 | 129 |                      .withConstValue(defaultColorInfo) | 
 | 130 |                      .build()); | 
 | 131 |  | 
 | 132 |     addParameter( | 
 | 133 |         DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) | 
 | 134 |             .withDefault(new C2StreamColorAspectsTuning::output( | 
 | 135 |                 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, | 
 | 136 |                 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) | 
 | 137 |             .withFields( | 
 | 138 |                 {C2F(mDefaultColorAspects, range) | 
 | 139 |                      .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), | 
 | 140 |                  C2F(mDefaultColorAspects, primaries) | 
 | 141 |                      .inRange(C2Color::PRIMARIES_UNSPECIFIED, | 
 | 142 |                               C2Color::PRIMARIES_OTHER), | 
 | 143 |                  C2F(mDefaultColorAspects, transfer) | 
 | 144 |                      .inRange(C2Color::TRANSFER_UNSPECIFIED, | 
 | 145 |                               C2Color::TRANSFER_OTHER), | 
 | 146 |                  C2F(mDefaultColorAspects, matrix) | 
 | 147 |                      .inRange(C2Color::MATRIX_UNSPECIFIED, | 
 | 148 |                               C2Color::MATRIX_OTHER)}) | 
 | 149 |             .withSetter(DefaultColorAspectsSetter) | 
 | 150 |             .build()); | 
 | 151 |  | 
 | 152 |     // TODO: support more formats? | 
 | 153 |     addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT) | 
 | 154 |                      .withConstValue(new C2StreamPixelFormatInfo::output( | 
 | 155 |                          0u, HAL_PIXEL_FORMAT_YCBCR_420_888)) | 
 | 156 |                      .build()); | 
 | 157 |   } | 
 | 158 |  | 
 | 159 |   static C2R SizeSetter(bool mayBlock, | 
 | 160 |                         const C2P<C2StreamPictureSizeInfo::output> &oldMe, | 
 | 161 |                         C2P<C2StreamPictureSizeInfo::output> &me) { | 
 | 162 |     (void)mayBlock; | 
 | 163 |     C2R res = C2R::Ok(); | 
 | 164 |     if (!me.F(me.v.width).supportsAtAll(me.v.width)) { | 
 | 165 |       res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width))); | 
 | 166 |       me.set().width = oldMe.v.width; | 
 | 167 |     } | 
 | 168 |     if (!me.F(me.v.height).supportsAtAll(me.v.height)) { | 
 | 169 |       res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height))); | 
 | 170 |       me.set().height = oldMe.v.height; | 
 | 171 |     } | 
 | 172 |     return res; | 
 | 173 |   } | 
 | 174 |  | 
 | 175 |   static C2R MaxPictureSizeSetter( | 
 | 176 |       bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me, | 
 | 177 |       const C2P<C2StreamPictureSizeInfo::output> &size) { | 
 | 178 |     (void)mayBlock; | 
 | 179 |     // TODO: get max width/height from the size's field helpers vs. | 
 | 180 |     // hardcoding | 
 | 181 |     me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u); | 
 | 182 |     me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u); | 
 | 183 |     return C2R::Ok(); | 
 | 184 |   } | 
 | 185 |  | 
 | 186 |   static C2R MaxInputSizeSetter( | 
 | 187 |       bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me, | 
 | 188 |       const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) { | 
 | 189 |     (void)mayBlock; | 
 | 190 |     // assume compression ratio of 2 | 
 | 191 |     me.set().value = | 
 | 192 |         (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072); | 
 | 193 |     return C2R::Ok(); | 
 | 194 |   } | 
 | 195 |  | 
 | 196 |   static C2R DefaultColorAspectsSetter( | 
 | 197 |       bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) { | 
 | 198 |     (void)mayBlock; | 
 | 199 |     if (me.v.range > C2Color::RANGE_OTHER) { | 
 | 200 |       me.set().range = C2Color::RANGE_OTHER; | 
 | 201 |     } | 
 | 202 |     if (me.v.primaries > C2Color::PRIMARIES_OTHER) { | 
 | 203 |       me.set().primaries = C2Color::PRIMARIES_OTHER; | 
 | 204 |     } | 
 | 205 |     if (me.v.transfer > C2Color::TRANSFER_OTHER) { | 
 | 206 |       me.set().transfer = C2Color::TRANSFER_OTHER; | 
 | 207 |     } | 
 | 208 |     if (me.v.matrix > C2Color::MATRIX_OTHER) { | 
 | 209 |       me.set().matrix = C2Color::MATRIX_OTHER; | 
 | 210 |     } | 
 | 211 |     return C2R::Ok(); | 
 | 212 |   } | 
 | 213 |  | 
 | 214 |   static C2R ProfileLevelSetter( | 
 | 215 |       bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me, | 
 | 216 |       const C2P<C2StreamPictureSizeInfo::output> &size) { | 
 | 217 |     (void)mayBlock; | 
 | 218 |     (void)size; | 
 | 219 |     (void)me;  // TODO: validate | 
 | 220 |     return C2R::Ok(); | 
 | 221 |   } | 
 | 222 |  | 
 | 223 |   std::shared_ptr<C2StreamColorAspectsTuning::output> | 
 | 224 |   getDefaultColorAspects_l() { | 
 | 225 |     return mDefaultColorAspects; | 
 | 226 |   } | 
 | 227 |  | 
 | 228 |   static C2R Hdr10PlusInfoInputSetter(bool mayBlock, | 
 | 229 |                                       C2P<C2StreamHdr10PlusInfo::input> &me) { | 
 | 230 |     (void)mayBlock; | 
 | 231 |     (void)me;  // TODO: validate | 
 | 232 |     return C2R::Ok(); | 
 | 233 |   } | 
 | 234 |  | 
 | 235 |   static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, | 
 | 236 |                                        C2P<C2StreamHdr10PlusInfo::output> &me) { | 
 | 237 |     (void)mayBlock; | 
 | 238 |     (void)me;  // TODO: validate | 
 | 239 |     return C2R::Ok(); | 
 | 240 |   } | 
 | 241 |  | 
 | 242 |  private: | 
 | 243 |   std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel; | 
 | 244 |   std::shared_ptr<C2StreamPictureSizeInfo::output> mSize; | 
 | 245 |   std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize; | 
 | 246 |   std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize; | 
 | 247 |   std::shared_ptr<C2StreamColorInfo::output> mColorInfo; | 
 | 248 |   std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat; | 
 | 249 |   std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects; | 
 | 250 |   std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput; | 
 | 251 |   std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput; | 
 | 252 | }; | 
 | 253 |  | 
 | 254 | C2SoftGav1Dec::C2SoftGav1Dec(const char *name, c2_node_id_t id, | 
 | 255 |                              const std::shared_ptr<IntfImpl> &intfImpl) | 
 | 256 |     : SimpleC2Component( | 
 | 257 |           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 258 |       mIntf(intfImpl), | 
 | 259 |       mCodecCtx(nullptr) { | 
 | 260 |   gettimeofday(&mTimeStart, nullptr); | 
 | 261 |   gettimeofday(&mTimeEnd, nullptr); | 
 | 262 | } | 
| Vignesh Venkatasubramanian | b6d383d | 2019-06-10 15:11:58 -0700 | [diff] [blame] | 263 |  | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 264 | C2SoftGav1Dec::~C2SoftGav1Dec() { onRelease(); } | 
 | 265 |  | 
 | 266 | c2_status_t C2SoftGav1Dec::onInit() { | 
 | 267 |   return initDecoder() ? C2_OK : C2_CORRUPTED; | 
 | 268 | } | 
 | 269 |  | 
 | 270 | c2_status_t C2SoftGav1Dec::onStop() { | 
 | 271 |   mSignalledError = false; | 
 | 272 |   mSignalledOutputEos = false; | 
| Vignesh Venkatasubramanian | b6d383d | 2019-06-10 15:11:58 -0700 | [diff] [blame] | 273 |   return C2_OK; | 
 | 274 | } | 
 | 275 |  | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 276 | void C2SoftGav1Dec::onReset() { | 
 | 277 |   (void)onStop(); | 
 | 278 |   c2_status_t err = onFlush_sm(); | 
 | 279 |   if (err != C2_OK) { | 
 | 280 |     ALOGW("Failed to flush the av1 decoder. Trying to hard reset."); | 
 | 281 |     destroyDecoder(); | 
 | 282 |     if (!initDecoder()) { | 
 | 283 |       ALOGE("Hard reset failed."); | 
 | 284 |     } | 
 | 285 |   } | 
 | 286 | } | 
 | 287 |  | 
 | 288 | void C2SoftGav1Dec::onRelease() { destroyDecoder(); } | 
 | 289 |  | 
 | 290 | c2_status_t C2SoftGav1Dec::onFlush_sm() { | 
 | 291 |   Libgav1StatusCode status = | 
 | 292 |       mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, | 
 | 293 |                               /*user_private_data=*/0); | 
 | 294 |   if (status != kLibgav1StatusOk) { | 
 | 295 |     ALOGE("Failed to flush av1 decoder. status: %d.", status); | 
 | 296 |     return C2_CORRUPTED; | 
 | 297 |   } | 
 | 298 |  | 
 | 299 |   // Dequeue frame (if any) that was enqueued previously. | 
 | 300 |   const libgav1::DecoderBuffer *buffer; | 
 | 301 |   status = mCodecCtx->DequeueFrame(&buffer); | 
 | 302 |   if (status != kLibgav1StatusOk) { | 
 | 303 |     ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d", | 
 | 304 |           status); | 
 | 305 |     return C2_CORRUPTED; | 
 | 306 |   } | 
 | 307 |  | 
 | 308 |   mSignalledError = false; | 
 | 309 |   mSignalledOutputEos = false; | 
 | 310 |  | 
 | 311 |   return C2_OK; | 
 | 312 | } | 
 | 313 |  | 
 | 314 | static int GetCPUCoreCount() { | 
 | 315 |   int cpuCoreCount = 1; | 
 | 316 | #if defined(_SC_NPROCESSORS_ONLN) | 
 | 317 |   cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); | 
 | 318 | #else | 
 | 319 |   // _SC_NPROC_ONLN must be defined... | 
 | 320 |   cpuCoreCount = sysconf(_SC_NPROC_ONLN); | 
 | 321 | #endif | 
 | 322 |   CHECK(cpuCoreCount >= 1); | 
 | 323 |   ALOGV("Number of CPU cores: %d", cpuCoreCount); | 
 | 324 |   return cpuCoreCount; | 
 | 325 | } | 
 | 326 |  | 
 | 327 | bool C2SoftGav1Dec::initDecoder() { | 
 | 328 |   mSignalledError = false; | 
 | 329 |   mSignalledOutputEos = false; | 
 | 330 |   mCodecCtx.reset(new libgav1::Decoder()); | 
 | 331 |  | 
 | 332 |   if (mCodecCtx == nullptr) { | 
 | 333 |     ALOGE("mCodecCtx is null"); | 
 | 334 |     return false; | 
 | 335 |   } | 
 | 336 |  | 
 | 337 |   libgav1::DecoderSettings settings = {}; | 
 | 338 |   settings.threads = GetCPUCoreCount(); | 
 | 339 |  | 
| Vignesh Venkatasubramanian | 61ba2cf | 2019-06-24 10:04:00 -0700 | [diff] [blame] | 340 |   ALOGV("Using libgav1 AV1 software decoder."); | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 341 |   Libgav1StatusCode status = mCodecCtx->Init(&settings); | 
 | 342 |   if (status != kLibgav1StatusOk) { | 
 | 343 |     ALOGE("av1 decoder failed to initialize. status: %d.", status); | 
 | 344 |     return false; | 
 | 345 |   } | 
 | 346 |  | 
 | 347 |   return true; | 
 | 348 | } | 
 | 349 |  | 
 | 350 | void C2SoftGav1Dec::destroyDecoder() { mCodecCtx = nullptr; } | 
 | 351 |  | 
 | 352 | void fillEmptyWork(const std::unique_ptr<C2Work> &work) { | 
 | 353 |   uint32_t flags = 0; | 
 | 354 |   if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { | 
 | 355 |     flags |= C2FrameData::FLAG_END_OF_STREAM; | 
 | 356 |     ALOGV("signalling eos"); | 
 | 357 |   } | 
 | 358 |   work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; | 
 | 359 |   work->worklets.front()->output.buffers.clear(); | 
 | 360 |   work->worklets.front()->output.ordinal = work->input.ordinal; | 
 | 361 |   work->workletsProcessed = 1u; | 
 | 362 | } | 
 | 363 |  | 
 | 364 | void C2SoftGav1Dec::finishWork(uint64_t index, | 
 | 365 |                                const std::unique_ptr<C2Work> &work, | 
 | 366 |                                const std::shared_ptr<C2GraphicBlock> &block) { | 
 | 367 |   std::shared_ptr<C2Buffer> buffer = | 
 | 368 |       createGraphicBuffer(block, C2Rect(mWidth, mHeight)); | 
 | 369 |   auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) { | 
 | 370 |     uint32_t flags = 0; | 
 | 371 |     if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) && | 
 | 372 |         (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) { | 
 | 373 |       flags |= C2FrameData::FLAG_END_OF_STREAM; | 
 | 374 |       ALOGV("signalling eos"); | 
 | 375 |     } | 
 | 376 |     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; | 
 | 377 |     work->worklets.front()->output.buffers.clear(); | 
 | 378 |     work->worklets.front()->output.buffers.push_back(buffer); | 
 | 379 |     work->worklets.front()->output.ordinal = work->input.ordinal; | 
 | 380 |     work->workletsProcessed = 1u; | 
 | 381 |   }; | 
 | 382 |   if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) { | 
 | 383 |     fillWork(work); | 
 | 384 |   } else { | 
 | 385 |     finish(index, fillWork); | 
 | 386 |   } | 
 | 387 | } | 
 | 388 |  | 
 | 389 | void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work, | 
 | 390 |                             const std::shared_ptr<C2BlockPool> &pool) { | 
 | 391 |   work->result = C2_OK; | 
 | 392 |   work->workletsProcessed = 0u; | 
 | 393 |   work->worklets.front()->output.configUpdate.clear(); | 
 | 394 |   work->worklets.front()->output.flags = work->input.flags; | 
 | 395 |   if (mSignalledError || mSignalledOutputEos) { | 
 | 396 |     work->result = C2_BAD_VALUE; | 
 | 397 |     return; | 
 | 398 |   } | 
 | 399 |  | 
 | 400 |   size_t inOffset = 0u; | 
 | 401 |   size_t inSize = 0u; | 
 | 402 |   C2ReadView rView = mDummyReadView; | 
 | 403 |   if (!work->input.buffers.empty()) { | 
 | 404 |     rView = work->input.buffers[0]->data().linearBlocks().front().map().get(); | 
 | 405 |     inSize = rView.capacity(); | 
 | 406 |     if (inSize && rView.error()) { | 
 | 407 |       ALOGE("read view map failed %d", rView.error()); | 
 | 408 |       work->result = C2_CORRUPTED; | 
 | 409 |       return; | 
 | 410 |     } | 
 | 411 |   } | 
 | 412 |  | 
 | 413 |   bool codecConfig = | 
 | 414 |       ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0); | 
 | 415 |   bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0); | 
 | 416 |  | 
 | 417 |   ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize, | 
 | 418 |         (int)work->input.ordinal.timestamp.peeku(), | 
 | 419 |         (int)work->input.ordinal.frameIndex.peeku(), work->input.flags); | 
 | 420 |  | 
 | 421 |   if (codecConfig) { | 
 | 422 |     fillEmptyWork(work); | 
 | 423 |     return; | 
 | 424 |   } | 
 | 425 |  | 
 | 426 |   int64_t frameIndex = work->input.ordinal.frameIndex.peekll(); | 
 | 427 |   if (inSize) { | 
 | 428 |     uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset); | 
 | 429 |     int32_t decodeTime = 0; | 
 | 430 |     int32_t delay = 0; | 
 | 431 |  | 
 | 432 |     GETTIME(&mTimeStart, nullptr); | 
 | 433 |     TIME_DIFF(mTimeEnd, mTimeStart, delay); | 
 | 434 |  | 
 | 435 |     const Libgav1StatusCode status = | 
 | 436 |         mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex); | 
 | 437 |  | 
 | 438 |     GETTIME(&mTimeEnd, nullptr); | 
 | 439 |     TIME_DIFF(mTimeStart, mTimeEnd, decodeTime); | 
 | 440 |     ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay); | 
 | 441 |  | 
 | 442 |     if (status != kLibgav1StatusOk) { | 
 | 443 |       ALOGE("av1 decoder failed to decode frame. status: %d.", status); | 
 | 444 |       work->result = C2_CORRUPTED; | 
 | 445 |       work->workletsProcessed = 1u; | 
 | 446 |       mSignalledError = true; | 
 | 447 |       return; | 
 | 448 |     } | 
 | 449 |  | 
 | 450 |   } else { | 
 | 451 |     const Libgav1StatusCode status = | 
 | 452 |         mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, | 
 | 453 |                                 /*user_private_data=*/0); | 
 | 454 |     if (status != kLibgav1StatusOk) { | 
 | 455 |       ALOGE("Failed to flush av1 decoder. status: %d.", status); | 
 | 456 |       work->result = C2_CORRUPTED; | 
 | 457 |       work->workletsProcessed = 1u; | 
 | 458 |       mSignalledError = true; | 
 | 459 |       return; | 
 | 460 |     } | 
 | 461 |   } | 
 | 462 |  | 
 | 463 |   (void)outputBuffer(pool, work); | 
 | 464 |  | 
 | 465 |   if (eos) { | 
 | 466 |     drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work); | 
 | 467 |     mSignalledOutputEos = true; | 
 | 468 |   } else if (!inSize) { | 
 | 469 |     fillEmptyWork(work); | 
 | 470 |   } | 
 | 471 | } | 
 | 472 |  | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 473 | static void copyOutputBufferToYuvPlanarFrame(uint8_t *dst, const uint8_t *srcY, | 
 | 474 |                                              const uint8_t *srcU, | 
 | 475 |                                              const uint8_t *srcV, size_t srcYStride, | 
 | 476 |                                              size_t srcUStride, size_t srcVStride, | 
 | 477 |                                              size_t dstYStride, size_t dstUVStride, | 
 | 478 |                                              uint32_t width, uint32_t height) { | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 479 |   uint8_t *const dstStart = dst; | 
 | 480 |  | 
 | 481 |   for (size_t i = 0; i < height; ++i) { | 
 | 482 |     memcpy(dst, srcY, width); | 
 | 483 |     srcY += srcYStride; | 
 | 484 |     dst += dstYStride; | 
 | 485 |   } | 
 | 486 |  | 
 | 487 |   dst = dstStart + dstYStride * height; | 
 | 488 |   for (size_t i = 0; i < height / 2; ++i) { | 
 | 489 |     memcpy(dst, srcV, width / 2); | 
 | 490 |     srcV += srcVStride; | 
 | 491 |     dst += dstUVStride; | 
 | 492 |   } | 
 | 493 |  | 
 | 494 |   dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2); | 
 | 495 |   for (size_t i = 0; i < height / 2; ++i) { | 
 | 496 |     memcpy(dst, srcU, width / 2); | 
 | 497 |     srcU += srcUStride; | 
 | 498 |     dst += dstUVStride; | 
 | 499 |   } | 
 | 500 | } | 
 | 501 |  | 
 | 502 | static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, | 
 | 503 |                                         const uint16_t *srcU, | 
 | 504 |                                         const uint16_t *srcV, size_t srcYStride, | 
 | 505 |                                         size_t srcUStride, size_t srcVStride, | 
 | 506 |                                         size_t dstStride, size_t width, | 
 | 507 |                                         size_t height) { | 
 | 508 |   // Converting two lines at a time, slightly faster | 
 | 509 |   for (size_t y = 0; y < height; y += 2) { | 
 | 510 |     uint32_t *dstTop = (uint32_t *)dst; | 
 | 511 |     uint32_t *dstBot = (uint32_t *)(dst + dstStride); | 
 | 512 |     uint16_t *ySrcTop = (uint16_t *)srcY; | 
 | 513 |     uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride); | 
 | 514 |     uint16_t *uSrc = (uint16_t *)srcU; | 
 | 515 |     uint16_t *vSrc = (uint16_t *)srcV; | 
 | 516 |  | 
 | 517 |     uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1; | 
 | 518 |     size_t x = 0; | 
 | 519 |     for (; x < width - 3; x += 4) { | 
 | 520 |       u01 = *((uint32_t *)uSrc); | 
 | 521 |       uSrc += 2; | 
 | 522 |       v01 = *((uint32_t *)vSrc); | 
 | 523 |       vSrc += 2; | 
 | 524 |  | 
 | 525 |       y01 = *((uint32_t *)ySrcTop); | 
 | 526 |       ySrcTop += 2; | 
 | 527 |       y23 = *((uint32_t *)ySrcTop); | 
 | 528 |       ySrcTop += 2; | 
 | 529 |       y45 = *((uint32_t *)ySrcBot); | 
 | 530 |       ySrcBot += 2; | 
 | 531 |       y67 = *((uint32_t *)ySrcBot); | 
 | 532 |       ySrcBot += 2; | 
 | 533 |  | 
 | 534 |       uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20); | 
 | 535 |       uv1 = (u01 >> 16) | ((v01 >> 16) << 20); | 
 | 536 |  | 
 | 537 |       *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0; | 
 | 538 |       *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0; | 
 | 539 |       *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1; | 
 | 540 |       *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1; | 
 | 541 |  | 
 | 542 |       *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0; | 
 | 543 |       *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0; | 
 | 544 |       *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1; | 
 | 545 |       *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1; | 
 | 546 |     } | 
 | 547 |  | 
 | 548 |     // There should be at most 2 more pixels to process. Note that we don't | 
 | 549 |     // need to consider odd case as the buffer is always aligned to even. | 
 | 550 |     if (x < width) { | 
 | 551 |       u01 = *uSrc; | 
 | 552 |       v01 = *vSrc; | 
 | 553 |       y01 = *((uint32_t *)ySrcTop); | 
 | 554 |       y45 = *((uint32_t *)ySrcBot); | 
 | 555 |       uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20); | 
 | 556 |       *dstTop++ = ((y01 & 0x3FF) << 10) | uv0; | 
 | 557 |       *dstTop++ = ((y01 >> 16) << 10) | uv0; | 
 | 558 |       *dstBot++ = ((y45 & 0x3FF) << 10) | uv0; | 
 | 559 |       *dstBot++ = ((y45 >> 16) << 10) | uv0; | 
 | 560 |     } | 
 | 561 |  | 
 | 562 |     srcY += srcYStride * 2; | 
 | 563 |     srcU += srcUStride; | 
 | 564 |     srcV += srcVStride; | 
 | 565 |     dst += dstStride * 2; | 
 | 566 |   } | 
 | 567 | } | 
 | 568 |  | 
 | 569 | static void convertYUV420Planar16ToYUV420Planar( | 
 | 570 |     uint8_t *dst, const uint16_t *srcY, const uint16_t *srcU, | 
 | 571 |     const uint16_t *srcV, size_t srcYStride, size_t srcUStride, | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 572 |     size_t srcVStride, size_t dstYStride, size_t dstUVStride, | 
 | 573 |     size_t width, size_t height) { | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 574 |   uint8_t *dstY = (uint8_t *)dst; | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 575 |   size_t dstYSize = dstYStride * height; | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 576 |   size_t dstUVSize = dstUVStride * height / 2; | 
 | 577 |   uint8_t *dstV = dstY + dstYSize; | 
 | 578 |   uint8_t *dstU = dstV + dstUVSize; | 
 | 579 |  | 
 | 580 |   for (size_t y = 0; y < height; ++y) { | 
 | 581 |     for (size_t x = 0; x < width; ++x) { | 
 | 582 |       dstY[x] = (uint8_t)(srcY[x] >> 2); | 
 | 583 |     } | 
 | 584 |  | 
 | 585 |     srcY += srcYStride; | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 586 |     dstY += dstYStride; | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 587 |   } | 
 | 588 |  | 
 | 589 |   for (size_t y = 0; y < (height + 1) / 2; ++y) { | 
 | 590 |     for (size_t x = 0; x < (width + 1) / 2; ++x) { | 
 | 591 |       dstU[x] = (uint8_t)(srcU[x] >> 2); | 
 | 592 |       dstV[x] = (uint8_t)(srcV[x] >> 2); | 
 | 593 |     } | 
 | 594 |  | 
 | 595 |     srcU += srcUStride; | 
 | 596 |     srcV += srcVStride; | 
 | 597 |     dstU += dstUVStride; | 
 | 598 |     dstV += dstUVStride; | 
 | 599 |   } | 
 | 600 | } | 
 | 601 |  | 
 | 602 | bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool, | 
 | 603 |                                  const std::unique_ptr<C2Work> &work) { | 
 | 604 |   if (!(work && pool)) return false; | 
 | 605 |  | 
 | 606 |   const libgav1::DecoderBuffer *buffer; | 
 | 607 |   const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer); | 
 | 608 |  | 
 | 609 |   if (status != kLibgav1StatusOk) { | 
 | 610 |     ALOGE("av1 decoder DequeueFrame failed. status: %d.", status); | 
 | 611 |     return false; | 
 | 612 |   } | 
 | 613 |  | 
 | 614 |   // |buffer| can be NULL if status was equal to kLibgav1StatusOk. This is not | 
 | 615 |   // an error. This could mean one of two things: | 
 | 616 |   //  - The EnqueueFrame() call was either a flush (called with nullptr). | 
 | 617 |   //  - The enqueued frame did not have any displayable frames. | 
 | 618 |   if (!buffer) { | 
 | 619 |     return false; | 
 | 620 |   } | 
 | 621 |  | 
 | 622 |   const int width = buffer->displayed_width[0]; | 
 | 623 |   const int height = buffer->displayed_height[0]; | 
 | 624 |   if (width != mWidth || height != mHeight) { | 
 | 625 |     mWidth = width; | 
 | 626 |     mHeight = height; | 
 | 627 |  | 
 | 628 |     C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight); | 
 | 629 |     std::vector<std::unique_ptr<C2SettingResult>> failures; | 
 | 630 |     c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures); | 
 | 631 |     if (err == C2_OK) { | 
 | 632 |       work->worklets.front()->output.configUpdate.push_back( | 
 | 633 |           C2Param::Copy(size)); | 
 | 634 |     } else { | 
 | 635 |       ALOGE("Config update size failed"); | 
 | 636 |       mSignalledError = true; | 
 | 637 |       work->result = C2_CORRUPTED; | 
 | 638 |       work->workletsProcessed = 1u; | 
 | 639 |       return false; | 
 | 640 |     } | 
 | 641 |   } | 
 | 642 |  | 
 | 643 |   // TODO(vigneshv): Add support for monochrome videos since AV1 supports it. | 
 | 644 |   CHECK(buffer->image_format == libgav1::kImageFormatYuv420); | 
 | 645 |  | 
 | 646 |   std::shared_ptr<C2GraphicBlock> block; | 
 | 647 |   uint32_t format = HAL_PIXEL_FORMAT_YV12; | 
 | 648 |   if (buffer->bitdepth == 10) { | 
 | 649 |     IntfImpl::Lock lock = mIntf->lock(); | 
 | 650 |     std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = | 
 | 651 |         mIntf->getDefaultColorAspects_l(); | 
 | 652 |  | 
 | 653 |     if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 && | 
 | 654 |         defaultColorAspects->matrix == C2Color::MATRIX_BT2020 && | 
 | 655 |         defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) { | 
 | 656 |       format = HAL_PIXEL_FORMAT_RGBA_1010102; | 
 | 657 |     } | 
 | 658 |   } | 
 | 659 |   C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}; | 
 | 660 |  | 
 | 661 |   c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, | 
 | 662 |                                             usage, &block); | 
 | 663 |  | 
 | 664 |   if (err != C2_OK) { | 
 | 665 |     ALOGE("fetchGraphicBlock for Output failed with status %d", err); | 
 | 666 |     work->result = err; | 
 | 667 |     return false; | 
 | 668 |   } | 
 | 669 |  | 
 | 670 |   C2GraphicView wView = block->map().get(); | 
 | 671 |  | 
 | 672 |   if (wView.error()) { | 
 | 673 |     ALOGE("graphic view map failed %d", wView.error()); | 
 | 674 |     work->result = C2_CORRUPTED; | 
 | 675 |     return false; | 
 | 676 |   } | 
 | 677 |  | 
 | 678 |   ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d", block->width(), | 
 | 679 |         block->height(), mWidth, mHeight, (int)buffer->user_private_data); | 
 | 680 |  | 
 | 681 |   uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]); | 
 | 682 |   size_t srcYStride = buffer->stride[0]; | 
 | 683 |   size_t srcUStride = buffer->stride[1]; | 
 | 684 |   size_t srcVStride = buffer->stride[2]; | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 685 |   C2PlanarLayout layout = wView.layout(); | 
 | 686 |   size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc; | 
 | 687 |   size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc; | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 688 |  | 
 | 689 |   if (buffer->bitdepth == 10) { | 
 | 690 |     const uint16_t *srcY = (const uint16_t *)buffer->plane[0]; | 
 | 691 |     const uint16_t *srcU = (const uint16_t *)buffer->plane[1]; | 
 | 692 |     const uint16_t *srcV = (const uint16_t *)buffer->plane[2]; | 
 | 693 |  | 
 | 694 |     if (format == HAL_PIXEL_FORMAT_RGBA_1010102) { | 
 | 695 |       convertYUV420Planar16ToY410( | 
 | 696 |           (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2, | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 697 |           srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight); | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 698 |     } else { | 
 | 699 |       convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2, | 
 | 700 |                                           srcUStride / 2, srcVStride / 2, | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 701 |                                           dstYStride, dstUVStride, mWidth, mHeight); | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 702 |     } | 
 | 703 |   } else { | 
 | 704 |     const uint8_t *srcY = (const uint8_t *)buffer->plane[0]; | 
 | 705 |     const uint8_t *srcU = (const uint8_t *)buffer->plane[1]; | 
 | 706 |     const uint8_t *srcV = (const uint8_t *)buffer->plane[2]; | 
| James Zern | b36ae37 | 2020-04-14 16:51:56 -0700 | [diff] [blame^] | 707 |     copyOutputBufferToYuvPlanarFrame(dst, srcY, srcU, srcV, srcYStride, srcUStride, | 
 | 708 |                                      srcVStride, dstYStride, dstUVStride, | 
 | 709 |                                      mWidth, mHeight); | 
| Vignesh Venkatasubramanian | 0f3e742 | 2019-06-17 16:21:36 -0700 | [diff] [blame] | 710 |   } | 
 | 711 |   finishWork(buffer->user_private_data, work, std::move(block)); | 
 | 712 |   block = nullptr; | 
 | 713 |   return true; | 
 | 714 | } | 
 | 715 |  | 
 | 716 | c2_status_t C2SoftGav1Dec::drainInternal( | 
 | 717 |     uint32_t drainMode, const std::shared_ptr<C2BlockPool> &pool, | 
 | 718 |     const std::unique_ptr<C2Work> &work) { | 
 | 719 |   if (drainMode == NO_DRAIN) { | 
 | 720 |     ALOGW("drain with NO_DRAIN: no-op"); | 
 | 721 |     return C2_OK; | 
 | 722 |   } | 
 | 723 |   if (drainMode == DRAIN_CHAIN) { | 
 | 724 |     ALOGW("DRAIN_CHAIN not supported"); | 
 | 725 |     return C2_OMITTED; | 
 | 726 |   } | 
 | 727 |  | 
 | 728 |   Libgav1StatusCode status = | 
 | 729 |       mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0, | 
 | 730 |                               /*user_private_data=*/0); | 
 | 731 |   if (status != kLibgav1StatusOk) { | 
 | 732 |     ALOGE("Failed to flush av1 decoder. status: %d.", status); | 
 | 733 |     return C2_CORRUPTED; | 
 | 734 |   } | 
 | 735 |  | 
 | 736 |   while (outputBuffer(pool, work)) { | 
 | 737 |   } | 
 | 738 |  | 
 | 739 |   if (drainMode == DRAIN_COMPONENT_WITH_EOS && work && | 
 | 740 |       work->workletsProcessed == 0u) { | 
 | 741 |     fillEmptyWork(work); | 
 | 742 |   } | 
 | 743 |  | 
 | 744 |   return C2_OK; | 
 | 745 | } | 
 | 746 |  | 
 | 747 | c2_status_t C2SoftGav1Dec::drain(uint32_t drainMode, | 
 | 748 |                                  const std::shared_ptr<C2BlockPool> &pool) { | 
 | 749 |   return drainInternal(drainMode, pool, nullptr); | 
 | 750 | } | 
 | 751 |  | 
| Vignesh Venkatasubramanian | b6d383d | 2019-06-10 15:11:58 -0700 | [diff] [blame] | 752 | class C2SoftGav1Factory : public C2ComponentFactory { | 
 | 753 |  public: | 
 | 754 |   C2SoftGav1Factory() | 
 | 755 |       : mHelper(std::static_pointer_cast<C2ReflectorHelper>( | 
 | 756 |             GetCodec2PlatformComponentStore()->getParamReflector())) {} | 
 | 757 |  | 
 | 758 |   virtual c2_status_t createComponent( | 
 | 759 |       c2_node_id_t id, std::shared_ptr<C2Component> *const component, | 
 | 760 |       std::function<void(C2Component *)> deleter) override { | 
 | 761 |     *component = std::shared_ptr<C2Component>( | 
 | 762 |         new C2SoftGav1Dec(COMPONENT_NAME, id, | 
 | 763 |                           std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)), | 
 | 764 |         deleter); | 
 | 765 |     return C2_OK; | 
 | 766 |   } | 
 | 767 |  | 
 | 768 |   virtual c2_status_t createInterface( | 
 | 769 |       c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface, | 
 | 770 |       std::function<void(C2ComponentInterface *)> deleter) override { | 
 | 771 |     *interface = std::shared_ptr<C2ComponentInterface>( | 
 | 772 |         new SimpleInterface<C2SoftGav1Dec::IntfImpl>( | 
 | 773 |             COMPONENT_NAME, id, | 
 | 774 |             std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)), | 
 | 775 |         deleter); | 
 | 776 |     return C2_OK; | 
 | 777 |   } | 
 | 778 |  | 
 | 779 |   virtual ~C2SoftGav1Factory() override = default; | 
 | 780 |  | 
 | 781 |  private: | 
 | 782 |   std::shared_ptr<C2ReflectorHelper> mHelper; | 
 | 783 | }; | 
 | 784 |  | 
 | 785 | }  // namespace android | 
 | 786 |  | 
 | 787 | extern "C" ::C2ComponentFactory *CreateCodec2Factory() { | 
 | 788 |   ALOGV("in %s", __func__); | 
 | 789 |   return new ::android::C2SoftGav1Factory(); | 
 | 790 | } | 
 | 791 |  | 
 | 792 | extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) { | 
 | 793 |   ALOGV("in %s", __func__); | 
 | 794 |   delete factory; | 
 | 795 | } |