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