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