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         constexpr bool hasPicture = false;
442         setDecodeArgs(nullptr, nullptr, 0, 0, 0, hasPicture);
443         mImg = mContext->getImage();
444         if (mImg.data == nullptr) {
445             resetPlugin();
446             break;
447         }
448     }
449 
450     if (mOutBufferFlush) {
451         ivd_aligned_free(nullptr, mOutBufferFlush);
452         mOutBufferFlush = nullptr;
453     }
454 
455     deleteContext();
456     return C2_OK;
457 }
458 
sendMetadata()459 void C2GoldfishHevcDec::sendMetadata() {
460     // compare and send if changed
461     MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
462     currentMetaData.primaries = mIntf->primaries();
463     currentMetaData.range = mIntf->range();
464     currentMetaData.transfer = mIntf->transfer();
465 
466     DDD("metadata primaries %d range %d transfer %d",
467             (int)(currentMetaData.primaries),
468             (int)(currentMetaData.range),
469             (int)(currentMetaData.transfer)
470        );
471 
472     if (mSentMetadata.primaries == currentMetaData.primaries &&
473         mSentMetadata.range == currentMetaData.range &&
474         mSentMetadata.transfer == currentMetaData.transfer) {
475         DDD("metadata is the same, no need to update");
476         return;
477     }
478     std::swap(mSentMetadata, currentMetaData);
479 
480     mContext->sendMetadata(&(mSentMetadata));
481 }
482 
createDecoder()483 status_t C2GoldfishHevcDec::createDecoder() {
484 
485     DDD("creating hevc context now w %d h %d", mWidth, mHeight);
486     if (mEnableAndroidNativeBuffers) {
487         mContext.reset(new MediaHevcDecoder(RenderMode::RENDER_BY_HOST_GPU));
488     } else {
489         mContext.reset(new MediaHevcDecoder(RenderMode::RENDER_BY_GUEST_CPU));
490     }
491     mContext->initHevcContext(mWidth, mHeight, mWidth, mHeight,
492                               MediaHevcDecoder::PixelFormat::YUV420P);
493 
494     return OK;
495 }
496 
setParams(size_t stride)497 status_t C2GoldfishHevcDec::setParams(size_t stride) {
498     (void)stride;
499     return OK;
500 }
501 
initDecoder()502 status_t C2GoldfishHevcDec::initDecoder() {
503     //    if (OK != createDecoder()) return UNKNOWN_ERROR;
504     mStride = ALIGN2(mWidth);
505     mSignalledError = false;
506     resetPlugin();
507 
508     return OK;
509 }
510 
setDecodeArgs(C2ReadView * inBuffer,C2GraphicView * outBuffer,size_t inOffset,size_t inSize,uint32_t tsMarker,bool hasPicture)511 bool C2GoldfishHevcDec::setDecodeArgs(C2ReadView *inBuffer,
512                                      C2GraphicView *outBuffer, size_t inOffset,
513                                      size_t inSize, uint32_t tsMarker, bool hasPicture) {
514     uint32_t displayStride = mStride;
515     (void)inBuffer;
516     (void)inOffset;
517     (void)inSize;
518     (void)tsMarker;
519     if (outBuffer) {
520         C2PlanarLayout layout;
521         layout = outBuffer->layout();
522         displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
523     }
524 
525     if (inBuffer) {
526         //= tsMarker;
527         mInPBuffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
528         mInPBufferSize = inSize;
529         mInTsMarker = tsMarker;
530         if (hasPicture) {
531             insertPts(tsMarker, mPts);
532         }
533     }
534 
535     // uint32_t displayHeight = mHeight;
536     // size_t lumaSize = displayStride * displayHeight;
537     // size_t chromaSize = lumaSize >> 2;
538 
539     if (mStride != displayStride) {
540         mStride = displayStride;
541         if (OK != setParams(mStride))
542             return false;
543     }
544 
545     return true;
546 }
547 
setFlushMode()548 status_t C2GoldfishHevcDec::setFlushMode() {
549     if (mContext) {
550         mContext->flush();
551     }
552     mHeaderDecoded = false;
553     return OK;
554 }
555 
resetDecoder()556 status_t C2GoldfishHevcDec::resetDecoder() {
557     mStride = 0;
558     mSignalledError = false;
559     mHeaderDecoded = false;
560     deleteContext();
561 
562     return OK;
563 }
564 
resetPlugin()565 void C2GoldfishHevcDec::resetPlugin() {
566     mSignalledOutputEos = false;
567     gettimeofday(&mTimeStart, nullptr);
568     gettimeofday(&mTimeEnd, nullptr);
569     if (mOutBlock) {
570         mOutBlock.reset();
571     }
572 }
573 
deleteContext()574 void C2GoldfishHevcDec::deleteContext() {
575     if (mContext) {
576         mContext->destroyHevcContext();
577         mContext.reset(nullptr);
578         mPts2Index.clear();
579         mOldPts2Index.clear();
580         mIndex2Pts.clear();
581     }
582 }
583 
fillEmptyWork(const std::unique_ptr<C2Work> & work)584 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
585     uint32_t flags = 0;
586     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
587         flags |= C2FrameData::FLAG_END_OF_STREAM;
588         DDD("signalling eos");
589     }
590     DDD("fill empty work");
591     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
592     work->worklets.front()->output.buffers.clear();
593     work->worklets.front()->output.ordinal = work->input.ordinal;
594     work->workletsProcessed = 1u;
595 }
596 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)597 void C2GoldfishHevcDec::finishWork(uint64_t index,
598                                   const std::unique_ptr<C2Work> &work) {
599     std::shared_ptr<C2Buffer> buffer =
600         createGraphicBuffer(std::move(mOutBlock), C2Rect(mWidth, mHeight));
601     mOutBlock = nullptr;
602     {
603         IntfImpl::Lock lock = mIntf->lock();
604         buffer->setInfo(mIntf->getColorAspects_l());
605     }
606 
607     class FillWork {
608       public:
609         FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
610                  const std::shared_ptr<C2Buffer> &buffer)
611             : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
612         ~FillWork() = default;
613 
614         void operator()(const std::unique_ptr<C2Work> &work) {
615             work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
616             work->worklets.front()->output.buffers.clear();
617             work->worklets.front()->output.ordinal = mOrdinal;
618             work->workletsProcessed = 1u;
619             work->result = C2_OK;
620             if (mBuffer) {
621                 work->worklets.front()->output.buffers.push_back(mBuffer);
622             }
623             DDD("timestamp = %lld, index = %lld, w/%s buffer",
624                 mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
625                 mBuffer ? "" : "o");
626         }
627 
628       private:
629         const uint32_t mFlags;
630         const C2WorkOrdinalStruct mOrdinal;
631         const std::shared_ptr<C2Buffer> mBuffer;
632     };
633 
634     auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
635         work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
636         work->worklets.front()->output.buffers.clear();
637         work->worklets.front()->output.buffers.push_back(buffer);
638         work->worklets.front()->output.ordinal = work->input.ordinal;
639         work->workletsProcessed = 1u;
640     };
641     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
642         bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
643         // TODO: Check if cloneAndSend can be avoided by tracking number of
644         // frames remaining
645         if (eos) {
646             if (buffer) {
647                 mOutIndex = index;
648                 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
649                 DDD("%s %d: cloneAndSend ", __func__, __LINE__);
650                 cloneAndSend(
651                     mOutIndex, work,
652                     FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
653                 buffer.reset();
654             }
655         } else {
656             DDD("%s %d: fill", __func__, __LINE__);
657             fillWork(work);
658         }
659     } else {
660         DDD("%s %d: finish", __func__, __LINE__);
661         finish(index, fillWork);
662     }
663 }
664 
665 c2_status_t
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)666 C2GoldfishHevcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
667     if (mOutBlock && (mOutBlock->width() != ALIGN2(mWidth) ||
668                       mOutBlock->height() != mHeight)) {
669         mOutBlock.reset();
670     }
671     if (!mOutBlock) {
672         const uint32_t format = HAL_PIXEL_FORMAT_YV12;
673         const C2MemoryUsage usage = {(uint64_t)(BufferUsage::VIDEO_DECODER),
674                                      C2MemoryUsage::CPU_WRITE | C2MemoryUsage::CPU_READ};
675         c2_status_t err = pool->fetchGraphicBlock(ALIGN2(mWidth), mHeight,
676                                                   format, usage, &mOutBlock);
677         if (err != C2_OK) {
678             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
679             return err;
680         }
681         if (mEnableAndroidNativeBuffers) {
682             auto c2Handle = mOutBlock->handle();
683             native_handle_t *grallocHandle =
684                 UnwrapNativeCodec2GrallocHandle(c2Handle);
685             mHostColorBufferId = getColorBufferHandle(grallocHandle);
686             DDD("found handle %d", mHostColorBufferId);
687         }
688         DDD("provided (%dx%d) required (%dx%d)", mOutBlock->width(),
689             mOutBlock->height(), ALIGN2(mWidth), mHeight);
690     }
691 
692     return C2_OK;
693 }
694 
checkMode(const std::shared_ptr<C2BlockPool> & pool)695 void C2GoldfishHevcDec::checkMode(const std::shared_ptr<C2BlockPool> &pool) {
696     mWidth = mIntf->width();
697     mHeight = mIntf->height();
698     //const bool isGraphic = (pool->getLocalId() == C2PlatformAllocatorStore::GRALLOC);
699     const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
700     DDD("buffer pool allocator id %x",  (int)(pool->getAllocatorId()));
701     if (isGraphic) {
702         uint64_t client_usage = getClientUsage(pool);
703         DDD("client has usage as 0x%llx", client_usage);
704         if (client_usage & BufferUsage::CPU_READ_MASK) {
705             DDD("decoding to guest byte buffer as client has read usage");
706             mEnableAndroidNativeBuffers = false;
707         } else {
708             DDD("decoding to host color buffer");
709             mEnableAndroidNativeBuffers = true;
710         }
711     } else {
712         DDD("decoding to guest byte buffer");
713         mEnableAndroidNativeBuffers = false;
714     }
715 }
716 
getVuiParams(hevc_image_t & img)717 void C2GoldfishHevcDec::getVuiParams(hevc_image_t &img) {
718 
719     VuiColorAspects vuiColorAspects;
720     vuiColorAspects.primaries = img.color_primaries;
721     vuiColorAspects.transfer = img.color_trc;
722     vuiColorAspects.coeffs = img.colorspace;
723     vuiColorAspects.fullRange = img.color_range == 2 ? true : false;
724 
725     // convert vui aspects to C2 values if changed
726     if (!(vuiColorAspects == mBitstreamColorAspects)) {
727         mBitstreamColorAspects = vuiColorAspects;
728         ColorAspects sfAspects;
729         C2StreamColorAspectsInfo::input codedAspects = {0u};
730         ColorUtils::convertIsoColorAspectsToCodecAspects(
731             vuiColorAspects.primaries, vuiColorAspects.transfer,
732             vuiColorAspects.coeffs, vuiColorAspects.fullRange, sfAspects);
733         if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
734             codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
735         }
736         if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
737             codedAspects.range = C2Color::RANGE_UNSPECIFIED;
738         }
739         if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
740             codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
741         }
742         if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
743             codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
744         }
745         std::vector<std::unique_ptr<C2SettingResult>> failures;
746         (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
747     }
748 }
749 
copyImageData(hevc_image_t & img)750 void C2GoldfishHevcDec::copyImageData(hevc_image_t &img) {
751     getVuiParams(img);
752     if (mEnableAndroidNativeBuffers)
753         return;
754 
755     auto writeView = mOutBlock->map().get();
756     if (writeView.error()) {
757         ALOGE("graphic view map failed %d", writeView.error());
758         return;
759     }
760     size_t dstYStride = writeView.layout().planes[C2PlanarLayout::PLANE_Y].rowInc;
761     size_t dstUVStride = writeView.layout().planes[C2PlanarLayout::PLANE_U].rowInc;
762 
763     uint8_t *pYBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_Y]);
764     uint8_t *pUBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_U]);
765     uint8_t *pVBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_V]);
766 
767     for (int i = 0; i < mHeight; ++i) {
768         memcpy(pYBuffer + i * dstYStride, img.data + i * mWidth, mWidth);
769     }
770     for (int i = 0; i < mHeight / 2; ++i) {
771         memcpy(pUBuffer + i * dstUVStride,
772                img.data + mWidth * mHeight + i * mWidth / 2, mWidth / 2);
773     }
774     for (int i = 0; i < mHeight / 2; ++i) {
775         memcpy(pVBuffer + i * dstUVStride,
776                img.data + mWidth * mHeight * 5 / 4 + i * mWidth / 2,
777                mWidth / 2);
778     }
779 }
780 
getWorkIndex(uint64_t pts)781 uint64_t C2GoldfishHevcDec::getWorkIndex(uint64_t pts) {
782     if (!mOldPts2Index.empty()) {
783         auto iter = mOldPts2Index.find(pts);
784         if (iter != mOldPts2Index.end()) {
785             auto index = iter->second;
786             DDD("found index %d for pts %" PRIu64, (int)index, pts);
787             return index;
788         }
789     }
790     auto iter = mPts2Index.find(pts);
791     if (iter != mPts2Index.end()) {
792         auto index = iter->second;
793         DDD("found index %d for pts %" PRIu64, (int)index, pts);
794         return index;
795     }
796     DDD("not found index for pts %" PRIu64, pts);
797     return 0;
798 }
799 
insertPts(uint32_t work_index,uint64_t pts)800 void C2GoldfishHevcDec::insertPts(uint32_t work_index, uint64_t pts) {
801     auto iter = mPts2Index.find(pts);
802     if (iter != mPts2Index.end()) {
803         // we have a collision here:
804         // apparently, older session is not done yet,
805         // lets save them
806         DDD("inserted to old pts %" PRIu64 " with index %d", pts, (int)iter->second);
807         mOldPts2Index[iter->first] = iter->second;
808     }
809     DDD("inserted pts %" PRIu64 " with index %d", pts, (int)work_index);
810     mIndex2Pts[work_index] = pts;
811     mPts2Index[pts] = work_index;
812 }
813 
removePts(uint64_t pts)814 void C2GoldfishHevcDec::removePts(uint64_t pts) {
815     bool found = false;
816     uint64_t index = 0;
817     // note: check old pts first to see
818     // if we have some left over, check them
819     if (!mOldPts2Index.empty()) {
820         auto iter = mOldPts2Index.find(pts);
821         if (iter != mOldPts2Index.end()) {
822             index = iter->second;
823             mOldPts2Index.erase(iter);
824             found = true;
825         }
826     } else {
827         auto iter = mPts2Index.find(pts);
828         if (iter != mPts2Index.end()) {
829             index = iter->second;
830             mPts2Index.erase(iter);
831             found = true;
832         }
833     }
834 
835     if (!found) return;
836 
837     auto iter2 = mIndex2Pts.find(index);
838     if (iter2 == mIndex2Pts.end()) return;
839     mIndex2Pts.erase(iter2);
840 }
841 
842 // TODO: can overall error checking be improved?
843 // TODO: allow configuration of color format and usage for graphic buffers
844 // instead
845 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
846 // TODO: pass coloraspects information to surface
847 // TODO: test support for dynamic change in resolution
848 // TODO: verify if the decoder sent back all frames
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)849 void C2GoldfishHevcDec::process(const std::unique_ptr<C2Work> &work,
850                                const std::shared_ptr<C2BlockPool> &pool) {
851     // Initialize output work
852     work->result = C2_OK;
853     work->workletsProcessed = 0u;
854     work->worklets.front()->output.flags = work->input.flags;
855     if (mSignalledError || mSignalledOutputEos) {
856         work->result = C2_BAD_VALUE;
857         return;
858     }
859 
860     DDD("process work");
861     if (!mContext) {
862         DDD("creating decoder context to host in process work");
863         checkMode(pool);
864         createDecoder();
865         decodeHeaderAfterFlush();
866     }
867 
868     size_t inOffset = 0u;
869     size_t inSize = 0u;
870     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
871     mPts = work->input.ordinal.timestamp.peeku();
872     C2ReadView rView = mDummyReadView;
873     if (!work->input.buffers.empty()) {
874         rView =
875             work->input.buffers[0]->data().linearBlocks().front().map().get();
876         inSize = rView.capacity();
877         if (inSize && rView.error()) {
878             ALOGE("read view map failed %d", rView.error());
879             work->result = rView.error();
880             return;
881         }
882     }
883     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
884     bool hasPicture = (inSize > 0);
885 
886     DDD("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
887         (int)work->input.ordinal.timestamp.peeku(),
888         (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
889     size_t inPos = 0;
890     while (inPos < inSize) {
891         if (C2_OK != ensureDecoderState(pool)) {
892             mSignalledError = true;
893             work->workletsProcessed = 1u;
894             work->result = C2_CORRUPTED;
895             return;
896         }
897 
898         {
899             // C2GraphicView wView;// = mOutBlock->map().get();
900             // if (wView.error()) {
901             //    ALOGE("graphic view map failed %d", wView.error());
902             //    work->result = wView.error();
903             //    return;
904             //}
905             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
906                 hasPicture = false;
907             }
908 
909             if (!setDecodeArgs(&rView, nullptr, inOffset + inPos,
910                                inSize - inPos, workIndex, hasPicture)) {
911                 mSignalledError = true;
912                 work->workletsProcessed = 1u;
913                 work->result = C2_CORRUPTED;
914                 return;
915             }
916 
917             DDD("flag is %x", work->input.flags);
918             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
919                 if (mCsd0.empty()) {
920                     mCsd0.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
921                     DDD("assign to csd0 with %d bytpes", mInPBufferSize);
922                 }
923             }
924 
925             bool whChanged = false;
926             if (GoldfishHevcHelper::isVpsFrame(mInPBuffer, mInPBufferSize)) {
927                 mHevcHelper.reset(new GoldfishHevcHelper(mWidth, mHeight));
928                 bool headerStatus = true;
929                 whChanged = mHevcHelper->decodeHeader(
930                     mInPBuffer, mInPBufferSize, headerStatus);
931                 if (!headerStatus) {
932                     mSignalledError = true;
933                     work->workletsProcessed = 1u;
934                     work->result = C2_CORRUPTED;
935                     return;
936                 }
937                 if (whChanged) {
938                         DDD("w changed from old %d to new %d\n", mWidth, mHevcHelper->getWidth());
939                         DDD("h changed from old %d to new %d\n", mHeight, mHevcHelper->getHeight());
940                         if (1) {
941                             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
942                             resetDecoder();
943                             resetPlugin();
944                             work->workletsProcessed = 0u;
945                         }
946                         {
947                             mWidth = mHevcHelper->getWidth();
948                             mHeight = mHevcHelper->getHeight();
949                             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
950                             std::vector<std::unique_ptr<C2SettingResult>> failures;
951                             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
952                             if (err == OK) {
953                                 work->worklets.front()->output.configUpdate.push_back(
954                                         C2Param::Copy(size));
955                                 ensureDecoderState(pool);
956                             } else {
957                                 ALOGE("Cannot set width and height");
958                                 mSignalledError = true;
959                                 work->workletsProcessed = 1u;
960                                 work->result = C2_CORRUPTED;
961                                 return;
962                             }
963                         }
964                         if (!mContext) {
965                             DDD("creating decoder context to host in process work");
966                             checkMode(pool);
967                             createDecoder();
968                         }
969                         continue;//return;
970                 } // end of whChanged
971             } // end of isVpsFrame
972 
973             sendMetadata();
974 
975             uint32_t delay;
976             GETTIME(&mTimeStart, nullptr);
977             TIME_DIFF(mTimeEnd, mTimeStart, delay);
978             (void)delay;
979             //(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
980             DDD("decoding");
981             hevc_result_t hevcRes =
982                 mContext->decodeFrame(mInPBuffer, mInPBufferSize, mPts);
983             mConsumedBytes = hevcRes.bytesProcessed;
984             DDD("decoding consumed %d", (int)mConsumedBytes);
985 
986             if (mHostColorBufferId > 0) {
987                 mImg = mContext->renderOnHostAndReturnImageMetadata(
988                     mHostColorBufferId);
989             } else {
990                 mImg = mContext->getImage();
991             }
992             uint32_t decodeTime;
993             GETTIME(&mTimeEnd, nullptr);
994             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
995             (void)decodeTime;
996         }
997         if (mImg.data != nullptr) {
998             DDD("got data %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
999             mHeaderDecoded = true;
1000             copyImageData(mImg);
1001             finishWork(getWorkIndex(mImg.pts), work);
1002             removePts(mImg.pts);
1003         } else {
1004             work->workletsProcessed = 0u;
1005         }
1006 
1007         inPos += mConsumedBytes;
1008     }
1009     if (eos) {
1010         DDD("drain because of eos");
1011         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1012         mSignalledOutputEos = true;
1013     } else if (!hasPicture) {
1014         DDD("no picture, fill empty work");
1015         fillEmptyWork(work);
1016     }
1017 
1018     work->input.buffers.clear();
1019 }
1020 
1021 c2_status_t
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1022 C2GoldfishHevcDec::drainInternal(uint32_t drainMode,
1023                                 const std::shared_ptr<C2BlockPool> &pool,
1024                                 const std::unique_ptr<C2Work> &work) {
1025     if (drainMode == NO_DRAIN) {
1026         ALOGW("drain with NO_DRAIN: no-op");
1027         return C2_OK;
1028     }
1029     if (drainMode == DRAIN_CHAIN) {
1030         ALOGW("DRAIN_CHAIN not supported");
1031         return C2_OMITTED;
1032     }
1033 
1034     if (OK != setFlushMode())
1035         return C2_CORRUPTED;
1036     while (true) {
1037         if (C2_OK != ensureDecoderState(pool)) {
1038             mSignalledError = true;
1039             work->workletsProcessed = 1u;
1040             work->result = C2_CORRUPTED;
1041             return C2_CORRUPTED;
1042         }
1043         /*
1044         C2GraphicView wView = mOutBlock->map().get();
1045         if (wView.error()) {
1046             ALOGE("graphic view map failed %d", wView.error());
1047             return C2_CORRUPTED;
1048         }
1049         if (!setDecodeArgs(nullptr, &wView, 0, 0, 0)) {
1050             mSignalledError = true;
1051             work->workletsProcessed = 1u;
1052             return C2_CORRUPTED;
1053         }
1054         */
1055 
1056         if (mHostColorBufferId > 0) {
1057             mImg = mContext->renderOnHostAndReturnImageMetadata(
1058                 mHostColorBufferId);
1059         } else {
1060             mImg = mContext->getImage();
1061         }
1062 
1063         // TODO: maybe keep rendering to screen
1064         //        mImg = mContext->getImage();
1065         if (mImg.data != nullptr) {
1066             DDD("got data in drain mode %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
1067             copyImageData(mImg);
1068             finishWork(getWorkIndex(mImg.pts), work);
1069             removePts(mImg.pts);
1070         } else {
1071             fillEmptyWork(work);
1072             break;
1073         }
1074     }
1075 
1076     return C2_OK;
1077 }
1078 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1079 c2_status_t C2GoldfishHevcDec::drain(uint32_t drainMode,
1080                                     const std::shared_ptr<C2BlockPool> &pool) {
1081     DDD("drainInternal because of drain");
1082     return drainInternal(drainMode, pool, nullptr);
1083 }
1084 
1085 class C2GoldfishHevcDecFactory : public C2ComponentFactory {
1086   public:
C2GoldfishHevcDecFactory()1087     C2GoldfishHevcDecFactory()
1088         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1089               GoldfishComponentStore::Create()->getParamReflector())) {}
1090 
1091     virtual c2_status_t
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1092     createComponent(c2_node_id_t id,
1093                     std::shared_ptr<C2Component> *const component,
1094                     std::function<void(C2Component *)> deleter) override {
1095         *component = std::shared_ptr<C2Component>(
1096             new C2GoldfishHevcDec(
1097                 COMPONENT_NAME, id,
1098                 std::make_shared<C2GoldfishHevcDec::IntfImpl>(mHelper)),
1099             deleter);
1100         return C2_OK;
1101     }
1102 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1103     virtual c2_status_t createInterface(
1104         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
1105         std::function<void(C2ComponentInterface *)> deleter) override {
1106         *interface = std::shared_ptr<C2ComponentInterface>(
1107             new SimpleInterface<C2GoldfishHevcDec::IntfImpl>(
1108                 COMPONENT_NAME, id,
1109                 std::make_shared<C2GoldfishHevcDec::IntfImpl>(mHelper)),
1110             deleter);
1111         return C2_OK;
1112     }
1113 
1114     virtual ~C2GoldfishHevcDecFactory() override = default;
1115 
1116   private:
1117     std::shared_ptr<C2ReflectorHelper> mHelper;
1118 };
1119 
1120 } // namespace android
1121 
CreateCodec2Factory()1122 extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
1123     DDD("in %s", __func__);
1124     return new ::android::C2GoldfishHevcDecFactory();
1125 }
1126 
DestroyCodec2Factory(::C2ComponentFactory * factory)1127 extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
1128     DDD("in %s", __func__);
1129     delete factory;
1130 }
1131