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 "C2SoftVpxDec"
19 #include <log/log.h>
20 
21 #include <algorithm>
22 #include <media/stagefright/foundation/AUtils.h>
23 #include <media/stagefright/foundation/MediaDefs.h>
24 
25 #include <C2Debug.h>
26 #include <C2PlatformSupport.h>
27 #include <Codec2BufferUtils.h>
28 #include <Codec2CommonUtils.h>
29 #include <SimpleC2Interface.h>
30 
31 #include "C2SoftVpxDec.h"
32 
33 namespace android {
34 constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
35 #ifdef VP9
36 constexpr char COMPONENT_NAME[] = "c2.android.vp9.decoder";
37 #else
38 constexpr char COMPONENT_NAME[] = "c2.android.vp8.decoder";
39 #endif
40 
41 class C2SoftVpxDec::IntfImpl : public SimpleInterface<void>::BaseParams {
42 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)43     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
44         : SimpleInterface<void>::BaseParams(
45                 helper,
46                 COMPONENT_NAME,
47                 C2Component::KIND_DECODER,
48                 C2Component::DOMAIN_VIDEO,
49 #ifdef VP9
50                 MEDIA_MIMETYPE_VIDEO_VP9
51 #else
52                 MEDIA_MIMETYPE_VIDEO_VP8
53 #endif
54                 ) {
55         noPrivateBuffers(); // TODO: account for our buffers here
56         noInputReferences();
57         noOutputReferences();
58         noInputLatency();
59         noTimeStretch();
60 
61         // TODO: output latency and reordering
62 
63         addParameter(
64                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
65                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
66                 .build());
67 
68         addParameter(
69                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
70                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
71                 .withFields({
72                     C2F(mSize, width).inRange(2, 2048),
73                     C2F(mSize, height).inRange(2, 2048),
74                 })
75                 .withSetter(SizeSetter)
76                 .build());
77 
78 #ifdef VP9
79         // TODO: Add C2Config::PROFILE_VP9_2HDR ??
80         addParameter(
81                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
82                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
83                         C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5))
84                 .withFields({
85                     C2F(mProfileLevel, profile).oneOf({
86                             C2Config::PROFILE_VP9_0,
87                             C2Config::PROFILE_VP9_2}),
88                     C2F(mProfileLevel, level).oneOf({
89                             C2Config::LEVEL_VP9_1,
90                             C2Config::LEVEL_VP9_1_1,
91                             C2Config::LEVEL_VP9_2,
92                             C2Config::LEVEL_VP9_2_1,
93                             C2Config::LEVEL_VP9_3,
94                             C2Config::LEVEL_VP9_3_1,
95                             C2Config::LEVEL_VP9_4,
96                             C2Config::LEVEL_VP9_4_1,
97                             C2Config::LEVEL_VP9_5,
98                     })
99                 })
100                 .withSetter(ProfileLevelSetter, mSize)
101                 .build());
102 
103         mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
104         addParameter(
105                 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
106                 .withDefault(mHdr10PlusInfoInput)
107                 .withFields({
108                     C2F(mHdr10PlusInfoInput, m.value).any(),
109                 })
110                 .withSetter(Hdr10PlusInfoInputSetter)
111                 .build());
112 
113         mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
114         addParameter(
115                 DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
116                 .withDefault(mHdr10PlusInfoOutput)
117                 .withFields({
118                     C2F(mHdr10PlusInfoOutput, m.value).any(),
119                 })
120                 .withSetter(Hdr10PlusInfoOutputSetter)
121                 .build());
122 
123 #if 0
124         // sample BT.2020 static info
125         mHdrStaticInfo = std::make_shared<C2StreamHdrStaticInfo::output>();
126         mHdrStaticInfo->mastering = {
127             .red   = { .x = 0.708,  .y = 0.292 },
128             .green = { .x = 0.170,  .y = 0.797 },
129             .blue  = { .x = 0.131,  .y = 0.046 },
130             .white = { .x = 0.3127, .y = 0.3290 },
131             .maxLuminance = 1000,
132             .minLuminance = 0.1,
133         };
134         mHdrStaticInfo->maxCll = 1000;
135         mHdrStaticInfo->maxFall = 120;
136 
137         mHdrStaticInfo->maxLuminance = 0; // disable static info
138 
139         helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
140         addParameter(
141                 DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
142                 .withDefault(mHdrStaticInfo)
143                 .withFields({
144                     C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
145                     // TODO
146                 })
147                 .withSetter(HdrStaticInfoSetter)
148                 .build());
149 #endif
150 #else
151         addParameter(
152                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
153                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
154                         C2Config::PROFILE_VP8_0, C2Config::LEVEL_UNUSED))
155                 .withFields({
156                     C2F(mProfileLevel, profile).equalTo(
157                         PROFILE_VP8_0
158                     ),
159                     C2F(mProfileLevel, level).equalTo(
160                         LEVEL_UNUSED),
161                 })
162                 .withSetter(ProfileLevelSetter, mSize)
163                 .build());
164 #endif
165 
166         addParameter(
167                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
168                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
169                 .withFields({
170                     C2F(mSize, width).inRange(2, 2048, 2),
171                     C2F(mSize, height).inRange(2, 2048, 2),
172                 })
173                 .withSetter(MaxPictureSizeSetter, mSize)
174                 .build());
175 
176         addParameter(
177                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
178                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
179                 .withFields({
180                     C2F(mMaxInputSize, value).any(),
181                 })
182                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
183                 .build());
184 
185         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
186         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
187             C2StreamColorInfo::output::AllocShared(
188                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
189         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
190 
191         defaultColorInfo =
192             C2StreamColorInfo::output::AllocShared(
193                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
194                     0u, 8u /* bitDepth */, C2Color::YUV_420);
195         helper->addStructDescriptors<C2ChromaOffsetStruct>();
196 
197         addParameter(
198                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
199                 .withConstValue(defaultColorInfo)
200                 .build());
201 
202         addParameter(
203                 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
204                 .withDefault(new C2StreamColorAspectsTuning::output(
205                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
206                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
207                 .withFields({
208                     C2F(mDefaultColorAspects, range).inRange(
209                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
210                     C2F(mDefaultColorAspects, primaries).inRange(
211                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
212                     C2F(mDefaultColorAspects, transfer).inRange(
213                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
214                     C2F(mDefaultColorAspects, matrix).inRange(
215                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
216                 })
217                 .withSetter(DefaultColorAspectsSetter)
218                 .build());
219 
220         // TODO: support more formats?
221         std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_YCBCR_420_888};
222 #ifdef VP9
223         if (isHalPixelFormatSupported((AHardwareBuffer_Format)HAL_PIXEL_FORMAT_YCBCR_P010)) {
224             pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
225         }
226         // If color format surface isn't added to supported formats, there is no way to know
227         // when the color-format is configured to surface. This is necessary to be able to
228         // choose 10-bit format while decoding 10-bit clips in surface mode
229         pixelFormats.push_back(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
230 #endif
231         addParameter(
232                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
233                 .withDefault(new C2StreamPixelFormatInfo::output(
234                                   0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
235                 .withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
236                 .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
237                 .build());
238 
239     }
240 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)241     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
242                           C2P<C2StreamPictureSizeInfo::output> &me) {
243         (void)mayBlock;
244         C2R res = C2R::Ok();
245         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
246             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
247             me.set().width = oldMe.v.width;
248         }
249         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
250             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
251             me.set().height = oldMe.v.height;
252         }
253         return res;
254     }
255 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)256     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
257                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
258         (void)mayBlock;
259         // TODO: get max width/height from the size's field helpers vs. hardcoding
260         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 2048u);
261         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 2048u);
262         return C2R::Ok();
263     }
264 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)265     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
266                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
267         (void)mayBlock;
268         // assume compression ratio of 2
269         me.set().value = c2_max((((maxSize.v.width + 63) / 64)
270                 * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
271         return C2R::Ok();
272     }
273 
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)274     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
275         (void)mayBlock;
276         if (me.v.range > C2Color::RANGE_OTHER) {
277             me.set().range = C2Color::RANGE_OTHER;
278         }
279         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
280             me.set().primaries = C2Color::PRIMARIES_OTHER;
281         }
282         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
283             me.set().transfer = C2Color::TRANSFER_OTHER;
284         }
285         if (me.v.matrix > C2Color::MATRIX_OTHER) {
286             me.set().matrix = C2Color::MATRIX_OTHER;
287         }
288         return C2R::Ok();
289     }
290 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)291     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
292                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
293         (void)mayBlock;
294         (void)size;
295         (void)me;  // TODO: validate
296         return C2R::Ok();
297     }
getDefaultColorAspects_l()298     std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
299         return mDefaultColorAspects;
300     }
301 
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)302     static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input> &me) {
303         (void)mayBlock;
304         (void)me;  // TODO: validate
305         return C2R::Ok();
306     }
307 
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)308     static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output> &me) {
309         (void)mayBlock;
310         (void)me;  // TODO: validate
311         return C2R::Ok();
312     }
313 
314     // unsafe getters
getPixelFormat_l() const315     std::shared_ptr<C2StreamPixelFormatInfo::output> getPixelFormat_l() const {
316         return mPixelFormat;
317     }
318 
319 private:
320     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
321     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
322     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
323     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
324     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
325     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
326     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
327 #ifdef VP9
328 #if 0
329     std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
330 #endif
331     std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
332     std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
333 #endif
334 };
335 
ConverterThread(const std::shared_ptr<Mutexed<ConversionQueue>> & queue)336 C2SoftVpxDec::ConverterThread::ConverterThread(
337         const std::shared_ptr<Mutexed<ConversionQueue>> &queue)
338     : Thread(false), mQueue(queue) {}
339 
threadLoop()340 bool C2SoftVpxDec::ConverterThread::threadLoop() {
341     Mutexed<ConversionQueue>::Locked queue(*mQueue);
342     if (queue->entries.empty()) {
343         queue.waitForCondition(queue->cond);
344         if (queue->entries.empty()) {
345             return true;
346         }
347     }
348     std::function<void()> convert = queue->entries.front();
349     queue->entries.pop_front();
350     if (!queue->entries.empty()) {
351         queue->cond.signal();
352     }
353     queue.unlock();
354 
355     convert();
356 
357     queue.lock();
358     if (--queue->numPending == 0u) {
359         queue->cond.broadcast();
360     }
361     return true;
362 }
363 
C2SoftVpxDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)364 C2SoftVpxDec::C2SoftVpxDec(
365         const char *name,
366         c2_node_id_t id,
367         const std::shared_ptr<IntfImpl> &intfImpl)
368     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
369       mIntf(intfImpl),
370       mCodecCtx(nullptr),
371       mCoreCount(1),
372       mQueue(new Mutexed<ConversionQueue>) {
373 }
374 
~C2SoftVpxDec()375 C2SoftVpxDec::~C2SoftVpxDec() {
376     onRelease();
377 }
378 
onInit()379 c2_status_t C2SoftVpxDec::onInit() {
380     status_t err = initDecoder();
381     return err == OK ? C2_OK : C2_CORRUPTED;
382 }
383 
onStop()384 c2_status_t C2SoftVpxDec::onStop() {
385     mSignalledError = false;
386     mSignalledOutputEos = false;
387 
388     return C2_OK;
389 }
390 
onReset()391 void C2SoftVpxDec::onReset() {
392     (void)onStop();
393     c2_status_t err = onFlush_sm();
394     if (err != C2_OK)
395     {
396         ALOGW("Failed to flush decoder. Try to hard reset decoder");
397         destroyDecoder();
398         (void)initDecoder();
399     }
400 }
401 
onRelease()402 void C2SoftVpxDec::onRelease() {
403     destroyDecoder();
404 }
405 
onFlush_sm()406 c2_status_t C2SoftVpxDec::onFlush_sm() {
407     if (mFrameParallelMode) {
408         // Flush decoder by passing nullptr data ptr and 0 size.
409         // Ideally, this should never fail.
410         if (vpx_codec_decode(mCodecCtx, nullptr, 0, nullptr, 0)) {
411             ALOGE("Failed to flush on2 decoder.");
412             return C2_CORRUPTED;
413         }
414     }
415 
416     // Drop all the decoded frames in decoder.
417     vpx_codec_iter_t iter = nullptr;
418     while (vpx_codec_get_frame(mCodecCtx, &iter)) {
419     }
420 
421     mSignalledError = false;
422     mSignalledOutputEos = false;
423     return C2_OK;
424 }
425 
GetCPUCoreCount()426 static int GetCPUCoreCount() {
427     int cpuCoreCount = 1;
428 #if defined(_SC_NPROCESSORS_ONLN)
429     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
430 #else
431     // _SC_NPROC_ONLN must be defined...
432     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
433 #endif
434     CHECK(cpuCoreCount >= 1);
435     ALOGV("Number of CPU cores: %d", cpuCoreCount);
436     return cpuCoreCount;
437 }
438 
initDecoder()439 status_t C2SoftVpxDec::initDecoder() {
440 #ifdef VP9
441     mMode = MODE_VP9;
442 #else
443     mMode = MODE_VP8;
444 #endif
445     mHalPixelFormat = HAL_PIXEL_FORMAT_YV12;
446     {
447         IntfImpl::Lock lock = mIntf->lock();
448         mPixelFormatInfo = mIntf->getPixelFormat_l();
449         mColorAspects = mIntf->getDefaultColorAspects_l();
450     }
451 
452     mWidth = 320;
453     mHeight = 240;
454     mFrameParallelMode = false;
455     mSignalledOutputEos = false;
456     mSignalledError = false;
457 
458     if (!mCodecCtx) {
459         mCodecCtx = new vpx_codec_ctx_t;
460     }
461     if (!mCodecCtx) {
462         ALOGE("mCodecCtx is null");
463         return NO_MEMORY;
464     }
465 
466     vpx_codec_dec_cfg_t cfg;
467     memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
468     cfg.threads = mCoreCount = GetCPUCoreCount();
469 
470     vpx_codec_flags_t flags;
471     memset(&flags, 0, sizeof(vpx_codec_flags_t));
472     if (mFrameParallelMode) flags |= VPX_CODEC_USE_FRAME_THREADING;
473 
474     vpx_codec_err_t vpx_err;
475     if ((vpx_err = vpx_codec_dec_init(
476                  mCodecCtx, mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
477                  &cfg, flags))) {
478         ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
479         return UNKNOWN_ERROR;
480     }
481 
482     if (mMode == MODE_VP9) {
483         using namespace std::string_literals;
484         for (int i = 0; i < mCoreCount; ++i) {
485             sp<ConverterThread> thread(new ConverterThread(mQueue));
486             mConverterThreads.push_back(thread);
487             if (thread->run(("vp9conv #"s + std::to_string(i)).c_str(),
488                             ANDROID_PRIORITY_AUDIO) != OK) {
489                 return UNKNOWN_ERROR;
490             }
491         }
492     }
493 
494     return OK;
495 }
496 
destroyDecoder()497 status_t C2SoftVpxDec::destroyDecoder() {
498     if  (mCodecCtx) {
499         vpx_codec_destroy(mCodecCtx);
500         delete mCodecCtx;
501         mCodecCtx = nullptr;
502     }
503     bool running = true;
504     for (const sp<ConverterThread> &thread : mConverterThreads) {
505         thread->requestExit();
506     }
507     while (running) {
508         mQueue->lock()->cond.broadcast();
509         running = false;
510         for (const sp<ConverterThread> &thread : mConverterThreads) {
511             if (thread->isRunning()) {
512                 running = true;
513                 break;
514             }
515         }
516     }
517     mConverterThreads.clear();
518 
519     return OK;
520 }
521 
fillEmptyWork(const std::unique_ptr<C2Work> & work)522 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
523     uint32_t flags = 0;
524     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
525         flags |= C2FrameData::FLAG_END_OF_STREAM;
526         ALOGV("signalling eos");
527     }
528     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
529     work->worklets.front()->output.buffers.clear();
530     work->worklets.front()->output.ordinal = work->input.ordinal;
531     work->workletsProcessed = 1u;
532 }
533 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)534 void C2SoftVpxDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
535                            const std::shared_ptr<C2GraphicBlock> &block) {
536     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
537                                                            C2Rect(mWidth, mHeight));
538     auto fillWork = [buffer, index, intf = this->mIntf](
539             const std::unique_ptr<C2Work> &work) {
540         uint32_t flags = 0;
541         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
542                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
543             flags |= C2FrameData::FLAG_END_OF_STREAM;
544             ALOGV("signalling eos");
545         }
546         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
547         work->worklets.front()->output.buffers.clear();
548         work->worklets.front()->output.buffers.push_back(buffer);
549         work->worklets.front()->output.ordinal = work->input.ordinal;
550         work->workletsProcessed = 1u;
551 
552         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
553             if (param) {
554                 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
555                         C2StreamHdr10PlusInfo::input::From(param.get());
556 
557                 if (hdr10PlusInfo != nullptr) {
558                     std::vector<std::unique_ptr<C2SettingResult>> failures;
559                     std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
560                             *param.get(), true /*output*/, param->stream());
561                     c2_status_t err = intf->config(
562                             { outParam.get() }, C2_MAY_BLOCK, &failures);
563                     if (err == C2_OK) {
564                         work->worklets.front()->output.configUpdate.push_back(
565                                 C2Param::Copy(*outParam.get()));
566                     } else {
567                         ALOGE("finishWork: Config update size failed");
568                     }
569                     break;
570                 }
571             }
572         }
573     };
574     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
575         fillWork(work);
576     } else {
577         finish(index, fillWork);
578     }
579 }
580 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)581 void C2SoftVpxDec::process(
582         const std::unique_ptr<C2Work> &work,
583         const std::shared_ptr<C2BlockPool> &pool) {
584     // Initialize output work
585     work->result = C2_OK;
586     work->workletsProcessed = 0u;
587     work->worklets.front()->output.configUpdate.clear();
588     work->worklets.front()->output.flags = work->input.flags;
589 
590     if (mSignalledError || mSignalledOutputEos) {
591         work->result = C2_BAD_VALUE;
592         return;
593     }
594 
595     // handle dynamic config parameters
596     {
597         IntfImpl::Lock lock = mIntf->lock();
598         std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
599             mIntf->getDefaultColorAspects_l();
600         lock.unlock();
601 
602         if (mColorAspects->range != defaultColorAspects->range ||
603             mColorAspects->primaries != defaultColorAspects->primaries ||
604             mColorAspects->matrix != defaultColorAspects->matrix ||
605             mColorAspects->transfer != defaultColorAspects->transfer) {
606 
607             mColorAspects->range = defaultColorAspects->range;
608             mColorAspects->primaries = defaultColorAspects->primaries;
609             mColorAspects->matrix = defaultColorAspects->matrix;
610             mColorAspects->transfer = defaultColorAspects->transfer;
611 
612             C2StreamColorAspectsTuning::output colorAspect(0u, defaultColorAspects->range,
613                 defaultColorAspects->primaries, defaultColorAspects->transfer,
614                 defaultColorAspects->matrix);
615             std::vector<std::unique_ptr<C2SettingResult>> failures;
616             c2_status_t err = mIntf->config({&colorAspect}, C2_MAY_BLOCK, &failures);
617             if (err == C2_OK) {
618                 work->worklets.front()->output.configUpdate.push_back(
619                     C2Param::Copy(colorAspect));
620             } else {
621                 ALOGE("Config update colorAspect failed");
622                 mSignalledError = true;
623                 work->workletsProcessed = 1u;
624                 work->result = C2_CORRUPTED;
625                 return;
626             }
627         }
628     }
629 
630     size_t inOffset = 0u;
631     size_t inSize = 0u;
632     C2ReadView rView = mDummyReadView;
633     if (!work->input.buffers.empty()) {
634         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
635         inSize = rView.capacity();
636         if (inSize && rView.error()) {
637             ALOGE("read view map failed %d", rView.error());
638             work->result = C2_CORRUPTED;
639             return;
640         }
641     }
642 
643     bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) !=0);
644     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
645 
646     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
647           inSize, (int)work->input.ordinal.timestamp.peeku(),
648           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
649 
650     // Software VP9 Decoder does not need the Codec Specific Data (CSD)
651     // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
652     // it was passed.
653     if (codecConfig) {
654         // Ignore CSD buffer for VP9.
655         if (mMode == MODE_VP9) {
656             fillEmptyWork(work);
657             return;
658         } else {
659             // Tolerate the CSD buffer for VP8. This is a workaround
660             // for b/28689536. continue
661             ALOGW("WARNING: Got CSD buffer for VP8. Continue");
662         }
663     }
664 
665     if (inSize) {
666         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
667         vpx_codec_err_t err = vpx_codec_decode(
668                 mCodecCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
669         if (err != VPX_CODEC_OK) {
670             ALOGE("on2 decoder failed to decode frame. err: %d", err);
671             mSignalledError = true;
672             work->workletsProcessed = 1u;
673             work->result = C2_CORRUPTED;
674             return;
675         }
676     }
677 
678     status_t err = outputBuffer(pool, work);
679     if (err == NOT_ENOUGH_DATA) {
680         if (inSize > 0) {
681             ALOGV("Maybe non-display frame at %lld.",
682                   work->input.ordinal.frameIndex.peekll());
683             // send the work back with empty buffer.
684             inSize = 0;
685         }
686     } else if (err != OK) {
687         ALOGD("Error while getting the output frame out");
688         // work->result would be already filled; do fillEmptyWork() below to
689         // send the work back.
690         inSize = 0;
691     }
692 
693     if (eos) {
694         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
695         mSignalledOutputEos = true;
696     } else if (!inSize) {
697         fillEmptyWork(work);
698     }
699 }
700 
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)701 status_t C2SoftVpxDec::outputBuffer(
702         const std::shared_ptr<C2BlockPool> &pool,
703         const std::unique_ptr<C2Work> &work)
704 {
705     if (!(work && pool)) return BAD_VALUE;
706 
707     vpx_codec_iter_t iter = nullptr;
708     vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
709 
710     if (!img) return NOT_ENOUGH_DATA;
711 
712     if (img->d_w != mWidth || img->d_h != mHeight) {
713         mWidth = img->d_w;
714         mHeight = img->d_h;
715 
716         C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
717         std::vector<std::unique_ptr<C2SettingResult>> failures;
718         c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
719         if (err == C2_OK) {
720             work->worklets.front()->output.configUpdate.push_back(
721                 C2Param::Copy(size));
722         } else {
723             ALOGE("Config update size failed");
724             mSignalledError = true;
725             work->workletsProcessed = 1u;
726             work->result = C2_CORRUPTED;
727             return UNKNOWN_ERROR;
728         }
729 
730     }
731     if(img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_I42016) {
732         ALOGE("img->fmt %d not supported", img->fmt);
733         mSignalledError = true;
734         work->workletsProcessed = 1u;
735         work->result = C2_CORRUPTED;
736         return false;
737     }
738 
739     std::shared_ptr<C2GraphicBlock> block;
740     uint32_t format = HAL_PIXEL_FORMAT_YV12;
741     std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects;
742     if (img->fmt == VPX_IMG_FMT_I42016 &&
743             mPixelFormatInfo->value != HAL_PIXEL_FORMAT_YCBCR_420_888) {
744         IntfImpl::Lock lock = mIntf->lock();
745         defaultColorAspects = mIntf->getDefaultColorAspects_l();
746         bool allowRGBA1010102 = false;
747         if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
748             defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
749             defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
750             allowRGBA1010102 = true;
751         }
752         format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
753     }
754 
755     if (mHalPixelFormat != format) {
756         C2StreamPixelFormatInfo::output pixelFormat(0u, format);
757         std::vector<std::unique_ptr<C2SettingResult>> failures;
758         c2_status_t err = mIntf->config({&pixelFormat }, C2_MAY_BLOCK, &failures);
759         if (err == C2_OK) {
760             work->worklets.front()->output.configUpdate.push_back(
761                 C2Param::Copy(pixelFormat));
762         } else {
763             ALOGE("Config update pixelFormat failed");
764             mSignalledError = true;
765             work->workletsProcessed = 1u;
766             work->result = C2_CORRUPTED;
767             return UNKNOWN_ERROR;
768         }
769         mHalPixelFormat = format;
770     }
771 
772     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
773     // We always create a graphic block that is width aligned to 16 and height
774     // aligned to 2. We set the correct "crop" value of the image in the call to
775     // createGraphicBuffer() by setting the correct image dimensions.
776     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16),
777                                               align(mHeight, 2), format, usage,
778                                               &block);
779     if (err != C2_OK) {
780         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
781         work->result = err;
782         return UNKNOWN_ERROR;
783     }
784 
785     C2GraphicView wView = block->map().get();
786     if (wView.error()) {
787         ALOGE("graphic view map failed %d", wView.error());
788         work->result = C2_CORRUPTED;
789         return UNKNOWN_ERROR;
790     }
791 
792     ALOGV("provided (%dx%d) required (%dx%d), out frameindex %lld",
793            block->width(), block->height(), mWidth, mHeight,
794            ((c2_cntr64_t *)img->user_priv)->peekll());
795 
796     uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
797     uint8_t *dstU = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
798     uint8_t *dstV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_V]);
799 
800     size_t srcYStride = img->stride[VPX_PLANE_Y];
801     size_t srcUStride = img->stride[VPX_PLANE_U];
802     size_t srcVStride = img->stride[VPX_PLANE_V];
803     C2PlanarLayout layout = wView.layout();
804     size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
805     size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
806     size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
807 
808     if (img->fmt == VPX_IMG_FMT_I42016) {
809         const uint16_t *srcY = (const uint16_t *)img->planes[VPX_PLANE_Y];
810         const uint16_t *srcU = (const uint16_t *)img->planes[VPX_PLANE_U];
811         const uint16_t *srcV = (const uint16_t *)img->planes[VPX_PLANE_V];
812 
813         if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
814             Mutexed<ConversionQueue>::Locked queue(*mQueue);
815             size_t i = 0;
816             constexpr size_t kHeight = 64;
817             for (; i < mHeight; i += kHeight) {
818                 queue->entries.push_back(
819                         [dstY, srcY, srcU, srcV,
820                          srcYStride, srcUStride, srcVStride, dstYStride,
821                          width = mWidth, height = std::min(mHeight - i, kHeight),
822                          defaultColorAspects] {
823                             convertYUV420Planar16ToY410OrRGBA1010102(
824                                     (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2,
825                                     srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t),
826                                     width, height,
827                                     std::static_pointer_cast<const C2ColorAspectsStruct>(
828                                             defaultColorAspects));
829                         });
830                 srcY += srcYStride / 2 * kHeight;
831                 srcU += srcUStride / 2 * (kHeight / 2);
832                 srcV += srcVStride / 2 * (kHeight / 2);
833                 dstY += dstYStride * kHeight;
834             }
835             CHECK_EQ(0u, queue->numPending);
836             queue->numPending = queue->entries.size();
837             while (queue->numPending > 0) {
838                 queue->cond.signal();
839                 queue.waitForCondition(queue->cond);
840             }
841         } else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
842             convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
843                                         srcYStride / 2, srcUStride / 2, srcVStride / 2,
844                                         dstYStride / 2, dstUStride / 2, mWidth, mHeight);
845         } else {
846             convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
847                                         srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
848                                         mWidth, mHeight);
849         }
850     } else {
851         const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
852         const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
853         const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
854 
855         convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
856                                    srcVStride, dstYStride, dstVStride, dstVStride, mWidth, mHeight);
857     }
858     finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
859     return OK;
860 }
861 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)862 c2_status_t C2SoftVpxDec::drainInternal(
863         uint32_t drainMode,
864         const std::shared_ptr<C2BlockPool> &pool,
865         const std::unique_ptr<C2Work> &work) {
866     if (drainMode == NO_DRAIN) {
867         ALOGW("drain with NO_DRAIN: no-op");
868         return C2_OK;
869     }
870     if (drainMode == DRAIN_CHAIN) {
871         ALOGW("DRAIN_CHAIN not supported");
872         return C2_OMITTED;
873     }
874 
875     while (outputBuffer(pool, work) == OK) {
876     }
877 
878     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
879             work && work->workletsProcessed == 0u) {
880         fillEmptyWork(work);
881     }
882 
883     return C2_OK;
884 }
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)885 c2_status_t C2SoftVpxDec::drain(
886         uint32_t drainMode,
887         const std::shared_ptr<C2BlockPool> &pool) {
888     return drainInternal(drainMode, pool, nullptr);
889 }
890 
891 class C2SoftVpxFactory : public C2ComponentFactory {
892 public:
C2SoftVpxFactory()893     C2SoftVpxFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
894         GetCodec2PlatformComponentStore()->getParamReflector())) {
895     }
896 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)897     virtual c2_status_t createComponent(
898             c2_node_id_t id,
899             std::shared_ptr<C2Component>* const component,
900             std::function<void(C2Component*)> deleter) override {
901         *component = std::shared_ptr<C2Component>(
902             new C2SoftVpxDec(COMPONENT_NAME, id,
903                           std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
904             deleter);
905         return C2_OK;
906     }
907 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)908     virtual c2_status_t createInterface(
909             c2_node_id_t id,
910             std::shared_ptr<C2ComponentInterface>* const interface,
911             std::function<void(C2ComponentInterface*)> deleter) override {
912         *interface = std::shared_ptr<C2ComponentInterface>(
913             new SimpleInterface<C2SoftVpxDec::IntfImpl>(
914                 COMPONENT_NAME, id,
915                 std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
916             deleter);
917         return C2_OK;
918     }
919 
920     virtual ~C2SoftVpxFactory() override = default;
921 
922 private:
923     std::shared_ptr<C2ReflectorHelper> mHelper;
924 };
925 
926 }  // namespace android
927 
928 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()929 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
930     ALOGV("in %s", __func__);
931     return new ::android::C2SoftVpxFactory();
932 }
933 
934 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)935 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
936     ALOGV("in %s", __func__);
937     delete factory;
938 }
939