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 = 2 * 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 // TODO: support more formats?
235 addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
236 .withConstValue(new C2StreamPixelFormatInfo::output(
237 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
238 .build());
239 }
240
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)241 static C2R SizeSetter(bool mayBlock,
242 const C2P<C2StreamPictureSizeInfo::output> &oldMe,
243 C2P<C2StreamPictureSizeInfo::output> &me) {
244 (void)mayBlock;
245 DDD("calling sizesetter old w %d", oldMe.v.width);
246 DDD("calling sizesetter old h %d", oldMe.v.height);
247 DDD("calling sizesetter change to w %d", me.v.width);
248 DDD("calling sizesetter change to h %d", me.v.height);
249 C2R res = C2R::Ok();
250 auto mewidth = me.F(me.v.width);
251 auto meheight = me.F(me.v.height);
252
253 if (!mewidth.supportsAtAll(me.v.width)) {
254 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
255 DDD("override width with oldMe value");
256 me.set().width = oldMe.v.width;
257 DDD("something wrong here %s %d", __func__, __LINE__);
258 }
259 if (!meheight.supportsAtAll(me.v.height)) {
260 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
261 DDD("override height with oldMe value");
262 me.set().height = oldMe.v.height;
263 DDD("something wrong here %s %d", __func__, __LINE__);
264 }
265 return res;
266 }
267
268 static C2R
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)269 MaxPictureSizeSetter(bool mayBlock,
270 C2P<C2StreamMaxPictureSizeTuning::output> &me,
271 const C2P<C2StreamPictureSizeInfo::output> &size) {
272 (void)mayBlock;
273 // TODO: get max width/height from the size's field helpers vs.
274 // hardcoding
275 me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
276 me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
277 return C2R::Ok();
278 }
279
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)280 static C2R MaxInputSizeSetter(
281 bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
282 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
283 (void)mayBlock;
284 // assume compression ratio of 2
285 me.set().value = c2_max((((maxSize.v.width + 63) / 64) *
286 ((maxSize.v.height + 63) / 64) * 3072),
287 kMinInputBufferSize);
288 return C2R::Ok();
289 }
290
291 static C2R
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)292 DefaultColorAspectsSetter(bool mayBlock,
293 C2P<C2StreamColorAspectsTuning::output> &me) {
294 (void)mayBlock;
295 if (me.v.range > C2Color::RANGE_OTHER) {
296 me.set().range = C2Color::RANGE_OTHER;
297 }
298 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
299 me.set().primaries = C2Color::PRIMARIES_OTHER;
300 }
301 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
302 me.set().transfer = C2Color::TRANSFER_OTHER;
303 }
304 if (me.v.matrix > C2Color::MATRIX_OTHER) {
305 me.set().matrix = C2Color::MATRIX_OTHER;
306 }
307 return C2R::Ok();
308 }
309
310 static C2R
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)311 ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
312 const C2P<C2StreamPictureSizeInfo::output> &size) {
313 (void)mayBlock;
314 (void)size;
315 (void)me; // TODO: validate
316 return C2R::Ok();
317 }
318 std::shared_ptr<C2StreamColorAspectsTuning::output>
getDefaultColorAspects_l()319 getDefaultColorAspects_l() {
320 return mDefaultColorAspects;
321 }
322
width() const323 int width() const { return mSize->width; }
324
height() const325 int height() const { return mSize->height; }
326
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)327 static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
328 C2P<C2StreamHdr10PlusInfo::input> &me) {
329 (void)mayBlock;
330 (void)me; // TODO: validate
331 return C2R::Ok();
332 }
333
334 static C2R
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)335 Hdr10PlusInfoOutputSetter(bool mayBlock,
336 C2P<C2StreamHdr10PlusInfo::output> &me) {
337 (void)mayBlock;
338 (void)me; // TODO: validate
339 return C2R::Ok();
340 }
341
342 private:
343 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
344 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
345 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
346 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
347 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
348 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
349 std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
350 #ifdef VP9
351 #if 0
352 std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
353 #endif
354 std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
355 std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
356 #endif
357 };
358
ConverterThread(const std::shared_ptr<Mutexed<ConversionQueue>> & queue)359 C2GoldfishVpxDec::ConverterThread::ConverterThread(
360 const std::shared_ptr<Mutexed<ConversionQueue>> &queue)
361 : Thread(false), mQueue(queue) {}
362
threadLoop()363 bool C2GoldfishVpxDec::ConverterThread::threadLoop() {
364 Mutexed<ConversionQueue>::Locked queue(*mQueue);
365 if (queue->entries.empty()) {
366 queue.waitForCondition(queue->cond);
367 if (queue->entries.empty()) {
368 return true;
369 }
370 }
371 std::function<void()> convert = queue->entries.front();
372 queue->entries.pop_front();
373 if (!queue->entries.empty()) {
374 queue->cond.signal();
375 }
376 queue.unlock();
377
378 convert();
379
380 queue.lock();
381 if (--queue->numPending == 0u) {
382 queue->cond.broadcast();
383 }
384 return true;
385 }
386
C2GoldfishVpxDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)387 C2GoldfishVpxDec::C2GoldfishVpxDec(const char *name, c2_node_id_t id,
388 const std::shared_ptr<IntfImpl> &intfImpl)
389 : SimpleC2Component(
390 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
391 mIntf(intfImpl), mCtx(nullptr), mQueue(new Mutexed<ConversionQueue>) {}
392
~C2GoldfishVpxDec()393 C2GoldfishVpxDec::~C2GoldfishVpxDec() { onRelease(); }
394
onInit()395 c2_status_t C2GoldfishVpxDec::onInit() {
396 status_t err = initDecoder();
397 return err == OK ? C2_OK : C2_CORRUPTED;
398 }
399
onStop()400 c2_status_t C2GoldfishVpxDec::onStop() {
401 mSignalledError = false;
402 mSignalledOutputEos = false;
403
404 return C2_OK;
405 }
406
onReset()407 void C2GoldfishVpxDec::onReset() {
408 (void)onStop();
409 c2_status_t err = onFlush_sm();
410 if (err != C2_OK) {
411 ALOGW("Failed to flush decoder. Try to hard reset decoder");
412 destroyDecoder();
413 (void)initDecoder();
414 }
415 }
416
onRelease()417 void C2GoldfishVpxDec::onRelease() { destroyDecoder(); }
418
onFlush_sm()419 c2_status_t C2GoldfishVpxDec::onFlush_sm() {
420 if (mFrameParallelMode) {
421 // Flush decoder by passing nullptr data ptr and 0 size.
422 // Ideally, this should never fail.
423 if (vpx_codec_flush(mCtx)) {
424 ALOGE("Failed to flush on2 decoder.");
425 return C2_CORRUPTED;
426 }
427 }
428
429 // Drop all the decoded frames in decoder.
430 if (mCtx) {
431 setup_ctx_parameters(mCtx);
432 while ((mImg = vpx_codec_get_frame(mCtx))) {
433 }
434 }
435
436 mSignalledError = false;
437 mSignalledOutputEos = false;
438 return C2_OK;
439 }
440
initDecoder()441 status_t C2GoldfishVpxDec::initDecoder() {
442 ALOGI("calling init GoldfishVPX");
443 #ifdef VP9
444 mMode = MODE_VP9;
445 #else
446 mMode = MODE_VP8;
447 #endif
448
449 mWidth = 320;
450 mHeight = 240;
451 mFrameParallelMode = false;
452 mSignalledOutputEos = false;
453 mSignalledError = false;
454
455 return OK;
456 }
457
checkContext(const std::shared_ptr<C2BlockPool> & pool)458 void C2GoldfishVpxDec::checkContext(const std::shared_ptr<C2BlockPool> &pool) {
459 if (mCtx)
460 return;
461
462 mWidth = mIntf->width();
463 mHeight = mIntf->height();
464 ALOGI("created decoder context w %d h %d", mWidth, mHeight);
465 mCtx = new vpx_codec_ctx_t;
466 mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
467
468 // check for decoding mode:
469 {
470 // now get the block
471 constexpr uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
472 std::shared_ptr<C2GraphicBlock> block;
473 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ,
474 C2MemoryUsage::CPU_WRITE};
475 usage.expected = (uint64_t)(BufferUsage::GPU_DATA_BUFFER);
476
477 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight,
478 format, usage, &block);
479 if (err != C2_OK) {
480 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
481 return;
482 }
483 auto c2Handle = block->handle();
484 native_handle_t *grallocHandle =
485 UnwrapNativeCodec2GrallocHandle(c2Handle);
486 int hostColorBufferId = getColorBufferHandle(grallocHandle);
487 if (hostColorBufferId > 0) {
488 DDD("decoding to host color buffer");
489 mEnableAndroidNativeBuffers = true;
490 } else {
491 DDD("decoding to guest byte buffer");
492 mEnableAndroidNativeBuffers = false;
493 }
494 }
495
496 mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
497
498 int vpx_err = 0;
499 if ((vpx_err = vpx_codec_dec_init(mCtx))) {
500 ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
501 delete mCtx;
502 mCtx = NULL;
503 }
504 }
505
destroyDecoder()506 status_t C2GoldfishVpxDec::destroyDecoder() {
507 if (mCtx) {
508 ALOGI("calling destroying GoldfishVPX ctx %p", mCtx);
509 vpx_codec_destroy(mCtx);
510 delete mCtx;
511 mCtx = NULL;
512 }
513
514 return OK;
515 }
516
fillEmptyWork(const std::unique_ptr<C2Work> & work)517 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
518 uint32_t flags = 0;
519 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
520 flags |= C2FrameData::FLAG_END_OF_STREAM;
521 DDD("signalling eos");
522 }
523 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
524 work->worklets.front()->output.buffers.clear();
525 work->worklets.front()->output.ordinal = work->input.ordinal;
526 work->workletsProcessed = 1u;
527 }
528
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)529 void C2GoldfishVpxDec::finishWork(
530 uint64_t index, const std::unique_ptr<C2Work> &work,
531 const std::shared_ptr<C2GraphicBlock> &block) {
532 std::shared_ptr<C2Buffer> buffer =
533 createGraphicBuffer(block, C2Rect(mWidth, mHeight));
534 auto fillWork = [buffer, index,
535 intf = this->mIntf](const std::unique_ptr<C2Work> &work) {
536 uint32_t flags = 0;
537 if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
538 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
539 flags |= C2FrameData::FLAG_END_OF_STREAM;
540 DDD("signalling eos");
541 }
542 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
543 work->worklets.front()->output.buffers.clear();
544 work->worklets.front()->output.buffers.push_back(buffer);
545 work->worklets.front()->output.ordinal = work->input.ordinal;
546 work->workletsProcessed = 1u;
547
548 for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
549 if (param) {
550 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
551 C2StreamHdr10PlusInfo::input::From(param.get());
552
553 if (hdr10PlusInfo != nullptr) {
554 std::vector<std::unique_ptr<C2SettingResult>> failures;
555 std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
556 *param.get(), true /*output*/, param->stream());
557 c2_status_t err =
558 intf->config({outParam.get()}, C2_MAY_BLOCK, &failures);
559 if (err == C2_OK) {
560 work->worklets.front()->output.configUpdate.push_back(
561 C2Param::Copy(*outParam.get()));
562 } else {
563 ALOGE("finishWork: Config update size failed");
564 }
565 break;
566 }
567 }
568 }
569 };
570 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
571 fillWork(work);
572 } else {
573 finish(index, fillWork);
574 }
575 }
576
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)577 void C2GoldfishVpxDec::process(const std::unique_ptr<C2Work> &work,
578 const std::shared_ptr<C2BlockPool> &pool) {
579 DDD("%s %d doing work now", __func__, __LINE__);
580 // Initialize output work
581 work->result = C2_OK;
582 work->workletsProcessed = 0u;
583 work->worklets.front()->output.configUpdate.clear();
584 work->worklets.front()->output.flags = work->input.flags;
585
586 if (mSignalledError || mSignalledOutputEos) {
587 work->result = C2_BAD_VALUE;
588 return;
589 }
590
591 size_t inOffset = 0u;
592 size_t inSize = 0u;
593 C2ReadView rView = mDummyReadView;
594 if (!work->input.buffers.empty()) {
595 rView =
596 work->input.buffers[0]->data().linearBlocks().front().map().get();
597 inSize = rView.capacity();
598 if (inSize && rView.error()) {
599 ALOGE("read view map failed %d", rView.error());
600 work->result = C2_CORRUPTED;
601 return;
602 }
603 }
604
605 checkContext(pool);
606
607 bool codecConfig =
608 ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
609 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
610
611 DDD("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
612 (int)work->input.ordinal.timestamp.peeku(),
613 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
614
615 // Software VP9 Decoder does not need the Codec Specific Data (CSD)
616 // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
617 // it was passed.
618 if (codecConfig) {
619 // Ignore CSD buffer for VP9.
620 if (mMode == MODE_VP9) {
621 fillEmptyWork(work);
622 return;
623 } else {
624 // Tolerate the CSD buffer for VP8. This is a workaround
625 // for b/28689536. continue
626 ALOGW("WARNING: Got CSD buffer for VP8. Continue");
627 }
628 }
629
630 if (inSize) {
631 uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
632 vpx_codec_err_t err = vpx_codec_decode(
633 mCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
634 if (err != 0) {
635 ALOGE("on2 decoder failed to decode frame. err: ");
636 mSignalledError = true;
637 work->workletsProcessed = 1u;
638 work->result = C2_CORRUPTED;
639 return;
640 }
641 }
642
643 status_t err = outputBuffer(pool, work);
644 if (err == NOT_ENOUGH_DATA) {
645 if (inSize > 0) {
646 DDD("Maybe non-display frame at %lld.",
647 work->input.ordinal.frameIndex.peekll());
648 // send the work back with empty buffer.
649 inSize = 0;
650 }
651 } else if (err != OK) {
652 ALOGD("Error while getting the output frame out");
653 // work->result would be already filled; do fillEmptyWork() below to
654 // send the work back.
655 inSize = 0;
656 }
657
658 if (eos) {
659 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
660 mSignalledOutputEos = true;
661 } else if (!inSize) {
662 fillEmptyWork(work);
663 }
664 }
665
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)666 static void copyOutputBufferToYuvPlanarFrame(
667 uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
668 size_t srcYStride, size_t srcUStride, size_t srcVStride, size_t dstYStride,
669 size_t dstUVStride, uint32_t width, uint32_t height) {
670 uint8_t *dstStart = dst;
671
672 for (size_t i = 0; i < height; ++i) {
673 memcpy(dst, srcY, width);
674 srcY += srcYStride;
675 dst += dstYStride;
676 }
677
678 dst = dstStart + dstYStride * height;
679 for (size_t i = 0; i < height / 2; ++i) {
680 memcpy(dst, srcV, width / 2);
681 srcV += srcVStride;
682 dst += dstUVStride;
683 }
684
685 dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
686 for (size_t i = 0; i < height / 2; ++i) {
687 memcpy(dst, srcU, width / 2);
688 srcU += srcUStride;
689 dst += dstUVStride;
690 }
691 }
692
setup_ctx_parameters(vpx_codec_ctx_t * ctx,int hostColorBufferId)693 void C2GoldfishVpxDec::setup_ctx_parameters(vpx_codec_ctx_t *ctx,
694 int hostColorBufferId) {
695 ctx->width = mWidth;
696 ctx->height = mHeight;
697 ctx->hostColorBufferId = hostColorBufferId;
698 ctx->outputBufferWidth = mWidth;
699 ctx->outputBufferHeight = mHeight;
700 int32_t bpp = 1;
701 ctx->bpp = bpp;
702 }
703
704 status_t
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)705 C2GoldfishVpxDec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
706 const std::unique_ptr<C2Work> &work) {
707 if (!(work && pool))
708 return BAD_VALUE;
709
710 // now get the block
711 std::shared_ptr<C2GraphicBlock> block;
712 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
713 uint32_t format = HAL_PIXEL_FORMAT_YCBCR_420_888;
714 usage.expected = (uint64_t)(BufferUsage::GPU_DATA_BUFFER);
715
716 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight, format,
717 usage, &block);
718 if (err != C2_OK) {
719 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
720 work->result = err;
721 return UNKNOWN_ERROR;
722 }
723
724 bool decodingToByteBuffer = false;
725 {
726 auto c2Handle = block->handle();
727 native_handle_t *grallocHandle =
728 UnwrapNativeCodec2GrallocHandle(c2Handle);
729 int hostColorBufferId = getColorBufferHandle(grallocHandle);
730 if (hostColorBufferId > 0) {
731 DDD("found handle %d", hostColorBufferId);
732 } else {
733 decodingToByteBuffer = true;
734 DDD("decode to buffer, because handle %d is invalid",
735 hostColorBufferId);
736 // change to -1 so host knows it is definitely invalid
737 // 0 is a bit confusing
738 hostColorBufferId = -1;
739 }
740 setup_ctx_parameters(mCtx, hostColorBufferId);
741 }
742
743 vpx_image_t *img = vpx_codec_get_frame(mCtx);
744
745 if (!img)
746 return NOT_ENOUGH_DATA;
747
748 if (img->d_w != mWidth || img->d_h != mHeight) {
749 DDD("updating w %d h %d to w %d h %d", mWidth, mHeight, img->d_w,
750 img->d_h);
751 mWidth = img->d_w;
752 mHeight = img->d_h;
753
754 // need to re-allocate since size changed, especially for byte buffer
755 // mode
756 if (true) {
757 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 2), mHeight,
758 format, usage, &block);
759 if (err != C2_OK) {
760 ALOGE("fetchGraphicBlock for Output failed with status %d",
761 err);
762 work->result = err;
763 return UNKNOWN_ERROR;
764 }
765 }
766
767 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
768 std::vector<std::unique_ptr<C2SettingResult>> failures;
769 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
770 if (err == C2_OK) {
771 work->worklets.front()->output.configUpdate.push_back(
772 C2Param::Copy(size));
773 } else {
774 ALOGE("Config update size failed");
775 mSignalledError = true;
776 work->workletsProcessed = 1u;
777 work->result = C2_CORRUPTED;
778 return UNKNOWN_ERROR;
779 }
780 }
781 if (img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_I42016) {
782 ALOGE("img->fmt %d not supported", img->fmt);
783 mSignalledError = true;
784 work->workletsProcessed = 1u;
785 work->result = C2_CORRUPTED;
786 return false;
787 }
788
789 if (img->fmt == VPX_IMG_FMT_I42016) {
790 IntfImpl::Lock lock = mIntf->lock();
791 std::shared_ptr<C2StreamColorAspectsTuning::output>
792 defaultColorAspects = mIntf->getDefaultColorAspects_l();
793
794 if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
795 defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
796 defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
797 format = HAL_PIXEL_FORMAT_RGBA_1010102;
798 }
799 }
800
801 if (decodingToByteBuffer) {
802
803 C2GraphicView wView = block->map().get();
804 if (wView.error()) {
805 ALOGE("graphic view map failed %d", wView.error());
806 work->result = C2_CORRUPTED;
807 return UNKNOWN_ERROR;
808 }
809
810 DDD("provided (%dx%d) required (%dx%d), out frameindex %lld",
811 block->width(), block->height(), mWidth, mHeight,
812 ((c2_cntr64_t *)img->user_priv)->peekll());
813
814 uint8_t *dst =
815 const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
816 size_t srcYStride = mWidth;
817 size_t srcUStride = mWidth / 2;
818 size_t srcVStride = mWidth / 2;
819 C2PlanarLayout layout = wView.layout();
820 size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
821 size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
822
823 if (img->fmt == VPX_IMG_FMT_I42016) {
824 ALOGW("WARNING: not I42016 is not supported !!!");
825 } else if (1) {
826 const uint8_t *srcY = (const uint8_t *)mCtx->dst;
827 const uint8_t *srcV = srcY + mWidth * mHeight;
828 const uint8_t *srcU = srcV + mWidth * mHeight / 4;
829 // TODO: the following crashes
830 copyOutputBufferToYuvPlanarFrame(dst, srcY, srcU, srcV, srcYStride,
831 srcUStride, srcVStride, dstYStride,
832 dstUVStride, mWidth, mHeight);
833 // memcpy(dst, srcY, mWidth * mHeight / 2);
834 }
835 }
836 DDD("provided (%dx%d) required (%dx%d), out frameindex %lld",
837 block->width(), block->height(), mWidth, mHeight,
838 ((c2_cntr64_t *)img->user_priv)->peekll());
839
840 finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work,
841 std::move(block));
842 return OK;
843 }
844
845 c2_status_t
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)846 C2GoldfishVpxDec::drainInternal(uint32_t drainMode,
847 const std::shared_ptr<C2BlockPool> &pool,
848 const std::unique_ptr<C2Work> &work) {
849 if (drainMode == NO_DRAIN) {
850 ALOGW("drain with NO_DRAIN: no-op");
851 return C2_OK;
852 }
853 if (drainMode == DRAIN_CHAIN) {
854 ALOGW("DRAIN_CHAIN not supported");
855 return C2_OMITTED;
856 }
857
858 while (outputBuffer(pool, work) == OK) {
859 }
860
861 if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
862 work->workletsProcessed == 0u) {
863 fillEmptyWork(work);
864 }
865
866 return C2_OK;
867 }
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)868 c2_status_t C2GoldfishVpxDec::drain(uint32_t drainMode,
869 const std::shared_ptr<C2BlockPool> &pool) {
870 return drainInternal(drainMode, pool, nullptr);
871 }
872
873 class C2GoldfishVpxFactory : public C2ComponentFactory {
874 public:
C2GoldfishVpxFactory()875 C2GoldfishVpxFactory()
876 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
877 GoldfishComponentStore::Create()->getParamReflector())) {
878
879 ALOGI("platform store is %p, reflector is %p",
880 GetCodec2PlatformComponentStore().get(),
881 GetCodec2PlatformComponentStore()->getParamReflector().get());
882 }
883
884 virtual c2_status_t
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)885 createComponent(c2_node_id_t id,
886 std::shared_ptr<C2Component> *const component,
887 std::function<void(C2Component *)> deleter) override {
888 *component = std::shared_ptr<C2Component>(
889 new C2GoldfishVpxDec(
890 COMPONENT_NAME, id,
891 std::make_shared<C2GoldfishVpxDec::IntfImpl>(mHelper)),
892 deleter);
893 return C2_OK;
894 }
895
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)896 virtual c2_status_t createInterface(
897 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
898 std::function<void(C2ComponentInterface *)> deleter) override {
899 *interface = std::shared_ptr<C2ComponentInterface>(
900 new SimpleInterface<C2GoldfishVpxDec::IntfImpl>(
901 COMPONENT_NAME, id,
902 std::make_shared<C2GoldfishVpxDec::IntfImpl>(mHelper)),
903 deleter);
904 return C2_OK;
905 }
906
907 virtual ~C2GoldfishVpxFactory() override = default;
908
909 private:
910 std::shared_ptr<C2ReflectorHelper> mHelper;
911 };
912
913 } // namespace android
914
CreateCodec2Factory()915 extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
916 DDD("in %s", __func__);
917 return new ::android::C2GoldfishVpxFactory();
918 }
919
DestroyCodec2Factory(::C2ComponentFactory * factory)920 extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
921 DDD("in %s", __func__);
922 delete factory;
923 }
924