• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 "C2GoldfishHevcDec"
19 #include <inttypes.h>
20 #include <log/log.h>
21 #include <media/stagefright/foundation/AUtils.h>
22 #include <media/stagefright/foundation/MediaDefs.h>
23 
24 #include <C2AllocatorGralloc.h>
25 #include <C2PlatformSupport.h>
26 //#include <android/hardware/graphics/common/1.0/types.h>
27 
28 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
29 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
30 #include <hidl/LegacySupport.h>
31 
32 #include <media/stagefright/foundation/MediaDefs.h>
33 
34 #include <C2Debug.h>
35 #include <C2PlatformSupport.h>
36 #include <Codec2Mapper.h>
37 #include <SimpleC2Interface.h>
38 #include <goldfish_codec2/store/GoldfishComponentStore.h>
39 #include <gralloc_cb_bp.h>
40 
41 #include <color_buffer_utils.h>
42 
43 #include "C2GoldfishHevcDec.h"
44 
45 #define DEBUG 0
46 #if DEBUG
47 #define DDD(...) ALOGD(__VA_ARGS__)
48 #else
49 #define DDD(...) ((void)0)
50 #endif
51 
52 using ::android::hardware::graphics::common::V1_0::BufferUsage;
53 using ::android::hardware::graphics::common::V1_2::PixelFormat;
54 
55 namespace android {
56 
57 namespace {
58 constexpr size_t kMinInputBufferSize = 6 * 1024 * 1024;
59 constexpr char COMPONENT_NAME[] = "c2.goldfish.hevc.decoder";
60 constexpr uint32_t kDefaultOutputDelay = 8;
61 constexpr uint32_t kMaxOutputDelay = 16;
62 } // namespace
63 
64 class C2GoldfishHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
65   public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)66     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
67         : SimpleInterface<void>::BaseParams(
68               helper, COMPONENT_NAME, C2Component::KIND_DECODER,
69               C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_HEVC) {
70         noPrivateBuffers(); // TODO: account for our buffers here
71         noInputReferences();
72         noOutputReferences();
73         noInputLatency();
74         noTimeStretch();
75 
76         // TODO: Proper support for reorder depth.
77         addParameter(
78             DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
79                 .withDefault(
80                     new C2PortActualDelayTuning::output(kDefaultOutputDelay))
81                 .withFields({C2F(mActualOutputDelay, value)
82                                  .inRange(0, kMaxOutputDelay)})
83                 .withSetter(
84                     Setter<
85                         decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
86                 .build());
87 
88         // TODO: output latency and reordering
89 
90         addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
91                          .withConstValue(new C2ComponentAttributesSetting(
92                              C2Component::ATTRIB_IS_TEMPORAL))
93                          .build());
94 
95         // coded and output picture size is the same for this codec
96         addParameter(
97             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
98                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
99                 .withFields({
100                     C2F(mSize, width).inRange(2, 4096, 2),
101                     C2F(mSize, height).inRange(2, 4096, 2),
102                 })
103                 .withSetter(SizeSetter)
104                 .build());
105 
106         addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
107                          .withDefault(new C2StreamMaxPictureSizeTuning::output(
108                              0u, 320, 240))
109                          .withFields({
110                              C2F(mSize, width).inRange(2, 4096, 2),
111                              C2F(mSize, height).inRange(2, 4096, 2),
112                          })
113                          .withSetter(MaxPictureSizeSetter, mSize)
114                          .build());
115 
116         addParameter(
117             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
118                 .withDefault(new C2StreamProfileLevelInfo::input(
119                     0u, C2Config::PROFILE_HEVC_MAIN, C2Config::LEVEL_HEVC_MAIN_5_1))
120                 .withFields({
121                     C2F(mProfileLevel, profile).oneOf({
122                             C2Config::PROFILE_HEVC_MAIN,
123                             C2Config::PROFILE_HEVC_MAIN_STILL}),
124                     C2F(mProfileLevel, level).oneOf({
125                             C2Config::LEVEL_HEVC_MAIN_1,
126                             C2Config::LEVEL_HEVC_MAIN_2, C2Config::LEVEL_HEVC_MAIN_2_1,
127                             C2Config::LEVEL_HEVC_MAIN_3, C2Config::LEVEL_HEVC_MAIN_3_1,
128                             C2Config::LEVEL_HEVC_MAIN_4, C2Config::LEVEL_HEVC_MAIN_4_1,
129                             C2Config::LEVEL_HEVC_MAIN_5, C2Config::LEVEL_HEVC_MAIN_5_1,
130                             C2Config::LEVEL_HEVC_MAIN_5_2, C2Config::LEVEL_HEVC_HIGH_4,
131                             C2Config::LEVEL_HEVC_HIGH_4_1, C2Config::LEVEL_HEVC_HIGH_5,
132                             C2Config::LEVEL_HEVC_HIGH_5_1, C2Config::LEVEL_HEVC_HIGH_5_2
133                     })
134                 })
135                 .withSetter(ProfileLevelSetter, mSize)
136                 .build());
137 
138         addParameter(
139             DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
140                 .withDefault(new C2StreamMaxBufferSizeInfo::input(
141                     0u, kMinInputBufferSize))
142                 .withFields({
143                     C2F(mMaxInputSize, value).any(),
144                 })
145                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
146                 .build());
147 
148         C2ChromaOffsetStruct locations[1] = {
149             C2ChromaOffsetStruct::ITU_YUV_420_0()};
150         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
151             C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
152                                                    C2Color::YUV_420);
153         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
154 
155         defaultColorInfo = C2StreamColorInfo::output::AllocShared(
156             {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
157             C2Color::YUV_420);
158         helper->addStructDescriptors<C2ChromaOffsetStruct>();
159 
160         addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
161                          .withConstValue(defaultColorInfo)
162                          .build());
163 
164         addParameter(
165             DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
166                 .withDefault(new C2StreamColorAspectsTuning::output(
167                     0u, C2Color::RANGE_UNSPECIFIED,
168                     C2Color::PRIMARIES_UNSPECIFIED,
169                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
170                 .withFields({C2F(mDefaultColorAspects, range)
171                                  .inRange(C2Color::RANGE_UNSPECIFIED,
172                                           C2Color::RANGE_OTHER),
173                              C2F(mDefaultColorAspects, primaries)
174                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
175                                           C2Color::PRIMARIES_OTHER),
176                              C2F(mDefaultColorAspects, transfer)
177                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
178                                           C2Color::TRANSFER_OTHER),
179                              C2F(mDefaultColorAspects, matrix)
180                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
181                                           C2Color::MATRIX_OTHER)})
182                 .withSetter(DefaultColorAspectsSetter)
183                 .build());
184 
185         addParameter(
186             DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
187                 .withDefault(new C2StreamColorAspectsInfo::input(
188                     0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
189                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
190                 .withFields({C2F(mCodedColorAspects, range)
191                                  .inRange(C2Color::RANGE_UNSPECIFIED,
192                                           C2Color::RANGE_OTHER),
193                              C2F(mCodedColorAspects, primaries)
194                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
195                                           C2Color::PRIMARIES_OTHER),
196                              C2F(mCodedColorAspects, transfer)
197                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
198                                           C2Color::TRANSFER_OTHER),
199                              C2F(mCodedColorAspects, matrix)
200                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
201                                           C2Color::MATRIX_OTHER)})
202                 .withSetter(CodedColorAspectsSetter)
203                 .build());
204 
205         addParameter(
206             DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
207                 .withDefault(new C2StreamColorAspectsInfo::output(
208                     0u, C2Color::RANGE_UNSPECIFIED,
209                     C2Color::PRIMARIES_UNSPECIFIED,
210                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
211                 .withFields({C2F(mColorAspects, range)
212                                  .inRange(C2Color::RANGE_UNSPECIFIED,
213                                           C2Color::RANGE_OTHER),
214                              C2F(mColorAspects, primaries)
215                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
216                                           C2Color::PRIMARIES_OTHER),
217                              C2F(mColorAspects, transfer)
218                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
219                                           C2Color::TRANSFER_OTHER),
220                              C2F(mColorAspects, matrix)
221                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
222                                           C2Color::MATRIX_OTHER)})
223                 .withSetter(ColorAspectsSetter, mDefaultColorAspects,
224                             mCodedColorAspects)
225                 .build());
226 
227         // TODO: support more formats?
228         addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
229                          .withConstValue(new C2StreamPixelFormatInfo::output(
230                              0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
231                          .build());
232     }
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)233     static C2R SizeSetter(bool mayBlock,
234                           const C2P<C2StreamPictureSizeInfo::output> &oldMe,
235                           C2P<C2StreamPictureSizeInfo::output> &me) {
236         (void)mayBlock;
237         DDD("calling sizesetter now %d", oldMe.v.height);
238         DDD("new calling sizesetter now %d", me.v.height);
239 
240         C2R res = C2R::Ok();
241         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
242             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
243             me.set().width = oldMe.v.width;
244         }
245         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
246             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
247             me.set().height = oldMe.v.height;
248         }
249         return res;
250     }
251 
252     static C2R
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)253     MaxPictureSizeSetter(bool mayBlock,
254                          C2P<C2StreamMaxPictureSizeTuning::output> &me,
255                          const C2P<C2StreamPictureSizeInfo::output> &size) {
256         (void)mayBlock;
257         // TODO: get max width/height from the size's field helpers vs.
258         // hardcoding
259         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
260         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
261         return C2R::Ok();
262     }
263 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)264     static C2R MaxInputSizeSetter(
265         bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
266         const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
267         (void)mayBlock;
268         // assume compression ratio of 2
269         me.set().value = c2_max((((maxSize.v.width + 63) / 64) *
270                                  ((maxSize.v.height + 64) / 64) * 3072),
271                                 kMinInputBufferSize);
272         return C2R::Ok();
273     }
274 
275     static C2R
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)276     ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
277                        const C2P<C2StreamPictureSizeInfo::output> &size) {
278         (void)mayBlock;
279         (void)size;
280         (void)me; // TODO: validate
281         return C2R::Ok();
282     }
283 
284     static C2R
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)285     DefaultColorAspectsSetter(bool mayBlock,
286                               C2P<C2StreamColorAspectsTuning::output> &me) {
287         (void)mayBlock;
288         if (me.v.range > C2Color::RANGE_OTHER) {
289             me.set().range = C2Color::RANGE_OTHER;
290         }
291         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
292             me.set().primaries = C2Color::PRIMARIES_OTHER;
293         }
294         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
295             me.set().transfer = C2Color::TRANSFER_OTHER;
296         }
297         if (me.v.matrix > C2Color::MATRIX_OTHER) {
298             me.set().matrix = C2Color::MATRIX_OTHER;
299         }
300         return C2R::Ok();
301     }
302 
303     static C2R
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)304     CodedColorAspectsSetter(bool mayBlock,
305                             C2P<C2StreamColorAspectsInfo::input> &me) {
306         (void)mayBlock;
307         if (me.v.range > C2Color::RANGE_OTHER) {
308             me.set().range = C2Color::RANGE_OTHER;
309         }
310         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
311             me.set().primaries = C2Color::PRIMARIES_OTHER;
312         }
313         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
314             me.set().transfer = C2Color::TRANSFER_OTHER;
315         }
316         if (me.v.matrix > C2Color::MATRIX_OTHER) {
317             me.set().matrix = C2Color::MATRIX_OTHER;
318         }
319         return C2R::Ok();
320     }
321 
322     static C2R
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)323     ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
324                        const C2P<C2StreamColorAspectsTuning::output> &def,
325                        const C2P<C2StreamColorAspectsInfo::input> &coded) {
326         (void)mayBlock;
327         // take default values for all unspecified fields, and coded values for
328         // specified ones
329         me.set().range =
330             coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
331         me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
332                                  ? def.v.primaries
333                                  : coded.v.primaries;
334         me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
335                                 ? def.v.transfer
336                                 : coded.v.transfer;
337         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix
338                                                                : coded.v.matrix;
339         return C2R::Ok();
340     }
341 
getColorAspects_l()342     std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
343         return mColorAspects;
344     }
345 
width() const346     int width() const { return mSize->width; }
347 
height() const348     int height() const { return mSize->height; }
349 
primaries() const350     int primaries() const { return mColorAspects->primaries; }
351 
range() const352     int range() const { return mColorAspects->range; }
353 
transfer() const354     int transfer() const { return mColorAspects->transfer; }
355 
356 
357   private:
358     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
359     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
360     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
361     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
362     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
363     std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
364     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
365     std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
366     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
367 };
368 
ivd_aligned_malloc(void * ctxt,uint32_t alignment,uint32_t size)369 static void *ivd_aligned_malloc(void *ctxt, uint32_t alignment, uint32_t size) {
370     (void)ctxt;
371     return memalign(alignment, size);
372 }
373 
ivd_aligned_free(void * ctxt,void * mem)374 static void ivd_aligned_free(void *ctxt, void *mem) {
375     (void)ctxt;
376     free(mem);
377 }
378 
C2GoldfishHevcDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)379 C2GoldfishHevcDec::C2GoldfishHevcDec(const char *name, c2_node_id_t id,
380                                    const std::shared_ptr<IntfImpl> &intfImpl)
381     : SimpleC2Component(
382           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
383       mIntf(intfImpl), mOutBufferFlush(nullptr), mWidth(1920), mHeight(1080),
384       mHeaderDecoded(false), mOutIndex(0u) {
385     mWidth = mIntf->width();
386     mHeight = mIntf->height();
387     DDD("creating hevc decoder now w %d h %d", mWidth, mHeight);
388 }
389 
~C2GoldfishHevcDec()390 C2GoldfishHevcDec::~C2GoldfishHevcDec() { onRelease(); }
391 
onInit()392 c2_status_t C2GoldfishHevcDec::onInit() {
393     status_t err = initDecoder();
394     return err == OK ? C2_OK : C2_CORRUPTED;
395 }
396 
onStop()397 c2_status_t C2GoldfishHevcDec::onStop() {
398     if (OK != resetDecoder())
399         return C2_CORRUPTED;
400     resetPlugin();
401     return C2_OK;
402 }
403 
onReset()404 void C2GoldfishHevcDec::onReset() { (void)onStop(); }
405 
onRelease()406 void C2GoldfishHevcDec::onRelease() {
407     deleteContext();
408     if (mOutBlock) {
409         mOutBlock.reset();
410     }
411 }
412 
decodeHeaderAfterFlush()413 void C2GoldfishHevcDec::decodeHeaderAfterFlush() {
414         DDD("calling %s", __func__);
415     if (mContext && !mCsd0.empty()) {
416         mContext->decodeFrame(&(mCsd0[0]), mCsd0.size(), 0);
417         DDD("resending csd0");
418         DDD("calling %s success", __func__);
419     }
420 }
421 
onFlush_sm()422 c2_status_t C2GoldfishHevcDec::onFlush_sm() {
423     if (OK != setFlushMode())
424         return C2_CORRUPTED;
425 
426     if (!mContext) {
427         // just ignore if context is not even created
428         return C2_OK;
429     }
430 
431     uint32_t bufferSize = mStride * mHeight * 3 / 2;
432     mOutBufferFlush = (uint8_t *)ivd_aligned_malloc(nullptr, 128, bufferSize);
433     if (!mOutBufferFlush) {
434         ALOGE("could not allocate tmp output buffer (for flush) of size %u ",
435               bufferSize);
436         return C2_NO_MEMORY;
437     }
438 
439     while (true) {
440         mPts = 0;
441         setDecodeArgs(nullptr, nullptr, 0, 0, 0);
442         mImg = mContext->getImage();
443         if (mImg.data == nullptr) {
444             resetPlugin();
445             break;
446         }
447     }
448 
449     if (mOutBufferFlush) {
450         ivd_aligned_free(nullptr, mOutBufferFlush);
451         mOutBufferFlush = nullptr;
452     }
453 
454     deleteContext();
455     return C2_OK;
456 }
457 
sendMetadata()458 void C2GoldfishHevcDec::sendMetadata() {
459     // compare and send if changed
460     MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
461     currentMetaData.primaries = mIntf->primaries();
462     currentMetaData.range = mIntf->range();
463     currentMetaData.transfer = mIntf->transfer();
464 
465     DDD("metadata primaries %d range %d transfer %d",
466             (int)(currentMetaData.primaries),
467             (int)(currentMetaData.range),
468             (int)(currentMetaData.transfer)
469        );
470 
471     if (mSentMetadata.primaries == currentMetaData.primaries &&
472         mSentMetadata.range == currentMetaData.range &&
473         mSentMetadata.transfer == currentMetaData.transfer) {
474         DDD("metadata is the same, no need to update");
475         return;
476     }
477     std::swap(mSentMetadata, currentMetaData);
478 
479     mContext->sendMetadata(&(mSentMetadata));
480 }
481 
createDecoder()482 status_t C2GoldfishHevcDec::createDecoder() {
483 
484     DDD("creating hevc context now w %d h %d", mWidth, mHeight);
485     if (mEnableAndroidNativeBuffers) {
486         mContext.reset(new MediaHevcDecoder(RenderMode::RENDER_BY_HOST_GPU));
487     } else {
488         mContext.reset(new MediaHevcDecoder(RenderMode::RENDER_BY_GUEST_CPU));
489     }
490     mContext->initHevcContext(mWidth, mHeight, mWidth, mHeight,
491                               MediaHevcDecoder::PixelFormat::YUV420P);
492 
493     return OK;
494 }
495 
setParams(size_t stride)496 status_t C2GoldfishHevcDec::setParams(size_t stride) {
497     (void)stride;
498     return OK;
499 }
500 
initDecoder()501 status_t C2GoldfishHevcDec::initDecoder() {
502     //    if (OK != createDecoder()) return UNKNOWN_ERROR;
503     mStride = ALIGN2(mWidth);
504     mSignalledError = false;
505     resetPlugin();
506 
507     return OK;
508 }
509 
setDecodeArgs(C2ReadView * inBuffer,C2GraphicView * outBuffer,size_t inOffset,size_t inSize,uint32_t tsMarker)510 bool C2GoldfishHevcDec::setDecodeArgs(C2ReadView *inBuffer,
511                                      C2GraphicView *outBuffer, size_t inOffset,
512                                      size_t inSize, uint32_t tsMarker) {
513     uint32_t displayStride = mStride;
514     (void)inBuffer;
515     (void)inOffset;
516     (void)inSize;
517     (void)tsMarker;
518     if (outBuffer) {
519         C2PlanarLayout layout;
520         layout = outBuffer->layout();
521         displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
522     }
523 
524     if (inBuffer) {
525         //= tsMarker;
526         mInPBuffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
527         mInPBufferSize = inSize;
528         mInTsMarker = tsMarker;
529         insertPts(tsMarker, mPts);
530     }
531 
532     // uint32_t displayHeight = mHeight;
533     // size_t lumaSize = displayStride * displayHeight;
534     // size_t chromaSize = lumaSize >> 2;
535 
536     if (mStride != displayStride) {
537         mStride = displayStride;
538         if (OK != setParams(mStride))
539             return false;
540     }
541 
542     return true;
543 }
544 
setFlushMode()545 status_t C2GoldfishHevcDec::setFlushMode() {
546     if (mContext) {
547         mContext->flush();
548     }
549     mHeaderDecoded = false;
550     return OK;
551 }
552 
resetDecoder()553 status_t C2GoldfishHevcDec::resetDecoder() {
554     mStride = 0;
555     mSignalledError = false;
556     mHeaderDecoded = false;
557     deleteContext();
558 
559     return OK;
560 }
561 
resetPlugin()562 void C2GoldfishHevcDec::resetPlugin() {
563     mSignalledOutputEos = false;
564     gettimeofday(&mTimeStart, nullptr);
565     gettimeofday(&mTimeEnd, nullptr);
566 }
567 
deleteContext()568 void C2GoldfishHevcDec::deleteContext() {
569     if (mContext) {
570         mContext->destroyHevcContext();
571         mContext.reset(nullptr);
572         mPts2Index.clear();
573         mOldPts2Index.clear();
574         mIndex2Pts.clear();
575     }
576 }
577 
fillEmptyWork(const std::unique_ptr<C2Work> & work)578 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
579     uint32_t flags = 0;
580     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
581         flags |= C2FrameData::FLAG_END_OF_STREAM;
582         DDD("signalling eos");
583     }
584     DDD("fill empty work");
585     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
586     work->worklets.front()->output.buffers.clear();
587     work->worklets.front()->output.ordinal = work->input.ordinal;
588     work->workletsProcessed = 1u;
589 }
590 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)591 void C2GoldfishHevcDec::finishWork(uint64_t index,
592                                   const std::unique_ptr<C2Work> &work) {
593     std::shared_ptr<C2Buffer> buffer =
594         createGraphicBuffer(std::move(mOutBlock), C2Rect(mWidth, mHeight));
595     mOutBlock = nullptr;
596     {
597         IntfImpl::Lock lock = mIntf->lock();
598         buffer->setInfo(mIntf->getColorAspects_l());
599     }
600 
601     class FillWork {
602       public:
603         FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
604                  const std::shared_ptr<C2Buffer> &buffer)
605             : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
606         ~FillWork() = default;
607 
608         void operator()(const std::unique_ptr<C2Work> &work) {
609             work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
610             work->worklets.front()->output.buffers.clear();
611             work->worklets.front()->output.ordinal = mOrdinal;
612             work->workletsProcessed = 1u;
613             work->result = C2_OK;
614             if (mBuffer) {
615                 work->worklets.front()->output.buffers.push_back(mBuffer);
616             }
617             DDD("timestamp = %lld, index = %lld, w/%s buffer",
618                 mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
619                 mBuffer ? "" : "o");
620         }
621 
622       private:
623         const uint32_t mFlags;
624         const C2WorkOrdinalStruct mOrdinal;
625         const std::shared_ptr<C2Buffer> mBuffer;
626     };
627 
628     auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
629         work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
630         work->worklets.front()->output.buffers.clear();
631         work->worklets.front()->output.buffers.push_back(buffer);
632         work->worklets.front()->output.ordinal = work->input.ordinal;
633         work->workletsProcessed = 1u;
634     };
635     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
636         bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
637         // TODO: Check if cloneAndSend can be avoided by tracking number of
638         // frames remaining
639         if (eos) {
640             if (buffer) {
641                 mOutIndex = index;
642                 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
643                 DDD("%s %d: cloneAndSend ", __func__, __LINE__);
644                 cloneAndSend(
645                     mOutIndex, work,
646                     FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
647                 buffer.reset();
648             }
649         } else {
650             DDD("%s %d: fill", __func__, __LINE__);
651             fillWork(work);
652         }
653     } else {
654         DDD("%s %d: finish", __func__, __LINE__);
655         finish(index, fillWork);
656     }
657 }
658 
659 c2_status_t
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)660 C2GoldfishHevcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
661     if (mOutBlock && (mOutBlock->width() != ALIGN2(mWidth) ||
662                       mOutBlock->height() != mHeight)) {
663         mOutBlock.reset();
664     }
665     if (!mOutBlock) {
666         uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
667         C2MemoryUsage usage = {C2MemoryUsage::CPU_READ,
668                                C2MemoryUsage::CPU_WRITE};
669         usage.expected = (uint64_t)(BufferUsage::VIDEO_DECODER);
670         // C2MemoryUsage usage = {(unsigned
671         // int)(BufferUsage::GPU_DATA_BUFFER)};// { C2MemoryUsage::CPU_READ,
672         // C2MemoryUsage::CPU_WRITE };
673         c2_status_t err = pool->fetchGraphicBlock(ALIGN2(mWidth), mHeight,
674                                                   format, usage, &mOutBlock);
675         if (err != C2_OK) {
676             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
677             return err;
678         }
679         if (mEnableAndroidNativeBuffers) {
680             auto c2Handle = mOutBlock->handle();
681             native_handle_t *grallocHandle =
682                 UnwrapNativeCodec2GrallocHandle(c2Handle);
683             mHostColorBufferId = getColorBufferHandle(grallocHandle);
684             DDD("found handle %d", mHostColorBufferId);
685         }
686         DDD("provided (%dx%d) required (%dx%d)", mOutBlock->width(),
687             mOutBlock->height(), ALIGN2(mWidth), mHeight);
688     }
689 
690     return C2_OK;
691 }
692 
checkMode(const std::shared_ptr<C2BlockPool> & pool)693 void C2GoldfishHevcDec::checkMode(const std::shared_ptr<C2BlockPool> &pool) {
694     mWidth = mIntf->width();
695     mHeight = mIntf->height();
696     const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
697     DDD("buffer id %d", (int)(pool->getAllocatorId()));
698     if (isGraphic) {
699         DDD("decoding to host color buffer");
700         mEnableAndroidNativeBuffers = true;
701     } else {
702         DDD("decoding to guest byte buffer");
703         mEnableAndroidNativeBuffers = false;
704     }
705 }
706 
getVuiParams(hevc_image_t & img)707 void C2GoldfishHevcDec::getVuiParams(hevc_image_t &img) {
708 
709     VuiColorAspects vuiColorAspects;
710     vuiColorAspects.primaries = img.color_primaries;
711     vuiColorAspects.transfer = img.color_trc;
712     vuiColorAspects.coeffs = img.colorspace;
713     vuiColorAspects.fullRange = img.color_range == 2 ? true : false;
714 
715     // convert vui aspects to C2 values if changed
716     if (!(vuiColorAspects == mBitstreamColorAspects)) {
717         mBitstreamColorAspects = vuiColorAspects;
718         ColorAspects sfAspects;
719         C2StreamColorAspectsInfo::input codedAspects = {0u};
720         ColorUtils::convertIsoColorAspectsToCodecAspects(
721             vuiColorAspects.primaries, vuiColorAspects.transfer,
722             vuiColorAspects.coeffs, vuiColorAspects.fullRange, sfAspects);
723         if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
724             codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
725         }
726         if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
727             codedAspects.range = C2Color::RANGE_UNSPECIFIED;
728         }
729         if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
730             codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
731         }
732         if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
733             codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
734         }
735         std::vector<std::unique_ptr<C2SettingResult>> failures;
736         (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
737     }
738 }
739 
copyImageData(hevc_image_t & img)740 void C2GoldfishHevcDec::copyImageData(hevc_image_t &img) {
741     getVuiParams(img);
742     if (mEnableAndroidNativeBuffers)
743         return;
744 
745     auto writeView = mOutBlock->map().get();
746     if (writeView.error()) {
747         ALOGE("graphic view map failed %d", writeView.error());
748         return;
749     }
750     size_t dstYStride = writeView.layout().planes[C2PlanarLayout::PLANE_Y].rowInc;
751     size_t dstUVStride = writeView.layout().planes[C2PlanarLayout::PLANE_U].rowInc;
752 
753     uint8_t *pYBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_Y]);
754     uint8_t *pUBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_U]);
755     uint8_t *pVBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_V]);
756 
757     for (int i = 0; i < mHeight; ++i) {
758         memcpy(pYBuffer + i * dstYStride, img.data + i * mWidth, mWidth);
759     }
760     for (int i = 0; i < mHeight / 2; ++i) {
761         memcpy(pUBuffer + i * dstUVStride,
762                img.data + mWidth * mHeight + i * mWidth / 2, mWidth / 2);
763     }
764     for (int i = 0; i < mHeight / 2; ++i) {
765         memcpy(pVBuffer + i * dstUVStride,
766                img.data + mWidth * mHeight * 5 / 4 + i * mWidth / 2,
767                mWidth / 2);
768     }
769 }
770 
getWorkIndex(uint64_t pts)771 uint64_t C2GoldfishHevcDec::getWorkIndex(uint64_t pts) {
772     if (!mOldPts2Index.empty()) {
773         auto iter = mOldPts2Index.find(pts);
774         if (iter != mOldPts2Index.end()) {
775             auto index = iter->second;
776             DDD("found index %d for pts %" PRIu64, (int)index, pts);
777             return index;
778         }
779     }
780     auto iter = mPts2Index.find(pts);
781     if (iter != mPts2Index.end()) {
782         auto index = iter->second;
783         DDD("found index %d for pts %" PRIu64, (int)index, pts);
784         return index;
785     }
786     DDD("not found index for pts %" PRIu64, pts);
787     return 0;
788 }
789 
insertPts(uint32_t work_index,uint64_t pts)790 void C2GoldfishHevcDec::insertPts(uint32_t work_index, uint64_t pts) {
791     auto iter = mPts2Index.find(pts);
792     if (iter != mPts2Index.end()) {
793         // we have a collision here:
794         // apparently, older session is not done yet,
795         // lets save them
796         DDD("inserted to old pts %" PRIu64 " with index %d", pts, (int)iter->second);
797         mOldPts2Index[iter->first] = iter->second;
798     }
799     DDD("inserted pts %" PRIu64 " with index %d", pts, (int)work_index);
800     mIndex2Pts[work_index] = pts;
801     mPts2Index[pts] = work_index;
802 }
803 
removePts(uint64_t pts)804 void C2GoldfishHevcDec::removePts(uint64_t pts) {
805     bool found = false;
806     uint64_t index = 0;
807     // note: check old pts first to see
808     // if we have some left over, check them
809     if (!mOldPts2Index.empty()) {
810         auto iter = mOldPts2Index.find(pts);
811         if (iter != mOldPts2Index.end()) {
812             mOldPts2Index.erase(iter);
813             index = iter->second;
814             found = true;
815         }
816     } else {
817         auto iter = mPts2Index.find(pts);
818         if (iter != mPts2Index.end()) {
819             mPts2Index.erase(iter);
820             index = iter->second;
821             found = true;
822         }
823     }
824 
825     if (!found) return;
826 
827     auto iter2 = mIndex2Pts.find(index);
828     if (iter2 == mIndex2Pts.end()) return;
829     mIndex2Pts.erase(iter2);
830 }
831 
832 // TODO: can overall error checking be improved?
833 // TODO: allow configuration of color format and usage for graphic buffers
834 // instead
835 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
836 // TODO: pass coloraspects information to surface
837 // TODO: test support for dynamic change in resolution
838 // TODO: verify if the decoder sent back all frames
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)839 void C2GoldfishHevcDec::process(const std::unique_ptr<C2Work> &work,
840                                const std::shared_ptr<C2BlockPool> &pool) {
841     // Initialize output work
842     work->result = C2_OK;
843     work->workletsProcessed = 0u;
844     work->worklets.front()->output.flags = work->input.flags;
845     if (mSignalledError || mSignalledOutputEos) {
846         work->result = C2_BAD_VALUE;
847         return;
848     }
849 
850     DDD("process work");
851     if (!mContext) {
852         DDD("creating decoder context to host in process work");
853         checkMode(pool);
854         createDecoder();
855         decodeHeaderAfterFlush();
856     }
857 
858     size_t inOffset = 0u;
859     size_t inSize = 0u;
860     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
861     mPts = work->input.ordinal.timestamp.peeku();
862     C2ReadView rView = mDummyReadView;
863     if (!work->input.buffers.empty()) {
864         rView =
865             work->input.buffers[0]->data().linearBlocks().front().map().get();
866         inSize = rView.capacity();
867         if (inSize && rView.error()) {
868             ALOGE("read view map failed %d", rView.error());
869             work->result = rView.error();
870             return;
871         }
872     }
873     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
874     bool hasPicture = (inSize > 0);
875 
876     DDD("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
877         (int)work->input.ordinal.timestamp.peeku(),
878         (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
879     size_t inPos = 0;
880     while (inPos < inSize) {
881         if (C2_OK != ensureDecoderState(pool)) {
882             mSignalledError = true;
883             work->workletsProcessed = 1u;
884             work->result = C2_CORRUPTED;
885             return;
886         }
887 
888         {
889             // C2GraphicView wView;// = mOutBlock->map().get();
890             // if (wView.error()) {
891             //    ALOGE("graphic view map failed %d", wView.error());
892             //    work->result = wView.error();
893             //    return;
894             //}
895             if (!setDecodeArgs(&rView, nullptr, inOffset + inPos,
896                                inSize - inPos, workIndex)) {
897                 mSignalledError = true;
898                 work->workletsProcessed = 1u;
899                 work->result = C2_CORRUPTED;
900                 return;
901             }
902 
903             DDD("flag is %x", work->input.flags);
904             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
905                 hasPicture = false;
906                 if (mCsd0.empty()) {
907                     mCsd0.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
908                     DDD("assign to csd0 with %d bytpes", mInPBufferSize);
909                 }
910                 // this is not really a valid pts from config
911                 removePts(mPts);
912             }
913 
914             bool whChanged = false;
915             if (GoldfishHevcHelper::isVpsFrame(mInPBuffer, mInPBufferSize)) {
916                 mHevcHelper.reset(new GoldfishHevcHelper(mWidth, mHeight));
917                 bool headerStatus = true;
918                 whChanged = mHevcHelper->decodeHeader(
919                     mInPBuffer, mInPBufferSize, headerStatus);
920                 if (!headerStatus) {
921                     mSignalledError = true;
922                     work->workletsProcessed = 1u;
923                     work->result = C2_CORRUPTED;
924                     return;
925                 }
926                 if (whChanged) {
927                         DDD("w changed from old %d to new %d\n", mWidth, mHevcHelper->getWidth());
928                         DDD("h changed from old %d to new %d\n", mHeight, mHevcHelper->getHeight());
929                         if (1) {
930                             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
931                             resetDecoder();
932                             resetPlugin();
933                             work->workletsProcessed = 0u;
934                         }
935                         {
936                             mWidth = mHevcHelper->getWidth();
937                             mHeight = mHevcHelper->getHeight();
938                             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
939                             std::vector<std::unique_ptr<C2SettingResult>> failures;
940                             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
941                             if (err == OK) {
942                                 work->worklets.front()->output.configUpdate.push_back(
943                                         C2Param::Copy(size));
944                                 ensureDecoderState(pool);
945                             } else {
946                                 ALOGE("Cannot set width and height");
947                                 mSignalledError = true;
948                                 work->workletsProcessed = 1u;
949                                 work->result = C2_CORRUPTED;
950                                 return;
951                             }
952                         }
953                         if (!mContext) {
954                             DDD("creating decoder context to host in process work");
955                             checkMode(pool);
956                             createDecoder();
957                         }
958                         continue;//return;
959                 } // end of whChanged
960             } // end of isVpsFrame
961 
962             sendMetadata();
963 
964             uint32_t delay;
965             GETTIME(&mTimeStart, nullptr);
966             TIME_DIFF(mTimeEnd, mTimeStart, delay);
967             (void)delay;
968             //(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
969             DDD("decoding");
970             hevc_result_t hevcRes =
971                 mContext->decodeFrame(mInPBuffer, mInPBufferSize, mIndex2Pts[mInTsMarker]);
972             mConsumedBytes = hevcRes.bytesProcessed;
973             DDD("decoding consumed %d", (int)mConsumedBytes);
974 
975             if (mHostColorBufferId > 0) {
976                 mImg = mContext->renderOnHostAndReturnImageMetadata(
977                     mHostColorBufferId);
978             } else {
979                 mImg = mContext->getImage();
980             }
981             uint32_t decodeTime;
982             GETTIME(&mTimeEnd, nullptr);
983             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
984             (void)decodeTime;
985         }
986         if (mImg.data != nullptr) {
987             DDD("got data %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
988             mHeaderDecoded = true;
989             copyImageData(mImg);
990             finishWork(getWorkIndex(mImg.pts), work);
991             removePts(mImg.pts);
992         } else {
993             work->workletsProcessed = 0u;
994         }
995 
996         inPos += mConsumedBytes;
997     }
998     if (eos) {
999         DDD("drain because of eos");
1000         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1001         mSignalledOutputEos = true;
1002     } else if (!hasPicture) {
1003         DDD("no picture, fill empty work");
1004         fillEmptyWork(work);
1005     }
1006 
1007     work->input.buffers.clear();
1008 }
1009 
1010 c2_status_t
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1011 C2GoldfishHevcDec::drainInternal(uint32_t drainMode,
1012                                 const std::shared_ptr<C2BlockPool> &pool,
1013                                 const std::unique_ptr<C2Work> &work) {
1014     if (drainMode == NO_DRAIN) {
1015         ALOGW("drain with NO_DRAIN: no-op");
1016         return C2_OK;
1017     }
1018     if (drainMode == DRAIN_CHAIN) {
1019         ALOGW("DRAIN_CHAIN not supported");
1020         return C2_OMITTED;
1021     }
1022 
1023     if (OK != setFlushMode())
1024         return C2_CORRUPTED;
1025     while (true) {
1026         if (C2_OK != ensureDecoderState(pool)) {
1027             mSignalledError = true;
1028             work->workletsProcessed = 1u;
1029             work->result = C2_CORRUPTED;
1030             return C2_CORRUPTED;
1031         }
1032         /*
1033         C2GraphicView wView = mOutBlock->map().get();
1034         if (wView.error()) {
1035             ALOGE("graphic view map failed %d", wView.error());
1036             return C2_CORRUPTED;
1037         }
1038         if (!setDecodeArgs(nullptr, &wView, 0, 0, 0)) {
1039             mSignalledError = true;
1040             work->workletsProcessed = 1u;
1041             return C2_CORRUPTED;
1042         }
1043         */
1044 
1045         if (mHostColorBufferId > 0) {
1046             mImg = mContext->renderOnHostAndReturnImageMetadata(
1047                 mHostColorBufferId);
1048         } else {
1049             mImg = mContext->getImage();
1050         }
1051 
1052         // TODO: maybe keep rendering to screen
1053         //        mImg = mContext->getImage();
1054         if (mImg.data != nullptr) {
1055             DDD("got data in drain mode %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
1056             copyImageData(mImg);
1057             finishWork(getWorkIndex(mImg.pts), work);
1058             removePts(mImg.pts);
1059         } else {
1060             fillEmptyWork(work);
1061             break;
1062         }
1063     }
1064 
1065     return C2_OK;
1066 }
1067 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1068 c2_status_t C2GoldfishHevcDec::drain(uint32_t drainMode,
1069                                     const std::shared_ptr<C2BlockPool> &pool) {
1070     DDD("drainInternal because of drain");
1071     return drainInternal(drainMode, pool, nullptr);
1072 }
1073 
1074 class C2GoldfishHevcDecFactory : public C2ComponentFactory {
1075   public:
C2GoldfishHevcDecFactory()1076     C2GoldfishHevcDecFactory()
1077         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1078               GoldfishComponentStore::Create()->getParamReflector())) {}
1079 
1080     virtual c2_status_t
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1081     createComponent(c2_node_id_t id,
1082                     std::shared_ptr<C2Component> *const component,
1083                     std::function<void(C2Component *)> deleter) override {
1084         *component = std::shared_ptr<C2Component>(
1085             new C2GoldfishHevcDec(
1086                 COMPONENT_NAME, id,
1087                 std::make_shared<C2GoldfishHevcDec::IntfImpl>(mHelper)),
1088             deleter);
1089         return C2_OK;
1090     }
1091 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1092     virtual c2_status_t createInterface(
1093         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
1094         std::function<void(C2ComponentInterface *)> deleter) override {
1095         *interface = std::shared_ptr<C2ComponentInterface>(
1096             new SimpleInterface<C2GoldfishHevcDec::IntfImpl>(
1097                 COMPONENT_NAME, id,
1098                 std::make_shared<C2GoldfishHevcDec::IntfImpl>(mHelper)),
1099             deleter);
1100         return C2_OK;
1101     }
1102 
1103     virtual ~C2GoldfishHevcDecFactory() override = default;
1104 
1105   private:
1106     std::shared_ptr<C2ReflectorHelper> mHelper;
1107 };
1108 
1109 } // namespace android
1110 
CreateCodec2Factory()1111 extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
1112     DDD("in %s", __func__);
1113     return new ::android::C2GoldfishHevcDecFactory();
1114 }
1115 
DestroyCodec2Factory(::C2ComponentFactory * factory)1116 extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
1117     DDD("in %s", __func__);
1118     delete factory;
1119 }
1120