• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &param : 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