1 /*
2 * Copyright (C) 2018 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 "C2GoldfishVpxDec"
19 #include <log/log.h>
20
21 #include <algorithm>
22
23 #include <media/stagefright/foundation/AUtils.h>
24 #include <media/stagefright/foundation/MediaDefs.h>
25
26 #include <C2AllocatorGralloc.h>
27 #include <C2PlatformSupport.h>
28 //#include <android/hardware/graphics/common/1.0/types.h>
29
30 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
31 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
32 #include <hidl/LegacySupport.h>
33
34 #include <C2Debug.h>
35 #include <C2PlatformSupport.h>
36 #include <SimpleC2Interface.h>
37 #include <goldfish_codec2/store/GoldfishComponentStore.h>
38
39 #include <gralloc_cb_bp.h>
40
41 #include <color_buffer_utils.h>
42
43 #include "C2GoldfishVpxDec.h"
44
45 #define DEBUG 0
46 #if DEBUG
47 #define DDD(...) ALOGW(__VA_ARGS__)
48 #else
49 #define DDD(...) ((void)0)
50 #endif
51 using ::android::hardware::graphics::common::V1_0::BufferUsage;
52 using ::android::hardware::graphics::common::V1_2::PixelFormat;
53
54 namespace android {
55 constexpr size_t kMinInputBufferSize = 6 * 1024 * 1024;
56 #ifdef VP9
57 constexpr char COMPONENT_NAME[] = "c2.goldfish.vp9.decoder";
58 #else
59 constexpr char COMPONENT_NAME[] = "c2.goldfish.vp8.decoder";
60 #endif
61
62 class C2GoldfishVpxDec::IntfImpl : public SimpleInterface<void>::BaseParams {
63 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)64 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
65 : SimpleInterface<void>::BaseParams(helper, COMPONENT_NAME,
66 C2Component::KIND_DECODER,
67 C2Component::DOMAIN_VIDEO,
68 #ifdef VP9
69 MEDIA_MIMETYPE_VIDEO_VP9
70 #else
71 MEDIA_MIMETYPE_VIDEO_VP8
72 #endif
73 ) {
74 DDD("calling IntfImpl now helper %p", helper.get());
75 noPrivateBuffers(); // TODO: account for our buffers here
76 noInputReferences();
77 noOutputReferences();
78 noInputLatency();
79 noTimeStretch();
80
81 // TODO: output latency and reordering
82
83 addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
84 .withConstValue(new C2ComponentAttributesSetting(
85 C2Component::ATTRIB_IS_TEMPORAL))
86 .build());
87
88 addParameter(
89 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
90 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
91 .withFields({
92 C2F(mSize, width).inRange(2, 4096, 2),
93 C2F(mSize, height).inRange(2, 4096, 2),
94 })
95 .withSetter(SizeSetter)
96 .build());
97
98 #ifdef VP9
99 // TODO: Add C2Config::PROFILE_VP9_2HDR ??
100 addParameter(
101 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
102 .withDefault(new C2StreamProfileLevelInfo::input(
103 0u, C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5))
104 .withFields({C2F(mProfileLevel, profile)
105 .oneOf({C2Config::PROFILE_VP9_0,
106 C2Config::PROFILE_VP9_2}),
107 C2F(mProfileLevel, level)
108 .oneOf({
109 C2Config::LEVEL_VP9_1,
110 C2Config::LEVEL_VP9_1_1,
111 C2Config::LEVEL_VP9_2,
112 C2Config::LEVEL_VP9_2_1,
113 C2Config::LEVEL_VP9_3,
114 C2Config::LEVEL_VP9_3_1,
115 C2Config::LEVEL_VP9_4,
116 C2Config::LEVEL_VP9_4_1,
117 C2Config::LEVEL_VP9_5,
118 })})
119 .withSetter(ProfileLevelSetter, mSize)
120 .build());
121
122 mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
123 addParameter(
124 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
125 .withDefault(mHdr10PlusInfoInput)
126 .withFields({
127 C2F(mHdr10PlusInfoInput, m.value).any(),
128 })
129 .withSetter(Hdr10PlusInfoInputSetter)
130 .build());
131
132 mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
133 addParameter(DefineParam(mHdr10PlusInfoOutput,
134 C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
135 .withDefault(mHdr10PlusInfoOutput)
136 .withFields({
137 C2F(mHdr10PlusInfoOutput, m.value).any(),
138 })
139 .withSetter(Hdr10PlusInfoOutputSetter)
140 .build());
141
142 #if 0
143 // sample BT.2020 static info
144 mHdrStaticInfo = std::make_shared<C2StreamHdrStaticInfo::output>();
145 mHdrStaticInfo->mastering = {
146 .red = { .x = 0.708, .y = 0.292 },
147 .green = { .x = 0.170, .y = 0.797 },
148 .blue = { .x = 0.131, .y = 0.046 },
149 .white = { .x = 0.3127, .y = 0.3290 },
150 .maxLuminance = 1000,
151 .minLuminance = 0.1,
152 };
153 mHdrStaticInfo->maxCll = 1000;
154 mHdrStaticInfo->maxFall = 120;
155
156 mHdrStaticInfo->maxLuminance = 0; // disable static info
157
158 helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
159 addParameter(
160 DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
161 .withDefault(mHdrStaticInfo)
162 .withFields({
163 C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
164 // TODO
165 })
166 .withSetter(HdrStaticInfoSetter)
167 .build());
168 #endif
169 #else
170 addParameter(
171 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
172 .withConstValue(new C2StreamProfileLevelInfo::input(
173 0u, C2Config::PROFILE_UNUSED, C2Config::LEVEL_UNUSED))
174 .build());
175 #endif
176
177 addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
178 .withDefault(new C2StreamMaxPictureSizeTuning::output(
179 0u, 320, 240))
180 .withFields({
181 C2F(mSize, width).inRange(2, 4096, 2),
182 C2F(mSize, height).inRange(2, 4096, 2),
183 })
184 .withSetter(MaxPictureSizeSetter, mSize)
185 .build());
186
187 addParameter(
188 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
189 .withDefault(new C2StreamMaxBufferSizeInfo::input(
190 0u, kMinInputBufferSize))
191 .withFields({
192 C2F(mMaxInputSize, value).any(),
193 })
194 .calculatedAs(MaxInputSizeSetter, mMaxSize)
195 .build());
196
197 C2ChromaOffsetStruct locations[1] = {
198 C2ChromaOffsetStruct::ITU_YUV_420_0()};
199 std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
200 C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
201 C2Color::YUV_420);
202 memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
203
204 defaultColorInfo = C2StreamColorInfo::output::AllocShared(
205 {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
206 C2Color::YUV_420);
207 helper->addStructDescriptors<C2ChromaOffsetStruct>();
208
209 addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
210 .withConstValue(defaultColorInfo)
211 .build());
212
213 addParameter(
214 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
215 .withDefault(new C2StreamColorAspectsTuning::output(
216 0u, C2Color::RANGE_UNSPECIFIED,
217 C2Color::PRIMARIES_UNSPECIFIED,
218 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
219 .withFields({C2F(mDefaultColorAspects, range)
220 .inRange(C2Color::RANGE_UNSPECIFIED,
221 C2Color::RANGE_OTHER),
222 C2F(mDefaultColorAspects, primaries)
223 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
224 C2Color::PRIMARIES_OTHER),
225 C2F(mDefaultColorAspects, transfer)
226 .inRange(C2Color::TRANSFER_UNSPECIFIED,
227 C2Color::TRANSFER_OTHER),
228 C2F(mDefaultColorAspects, matrix)
229 .inRange(C2Color::MATRIX_UNSPECIFIED,
230 C2Color::MATRIX_OTHER)})
231 .withSetter(DefaultColorAspectsSetter)
232 .build());
233
234 addParameter(
235 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
236 .withDefault(new C2StreamColorAspectsInfo::input(
237 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
238 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
239 .withFields({C2F(mCodedColorAspects, range)
240 .inRange(C2Color::RANGE_UNSPECIFIED,
241 C2Color::RANGE_OTHER),
242 C2F(mCodedColorAspects, primaries)
243 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
244 C2Color::PRIMARIES_OTHER),
245 C2F(mCodedColorAspects, transfer)
246 .inRange(C2Color::TRANSFER_UNSPECIFIED,
247 C2Color::TRANSFER_OTHER),
248 C2F(mCodedColorAspects, matrix)
249 .inRange(C2Color::MATRIX_UNSPECIFIED,
250 C2Color::MATRIX_OTHER)})
251 .withSetter(CodedColorAspectsSetter)
252 .build());
253
254 addParameter(
255 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
256 .withDefault(new C2StreamColorAspectsInfo::output(
257 0u, C2Color::RANGE_UNSPECIFIED,
258 C2Color::PRIMARIES_UNSPECIFIED,
259 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
260 .withFields({C2F(mColorAspects, range)
261 .inRange(C2Color::RANGE_UNSPECIFIED,
262 C2Color::RANGE_OTHER),
263 C2F(mColorAspects, primaries)
264 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
265 C2Color::PRIMARIES_OTHER),
266 C2F(mColorAspects, transfer)
267 .inRange(C2Color::TRANSFER_UNSPECIFIED,
268 C2Color::TRANSFER_OTHER),
269 C2F(mColorAspects, matrix)
270 .inRange(C2Color::MATRIX_UNSPECIFIED,
271 C2Color::MATRIX_OTHER)})
272 .withSetter(ColorAspectsSetter, mDefaultColorAspects,
273 mCodedColorAspects)
274 .build());
275
276 // TODO: support more formats?
277 addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
278 .withConstValue(new C2StreamPixelFormatInfo::output(
279 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
280 .build());
281 }
282
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)283 static C2R SizeSetter(bool mayBlock,
284 const C2P<C2StreamPictureSizeInfo::output> &oldMe,
285 C2P<C2StreamPictureSizeInfo::output> &me) {
286 (void)mayBlock;
287 DDD("calling sizesetter old w %d", oldMe.v.width);
288 DDD("calling sizesetter old h %d", oldMe.v.height);
289 DDD("calling sizesetter change to w %d", me.v.width);
290 DDD("calling sizesetter change to h %d", me.v.height);
291 C2R res = C2R::Ok();
292 auto mewidth = me.F(me.v.width);
293 auto meheight = me.F(me.v.height);
294
295 if (!mewidth.supportsAtAll(me.v.width)) {
296 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
297 DDD("override width with oldMe value");
298 me.set().width = oldMe.v.width;
299 DDD("something wrong here %s %d", __func__, __LINE__);
300 }
301 if (!meheight.supportsAtAll(me.v.height)) {
302 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
303 DDD("override height with oldMe value");
304 me.set().height = oldMe.v.height;
305 DDD("something wrong here %s %d", __func__, __LINE__);
306 }
307 return res;
308 }
309
310 static C2R
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)311 MaxPictureSizeSetter(bool mayBlock,
312 C2P<C2StreamMaxPictureSizeTuning::output> &me,
313 const C2P<C2StreamPictureSizeInfo::output> &size) {
314 (void)mayBlock;
315 // TODO: get max width/height from the size's field helpers vs.
316 // hardcoding
317 me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
318 me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
319 return C2R::Ok();
320 }
321
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)322 static C2R MaxInputSizeSetter(
323 bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
324 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
325 (void)mayBlock;
326 // assume compression ratio of 2
327 me.set().value = c2_max((((maxSize.v.width + 63) / 64) *
328 ((maxSize.v.height + 63) / 64) * 3072),
329 kMinInputBufferSize);
330 return C2R::Ok();
331 }
332
333 static C2R
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)334 DefaultColorAspectsSetter(bool mayBlock,
335 C2P<C2StreamColorAspectsTuning::output> &me) {
336 (void)mayBlock;
337 if (me.v.range > C2Color::RANGE_OTHER) {
338 me.set().range = C2Color::RANGE_OTHER;
339 }
340 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
341 me.set().primaries = C2Color::PRIMARIES_OTHER;
342 }
343 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
344 me.set().transfer = C2Color::TRANSFER_OTHER;
345 }
346 if (me.v.matrix > C2Color::MATRIX_OTHER) {
347 me.set().matrix = C2Color::MATRIX_OTHER;
348 }
349 DDD("%s %d update range %d primaries/color %d transfer %d",
350 __func__, __LINE__,
351 (int)(me.v.range),
352 (int)(me.v.primaries),
353 (int)(me.v.transfer)
354 );
355 return C2R::Ok();
356 }
357
358 static C2R
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)359 CodedColorAspectsSetter(bool mayBlock,
360 C2P<C2StreamColorAspectsInfo::input> &me) {
361 (void)mayBlock;
362 if (me.v.range > C2Color::RANGE_OTHER) {
363 me.set().range = C2Color::RANGE_OTHER;
364 }
365 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
366 me.set().primaries = C2Color::PRIMARIES_OTHER;
367 }
368 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
369 me.set().transfer = C2Color::TRANSFER_OTHER;
370 }
371 if (me.v.matrix > C2Color::MATRIX_OTHER) {
372 me.set().matrix = C2Color::MATRIX_OTHER;
373 }
374 DDD("%s %d coded color aspect range %d primaries/color %d transfer %d",
375 __func__, __LINE__,
376 (int)(me.v.range),
377 (int)(me.v.primaries),
378 (int)(me.v.transfer)
379 );
380 return C2R::Ok();
381 }
382
383 static C2R
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)384 ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
385 const C2P<C2StreamColorAspectsTuning::output> &def,
386 const C2P<C2StreamColorAspectsInfo::input> &coded) {
387 (void)mayBlock;
388 // take default values for all unspecified fields, and coded values for
389 // specified ones
390 DDD("%s %d before update: color aspect range %d primaries/color %d transfer %d",
391 __func__, __LINE__,
392 (int)(me.v.range),
393 (int)(me.v.primaries),
394 (int)(me.v.transfer)
395 );
396 me.set().range =
397 coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
398 me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
399 ? def.v.primaries
400 : coded.v.primaries;
401 me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
402 ? def.v.transfer
403 : coded.v.transfer;
404 me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix
405 : coded.v.matrix;
406
407 DDD("%s %d after update: color aspect range %d primaries/color %d transfer %d",
408 __func__, __LINE__,
409 (int)(me.v.range),
410 (int)(me.v.primaries),
411 (int)(me.v.transfer)
412 );
413 return C2R::Ok();
414 }
415
416 static C2R
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)417 ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
418 const C2P<C2StreamPictureSizeInfo::output> &size) {
419 (void)mayBlock;
420 (void)size;
421 (void)me; // TODO: validate
422 return C2R::Ok();
423 }
424 std::shared_ptr<C2StreamColorAspectsTuning::output>
getDefaultColorAspects_l()425 getDefaultColorAspects_l() {
426 return mDefaultColorAspects;
427 }
428
getColorAspects_l()429 std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
430 return mColorAspects;
431 }
432
width() const433 int width() const { return mSize->width; }
434
height() const435 int height() const { return mSize->height; }
436
primaries() const437 int primaries() const { return mDefaultColorAspects->primaries; }
438
range() const439 int range() const { return mDefaultColorAspects->range; }
440
transfer() const441 int transfer() const { return mDefaultColorAspects->transfer; }
442
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)443 static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
444 C2P<C2StreamHdr10PlusInfo::input> &me) {
445 (void)mayBlock;
446 (void)me; // TODO: validate
447 return C2R::Ok();
448 }
449
450 static C2R
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)451 Hdr10PlusInfoOutputSetter(bool mayBlock,
452 C2P<C2StreamHdr10PlusInfo::output> &me) {
453 (void)mayBlock;
454 (void)me; // TODO: validate
455 return C2R::Ok();
456 }
457
458 private:
459 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
460 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
461 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
462 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
463 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
464 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
465 std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
466 std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
467 std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
468 #ifdef VP9
469 #if 0
470 std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
471 #endif
472 std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
473 std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
474 #endif
475 };
476
ConverterThread(const std::shared_ptr<Mutexed<ConversionQueue>> & queue)477 C2GoldfishVpxDec::ConverterThread::ConverterThread(
478 const std::shared_ptr<Mutexed<ConversionQueue>> &queue)
479 : Thread(false), mQueue(queue) {}
480
threadLoop()481 bool C2GoldfishVpxDec::ConverterThread::threadLoop() {
482 Mutexed<ConversionQueue>::Locked queue(*mQueue);
483 if (queue->entries.empty()) {
484 queue.waitForCondition(queue->cond);
485 if (queue->entries.empty()) {
486 return true;
487 }
488 }
489 std::function<void()> convert = queue->entries.front();
490 queue->entries.pop_front();
491 if (!queue->entries.empty()) {
492 queue->cond.signal();
493 }
494 queue.unlock();
495
496 convert();
497
498 queue.lock();
499 if (--queue->numPending == 0u) {
500 queue->cond.broadcast();
501 }
502 return true;
503 }
504
C2GoldfishVpxDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)505 C2GoldfishVpxDec::C2GoldfishVpxDec(const char *name, c2_node_id_t id,
506 const std::shared_ptr<IntfImpl> &intfImpl)
507 : SimpleC2Component(
508 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
509 mIntf(intfImpl), mCtx(nullptr), mQueue(new Mutexed<ConversionQueue>) {}
510
~C2GoldfishVpxDec()511 C2GoldfishVpxDec::~C2GoldfishVpxDec() { onRelease(); }
512
onInit()513 c2_status_t C2GoldfishVpxDec::onInit() {
514 status_t err = initDecoder();
515 return err == OK ? C2_OK : C2_CORRUPTED;
516 }
517
onStop()518 c2_status_t C2GoldfishVpxDec::onStop() {
519 mSignalledError = false;
520 mSignalledOutputEos = false;
521
522 return C2_OK;
523 }
524
onReset()525 void C2GoldfishVpxDec::onReset() {
526 (void)onStop();
527 c2_status_t err = onFlush_sm();
528 if (err != C2_OK) {
529 ALOGW("Failed to flush decoder. Try to hard reset decoder");
530 destroyDecoder();
531 (void)initDecoder();
532 }
533 }
534
onRelease()535 void C2GoldfishVpxDec::onRelease() { destroyDecoder(); }
536
sendMetadata()537 void C2GoldfishVpxDec::sendMetadata() {
538 // compare and send if changed
539 MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
540 currentMetaData.primaries = mIntf->primaries();
541 currentMetaData.range = mIntf->range();
542 currentMetaData.transfer = mIntf->transfer();
543
544 DDD("metadata primaries %d range %d transfer %d",
545 (int)(currentMetaData.primaries),
546 (int)(currentMetaData.range),
547 (int)(currentMetaData.transfer)
548 );
549
550 if (mSentMetadata.primaries == currentMetaData.primaries &&
551 mSentMetadata.range == currentMetaData.range &&
552 mSentMetadata.transfer == currentMetaData.transfer) {
553 DDD("metadata is the same, no need to update");
554 return;
555 }
556 std::swap(mSentMetadata, currentMetaData);
557
558 vpx_codec_send_metadata(mCtx, &(mSentMetadata));
559 }
560
onFlush_sm()561 c2_status_t C2GoldfishVpxDec::onFlush_sm() {
562 if (mFrameParallelMode) {
563 // Flush decoder by passing nullptr data ptr and 0 size.
564 // Ideally, this should never fail.
565 if (vpx_codec_flush(mCtx)) {
566 ALOGE("Failed to flush on2 decoder.");
567 return C2_CORRUPTED;
568 }
569 }
570
571 // Drop all the decoded frames in decoder.
572 if (mCtx) {
573 setup_ctx_parameters(mCtx);
574 while ((mImg = vpx_codec_get_frame(mCtx))) {
575 }
576 }
577
578 mSignalledError = false;
579 mSignalledOutputEos = false;
580 return C2_OK;
581 }
582
initDecoder()583 status_t C2GoldfishVpxDec::initDecoder() {
584 ALOGI("calling init GoldfishVPX");
585 #ifdef VP9
586 mMode = MODE_VP9;
587 #else
588 mMode = MODE_VP8;
589 #endif
590
591 mWidth = 320;
592 mHeight = 240;
593 mFrameParallelMode = false;
594 mSignalledOutputEos = false;
595 mSignalledError = false;
596
597 return OK;
598 }
599
checkContext(const std::shared_ptr<C2BlockPool> & pool)600 void C2GoldfishVpxDec::checkContext(const std::shared_ptr<C2BlockPool> &pool) {
601 if (mCtx)
602 return;
603
604 mWidth = mIntf->width();
605 mHeight = mIntf->height();
606 ALOGI("created decoder context w %d h %d", mWidth, mHeight);
607 mCtx = new vpx_codec_ctx_t;
608 mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
609
610 //const bool isGraphic = (pool->getLocalId() == C2PlatformAllocatorStore::GRALLOC);
611 const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
612 DDD("buffer pool allocator id %x", (int)(pool->getAllocatorId()));
613 if (isGraphic) {
614 uint64_t client_usage = getClientUsage(pool);
615 DDD("client has usage as 0x%llx", client_usage);
616 if (client_usage & BufferUsage::CPU_READ_MASK) {
617 DDD("decoding to guest byte buffer as client has read usage");
618 mEnableAndroidNativeBuffers = false;
619 } else {
620 DDD("decoding to host color buffer");
621 mEnableAndroidNativeBuffers = true;
622 }
623 } else {
624 DDD("decoding to guest byte buffer");
625 mEnableAndroidNativeBuffers = false;
626 }
627
628 mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
629
630 int vpx_err = 0;
631 if ((vpx_err = vpx_codec_dec_init(mCtx))) {
632 ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
633 delete mCtx;
634 mCtx = NULL;
635 }
636 }
637
destroyDecoder()638 status_t C2GoldfishVpxDec::destroyDecoder() {
639 if (mCtx) {
640 ALOGI("calling destroying GoldfishVPX ctx %p", mCtx);
641 vpx_codec_destroy(mCtx);
642 delete mCtx;
643 mCtx = NULL;
644 }
645
646 return OK;
647 }
648
fillEmptyWork(const std::unique_ptr<C2Work> & work)649 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
650 uint32_t flags = 0;
651 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
652 flags |= C2FrameData::FLAG_END_OF_STREAM;
653 DDD("signalling eos");
654 }
655 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
656 work->worklets.front()->output.buffers.clear();
657 work->worklets.front()->output.ordinal = work->input.ordinal;
658 work->workletsProcessed = 1u;
659 }
660
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)661 void C2GoldfishVpxDec::finishWork(
662 uint64_t index, const std::unique_ptr<C2Work> &work,
663 const std::shared_ptr<C2GraphicBlock> &block) {
664 std::shared_ptr<C2Buffer> buffer =
665 createGraphicBuffer(block, C2Rect(mWidth, mHeight));
666 {
667 IntfImpl::Lock lock = mIntf->lock();
668 #ifdef VP9
669 buffer->setInfo(mIntf->getColorAspects_l());
670 #else
671 std::shared_ptr<C2StreamColorAspectsInfo::output> tColorAspects =
672 std::make_shared<C2StreamColorAspectsInfo::output>
673 (C2StreamColorAspectsInfo::output(0u, m_range,
674 m_primaries, m_transfer,
675 m_matrix));
676 DDD("%s %d setting to index %d range %d primaries %d transfer %d",
677 __func__, __LINE__, (int)index,
678 (int)tColorAspects->range,
679 (int)tColorAspects->primaries,
680 (int)tColorAspects->transfer);
681 buffer->setInfo(tColorAspects);
682 #endif
683 }
684
685 auto fillWork = [buffer, index,
686 intf = this->mIntf](const std::unique_ptr<C2Work> &work) {
687 uint32_t flags = 0;
688 if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
689 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
690 flags |= C2FrameData::FLAG_END_OF_STREAM;
691 DDD("signalling eos");
692 }
693 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
694 work->worklets.front()->output.buffers.clear();
695 work->worklets.front()->output.buffers.push_back(buffer);
696 work->worklets.front()->output.ordinal = work->input.ordinal;
697 work->workletsProcessed = 1u;
698
699 for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
700 if (param) {
701 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
702 C2StreamHdr10PlusInfo::input::From(param.get());
703
704 if (hdr10PlusInfo != nullptr) {
705 std::vector<std::unique_ptr<C2SettingResult>> failures;
706 std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
707 *param.get(), true /*output*/, param->stream());
708 c2_status_t err =
709 intf->config({outParam.get()}, C2_MAY_BLOCK, &failures);
710 if (err == C2_OK) {
711 work->worklets.front()->output.configUpdate.push_back(
712 C2Param::Copy(*outParam.get()));
713 } else {
714 ALOGE("finishWork: Config update size failed");
715 }
716 break;
717 }
718 }
719 }
720 };
721 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
722 fillWork(work);
723 } else {
724 finish(index, fillWork);
725 }
726 }
727
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)728 void C2GoldfishVpxDec::process(const std::unique_ptr<C2Work> &work,
729 const std::shared_ptr<C2BlockPool> &pool) {
730 DDD("%s %d doing work now", __func__, __LINE__);
731 // Initialize output work
732 work->result = C2_OK;
733 work->workletsProcessed = 0u;
734 work->worklets.front()->output.configUpdate.clear();
735 work->worklets.front()->output.flags = work->input.flags;
736
737 if (mSignalledError || mSignalledOutputEos) {
738 work->result = C2_BAD_VALUE;
739 return;
740 }
741
742 size_t inOffset = 0u;
743 size_t inSize = 0u;
744 C2ReadView rView = mDummyReadView;
745 if (!work->input.buffers.empty()) {
746 rView =
747 work->input.buffers[0]->data().linearBlocks().front().map().get();
748 inSize = rView.capacity();
749 if (inSize && rView.error()) {
750 ALOGE("read view map failed %d", rView.error());
751 work->result = C2_CORRUPTED;
752 return;
753 }
754 }
755
756 checkContext(pool);
757
758 bool codecConfig =
759 ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
760 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
761
762 DDD("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
763 (int)work->input.ordinal.timestamp.peeku(),
764 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
765
766 if (mMode == MODE_VP8) {
767 constexpr uint64_t ONE_SECOND_IN_MICRO_SECOND = 1000 * 1000;
768 // bug: 349159609
769 // note, vp8 does not have the FLAG_CODEC_CONFIG and the test
770 // android.mediav2.cts.DecoderDynamicColorAspectTest test still
771 // expects vp8 to pass. so this hack is to check the time stamp
772 // change to update the color aspect: too early or too late is
773 // a problem as it can cause mismatch of frame and coloraspect
774 DDD("%s %d vp8 last pts is %d current pts is %d",
775 __func__, __LINE__, mLastPts, (int) work->input.ordinal.timestamp.peeku());
776 if (mLastPts + ONE_SECOND_IN_MICRO_SECOND <= work->input.ordinal.timestamp.peeku()) {
777 codecConfig = true;
778 DDD("%s %d updated codecConfig to true", __func__, __LINE__);
779 } else {
780 DDD("%s %d keep codecConfig to false", __func__, __LINE__);
781 }
782 mLastPts = work->input.ordinal.timestamp.peeku();
783 if (mLastPts == 0) {
784 codecConfig = true;
785 }
786 if (codecConfig) {
787 IntfImpl::Lock lock = mIntf->lock();
788 std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
789 mIntf->getDefaultColorAspects_l();
790 m_primaries = defaultColorAspects->primaries;
791 m_range = defaultColorAspects->range;
792 m_transfer = defaultColorAspects->transfer;
793 m_matrix = defaultColorAspects->matrix;
794 }
795 }
796
797 if (codecConfig) {
798 {
799 IntfImpl::Lock lock = mIntf->lock();
800 std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
801 mIntf->getDefaultColorAspects_l();
802 lock.unlock();
803 C2StreamColorAspectsInfo::input codedAspects(0u, defaultColorAspects->range,
804 defaultColorAspects->primaries, defaultColorAspects->transfer,
805 defaultColorAspects->matrix);
806 std::vector<std::unique_ptr<C2SettingResult>> failures;
807 (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
808 }
809
810 DDD("%s %d updated coloraspect due to codec config", __func__, __LINE__);
811 if (mMode == MODE_VP9) {
812 fillEmptyWork(work);
813 return;
814 }
815 }
816
817 sendMetadata();
818
819 if (inSize) {
820 uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
821 vpx_codec_err_t err = vpx_codec_decode(
822 mCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
823 if (err != 0) {
824 ALOGE("on2 decoder failed to decode frame. err: ");
825 mSignalledError = true;
826 work->workletsProcessed = 1u;
827 work->result = C2_CORRUPTED;
828 return;
829 }
830 }
831
832 status_t err = outputBuffer(pool, work);
833 if (err == NOT_ENOUGH_DATA) {
834 if (inSize > 0) {
835 DDD("Maybe non-display frame at %lld.",
836 work->input.ordinal.frameIndex.peekll());
837 // send the work back with empty buffer.
838 inSize = 0;
839 }
840 } else if (err != OK) {
841 ALOGD("Error while getting the output frame out");
842 // work->result would be already filled; do fillEmptyWork() below to
843 // send the work back.
844 inSize = 0;
845 }
846
847 if (eos) {
848 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
849 mSignalledOutputEos = true;
850 } else if (!inSize) {
851 fillEmptyWork(work);
852 }
853 }
854
copyOutputBufferToYuvPlanarFrame(uint8_t * dst,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,uint32_t width,uint32_t height)855 static void copyOutputBufferToYuvPlanarFrame(
856 uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
857 size_t srcYStride, size_t srcUStride, size_t srcVStride, size_t dstYStride,
858 size_t dstUVStride, uint32_t width, uint32_t height) {
859 uint8_t *dstStart = dst;
860
861 for (size_t i = 0; i < height; ++i) {
862 memcpy(dst, srcY, width);
863 srcY += srcYStride;
864 dst += dstYStride;
865 }
866
867 dst = dstStart + dstYStride * height;
868 for (size_t i = 0; i < height / 2; ++i) {
869 memcpy(dst, srcV, width / 2);
870 srcV += srcVStride;
871 dst += dstUVStride;
872 }
873
874 dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
875 for (size_t i = 0; i < height / 2; ++i) {
876 memcpy(dst, srcU, width / 2);
877 srcU += srcUStride;
878 dst += dstUVStride;
879 }
880 }
881
setup_ctx_parameters(vpx_codec_ctx_t * ctx,int hostColorBufferId)882 void C2GoldfishVpxDec::setup_ctx_parameters(vpx_codec_ctx_t *ctx,
883 int hostColorBufferId) {
884 ctx->width = mWidth;
885 ctx->height = mHeight;
886 ctx->hostColorBufferId = hostColorBufferId;
887 ctx->outputBufferWidth = mWidth;
888 ctx->outputBufferHeight = mHeight;
889 int32_t bpp = 1;
890 ctx->bpp = bpp;
891 }
892
893 status_t
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)894 C2GoldfishVpxDec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
895 const std::unique_ptr<C2Work> &work) {
896 if (!(work && pool))
897 return BAD_VALUE;
898
899 // now get the block
900 std::shared_ptr<C2GraphicBlock> block;
901 uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
902 const C2MemoryUsage usage = {(uint64_t)(BufferUsage::VIDEO_DECODER),
903 C2MemoryUsage::CPU_WRITE | C2MemoryUsage::CPU_READ};
904
905 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight, format,
906 usage, &block);
907 if (err != C2_OK) {
908 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
909 work->result = err;
910 return UNKNOWN_ERROR;
911 }
912
913 int hostColorBufferId = -1;
914 const bool decodingToHostColorBuffer = mEnableAndroidNativeBuffers;
915 if(decodingToHostColorBuffer){
916 auto c2Handle = block->handle();
917 native_handle_t *grallocHandle =
918 UnwrapNativeCodec2GrallocHandle(c2Handle);
919 hostColorBufferId = getColorBufferHandle(grallocHandle);
920 if (hostColorBufferId > 0) {
921 DDD("found handle %d", hostColorBufferId);
922 } else {
923 DDD("decode to buffer, because handle %d is invalid",
924 hostColorBufferId);
925 // change to -1 so host knows it is definitely invalid
926 // 0 is a bit confusing
927 hostColorBufferId = -1;
928 }
929 }
930 setup_ctx_parameters(mCtx, hostColorBufferId);
931
932 vpx_image_t *img = vpx_codec_get_frame(mCtx);
933
934 if (!img)
935 return NOT_ENOUGH_DATA;
936
937 if (img->d_w != mWidth || img->d_h != mHeight) {
938 DDD("updating w %d h %d to w %d h %d", mWidth, mHeight, img->d_w,
939 img->d_h);
940 mWidth = img->d_w;
941 mHeight = img->d_h;
942
943 // need to re-allocate since size changed, especially for byte buffer
944 // mode
945 if (true) {
946 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight,
947 format, usage, &block);
948 if (err != C2_OK) {
949 ALOGE("fetchGraphicBlock for Output failed with status %d",
950 err);
951 work->result = err;
952 return UNKNOWN_ERROR;
953 }
954 }
955
956 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
957 std::vector<std::unique_ptr<C2SettingResult>> failures;
958 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
959 if (err == C2_OK) {
960 work->worklets.front()->output.configUpdate.push_back(
961 C2Param::Copy(size));
962 } else {
963 ALOGE("Config update size failed");
964 mSignalledError = true;
965 work->workletsProcessed = 1u;
966 work->result = C2_CORRUPTED;
967 return UNKNOWN_ERROR;
968 }
969 }
970 if (img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_I42016) {
971 ALOGE("img->fmt %d not supported", img->fmt);
972 mSignalledError = true;
973 work->workletsProcessed = 1u;
974 work->result = C2_CORRUPTED;
975 return false;
976 }
977
978 if (img->fmt == VPX_IMG_FMT_I42016) {
979 IntfImpl::Lock lock = mIntf->lock();
980 std::shared_ptr<C2StreamColorAspectsTuning::output>
981 defaultColorAspects = mIntf->getDefaultColorAspects_l();
982
983 if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
984 defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
985 defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
986 format = HAL_PIXEL_FORMAT_RGBA_1010102;
987 }
988 }
989
990 if (!decodingToHostColorBuffer) {
991
992 C2GraphicView wView = block->map().get();
993 if (wView.error()) {
994 ALOGE("graphic view map failed %d", wView.error());
995 work->result = C2_CORRUPTED;
996 return UNKNOWN_ERROR;
997 }
998
999 DDD("provided (%dx%d) required (%dx%d), out frameindex %lld",
1000 block->width(), block->height(), mWidth, mHeight,
1001 ((c2_cntr64_t *)img->user_priv)->peekll());
1002
1003 uint8_t *dst =
1004 const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
1005 size_t srcYStride = mWidth;
1006 size_t srcUStride = mWidth / 2;
1007 size_t srcVStride = mWidth / 2;
1008 C2PlanarLayout layout = wView.layout();
1009 size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
1010 size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
1011
1012 if (img->fmt == VPX_IMG_FMT_I42016) {
1013 ALOGW("WARNING: not I42016 is not supported !!!");
1014 } else if (1) {
1015 const uint8_t *srcY = (const uint8_t *)mCtx->dst;
1016 const uint8_t *srcV = srcY + mWidth * mHeight;
1017 const uint8_t *srcU = srcV + mWidth * mHeight / 4;
1018 // TODO: the following crashes
1019 copyOutputBufferToYuvPlanarFrame(dst, srcY, srcU, srcV, srcYStride,
1020 srcUStride, srcVStride, dstYStride,
1021 dstUVStride, mWidth, mHeight);
1022 // memcpy(dst, srcY, mWidth * mHeight / 2);
1023 }
1024 }
1025 DDD("provided (%dx%d) required (%dx%d), out frameindex %lld",
1026 block->width(), block->height(), mWidth, mHeight,
1027 ((c2_cntr64_t *)img->user_priv)->peekll());
1028
1029 finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work,
1030 std::move(block));
1031 return OK;
1032 }
1033
1034 c2_status_t
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1035 C2GoldfishVpxDec::drainInternal(uint32_t drainMode,
1036 const std::shared_ptr<C2BlockPool> &pool,
1037 const std::unique_ptr<C2Work> &work) {
1038 if (drainMode == NO_DRAIN) {
1039 ALOGW("drain with NO_DRAIN: no-op");
1040 return C2_OK;
1041 }
1042 if (drainMode == DRAIN_CHAIN) {
1043 ALOGW("DRAIN_CHAIN not supported");
1044 return C2_OMITTED;
1045 }
1046
1047 while (outputBuffer(pool, work) == OK) {
1048 }
1049
1050 if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
1051 work->workletsProcessed == 0u) {
1052 fillEmptyWork(work);
1053 }
1054
1055 return C2_OK;
1056 }
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1057 c2_status_t C2GoldfishVpxDec::drain(uint32_t drainMode,
1058 const std::shared_ptr<C2BlockPool> &pool) {
1059 return drainInternal(drainMode, pool, nullptr);
1060 }
1061
1062 class C2GoldfishVpxFactory : public C2ComponentFactory {
1063 public:
C2GoldfishVpxFactory()1064 C2GoldfishVpxFactory()
1065 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1066 GoldfishComponentStore::Create()->getParamReflector())) {
1067
1068 ALOGI("platform store is %p, reflector is %p",
1069 GetCodec2PlatformComponentStore().get(),
1070 GetCodec2PlatformComponentStore()->getParamReflector().get());
1071 }
1072
1073 virtual c2_status_t
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1074 createComponent(c2_node_id_t id,
1075 std::shared_ptr<C2Component> *const component,
1076 std::function<void(C2Component *)> deleter) override {
1077 *component = std::shared_ptr<C2Component>(
1078 new C2GoldfishVpxDec(
1079 COMPONENT_NAME, id,
1080 std::make_shared<C2GoldfishVpxDec::IntfImpl>(mHelper)),
1081 deleter);
1082 return C2_OK;
1083 }
1084
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1085 virtual c2_status_t createInterface(
1086 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
1087 std::function<void(C2ComponentInterface *)> deleter) override {
1088 *interface = std::shared_ptr<C2ComponentInterface>(
1089 new SimpleInterface<C2GoldfishVpxDec::IntfImpl>(
1090 COMPONENT_NAME, id,
1091 std::make_shared<C2GoldfishVpxDec::IntfImpl>(mHelper)),
1092 deleter);
1093 return C2_OK;
1094 }
1095
1096 virtual ~C2GoldfishVpxFactory() override = default;
1097
1098 private:
1099 std::shared_ptr<C2ReflectorHelper> mHelper;
1100 };
1101
1102 } // namespace android
1103
CreateCodec2Factory()1104 extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
1105 DDD("in %s", __func__);
1106 return new ::android::C2GoldfishVpxFactory();
1107 }
1108
DestroyCodec2Factory(::C2ComponentFactory * factory)1109 extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
1110 DDD("in %s", __func__);
1111 delete factory;
1112 }
1113