• 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 "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, 2),
73                     C2F(mSize, height).inRange(2, 2048, 2),
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     }
450 
451     mWidth = 320;
452     mHeight = 240;
453     mFrameParallelMode = false;
454     mSignalledOutputEos = false;
455     mSignalledError = false;
456 
457     if (!mCodecCtx) {
458         mCodecCtx = new vpx_codec_ctx_t;
459     }
460     if (!mCodecCtx) {
461         ALOGE("mCodecCtx is null");
462         return NO_MEMORY;
463     }
464 
465     vpx_codec_dec_cfg_t cfg;
466     memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
467     cfg.threads = mCoreCount = GetCPUCoreCount();
468 
469     vpx_codec_flags_t flags;
470     memset(&flags, 0, sizeof(vpx_codec_flags_t));
471     if (mFrameParallelMode) flags |= VPX_CODEC_USE_FRAME_THREADING;
472 
473     vpx_codec_err_t vpx_err;
474     if ((vpx_err = vpx_codec_dec_init(
475                  mCodecCtx, mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
476                  &cfg, flags))) {
477         ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
478         return UNKNOWN_ERROR;
479     }
480 
481     if (mMode == MODE_VP9) {
482         using namespace std::string_literals;
483         for (int i = 0; i < mCoreCount; ++i) {
484             sp<ConverterThread> thread(new ConverterThread(mQueue));
485             mConverterThreads.push_back(thread);
486             if (thread->run(("vp9conv #"s + std::to_string(i)).c_str(),
487                             ANDROID_PRIORITY_AUDIO) != OK) {
488                 return UNKNOWN_ERROR;
489             }
490         }
491     }
492 
493     return OK;
494 }
495 
destroyDecoder()496 status_t C2SoftVpxDec::destroyDecoder() {
497     if  (mCodecCtx) {
498         vpx_codec_destroy(mCodecCtx);
499         delete mCodecCtx;
500         mCodecCtx = nullptr;
501     }
502     bool running = true;
503     for (const sp<ConverterThread> &thread : mConverterThreads) {
504         thread->requestExit();
505     }
506     while (running) {
507         mQueue->lock()->cond.broadcast();
508         running = false;
509         for (const sp<ConverterThread> &thread : mConverterThreads) {
510             if (thread->isRunning()) {
511                 running = true;
512                 break;
513             }
514         }
515     }
516     mConverterThreads.clear();
517 
518     return OK;
519 }
520 
fillEmptyWork(const std::unique_ptr<C2Work> & work)521 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
522     uint32_t flags = 0;
523     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
524         flags |= C2FrameData::FLAG_END_OF_STREAM;
525         ALOGV("signalling eos");
526     }
527     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
528     work->worklets.front()->output.buffers.clear();
529     work->worklets.front()->output.ordinal = work->input.ordinal;
530     work->workletsProcessed = 1u;
531 }
532 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)533 void C2SoftVpxDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
534                            const std::shared_ptr<C2GraphicBlock> &block) {
535     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
536                                                            C2Rect(mWidth, mHeight));
537     auto fillWork = [buffer, index, intf = this->mIntf](
538             const std::unique_ptr<C2Work> &work) {
539         uint32_t flags = 0;
540         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
541                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
542             flags |= C2FrameData::FLAG_END_OF_STREAM;
543             ALOGV("signalling eos");
544         }
545         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
546         work->worklets.front()->output.buffers.clear();
547         work->worklets.front()->output.buffers.push_back(buffer);
548         work->worklets.front()->output.ordinal = work->input.ordinal;
549         work->workletsProcessed = 1u;
550 
551         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
552             if (param) {
553                 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
554                         C2StreamHdr10PlusInfo::input::From(param.get());
555 
556                 if (hdr10PlusInfo != nullptr) {
557                     std::vector<std::unique_ptr<C2SettingResult>> failures;
558                     std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
559                             *param.get(), true /*output*/, param->stream());
560                     c2_status_t err = intf->config(
561                             { outParam.get() }, C2_MAY_BLOCK, &failures);
562                     if (err == C2_OK) {
563                         work->worklets.front()->output.configUpdate.push_back(
564                                 C2Param::Copy(*outParam.get()));
565                     } else {
566                         ALOGE("finishWork: Config update size failed");
567                     }
568                     break;
569                 }
570             }
571         }
572     };
573     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
574         fillWork(work);
575     } else {
576         finish(index, fillWork);
577     }
578 }
579 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)580 void C2SoftVpxDec::process(
581         const std::unique_ptr<C2Work> &work,
582         const std::shared_ptr<C2BlockPool> &pool) {
583     // Initialize output work
584     work->result = C2_OK;
585     work->workletsProcessed = 0u;
586     work->worklets.front()->output.configUpdate.clear();
587     work->worklets.front()->output.flags = work->input.flags;
588 
589     if (mSignalledError || mSignalledOutputEos) {
590         work->result = C2_BAD_VALUE;
591         return;
592     }
593 
594     size_t inOffset = 0u;
595     size_t inSize = 0u;
596     C2ReadView rView = mDummyReadView;
597     if (!work->input.buffers.empty()) {
598         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
599         inSize = rView.capacity();
600         if (inSize && rView.error()) {
601             ALOGE("read view map failed %d", rView.error());
602             work->result = C2_CORRUPTED;
603             return;
604         }
605     }
606 
607     bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) !=0);
608     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
609 
610     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
611           inSize, (int)work->input.ordinal.timestamp.peeku(),
612           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
613 
614     // Software VP9 Decoder does not need the Codec Specific Data (CSD)
615     // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
616     // it was passed.
617     if (codecConfig) {
618         // Ignore CSD buffer for VP9.
619         if (mMode == MODE_VP9) {
620             fillEmptyWork(work);
621             return;
622         } else {
623             // Tolerate the CSD buffer for VP8. This is a workaround
624             // for b/28689536. continue
625             ALOGW("WARNING: Got CSD buffer for VP8. Continue");
626         }
627     }
628 
629     if (inSize) {
630         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
631         vpx_codec_err_t err = vpx_codec_decode(
632                 mCodecCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
633         if (err != VPX_CODEC_OK) {
634             ALOGE("on2 decoder failed to decode frame. err: %d", err);
635             mSignalledError = true;
636             work->workletsProcessed = 1u;
637             work->result = C2_CORRUPTED;
638             return;
639         }
640     }
641 
642     status_t err = outputBuffer(pool, work);
643     if (err == NOT_ENOUGH_DATA) {
644         if (inSize > 0) {
645             ALOGV("Maybe non-display frame at %lld.",
646                   work->input.ordinal.frameIndex.peekll());
647             // send the work back with empty buffer.
648             inSize = 0;
649         }
650     } else if (err != OK) {
651         ALOGD("Error while getting the output frame out");
652         // work->result would be already filled; do fillEmptyWork() below to
653         // send the work back.
654         inSize = 0;
655     }
656 
657     if (eos) {
658         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
659         mSignalledOutputEos = true;
660     } else if (!inSize) {
661         fillEmptyWork(work);
662     }
663 }
664 
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)665 status_t C2SoftVpxDec::outputBuffer(
666         const std::shared_ptr<C2BlockPool> &pool,
667         const std::unique_ptr<C2Work> &work)
668 {
669     if (!(work && pool)) return BAD_VALUE;
670 
671     vpx_codec_iter_t iter = nullptr;
672     vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
673 
674     if (!img) return NOT_ENOUGH_DATA;
675 
676     if (img->d_w != mWidth || img->d_h != mHeight) {
677         mWidth = img->d_w;
678         mHeight = img->d_h;
679 
680         C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
681         std::vector<std::unique_ptr<C2SettingResult>> failures;
682         c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
683         if (err == C2_OK) {
684             work->worklets.front()->output.configUpdate.push_back(
685                 C2Param::Copy(size));
686         } else {
687             ALOGE("Config update size failed");
688             mSignalledError = true;
689             work->workletsProcessed = 1u;
690             work->result = C2_CORRUPTED;
691             return UNKNOWN_ERROR;
692         }
693 
694     }
695     if(img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_I42016) {
696         ALOGE("img->fmt %d not supported", img->fmt);
697         mSignalledError = true;
698         work->workletsProcessed = 1u;
699         work->result = C2_CORRUPTED;
700         return false;
701     }
702 
703     std::shared_ptr<C2GraphicBlock> block;
704     uint32_t format = HAL_PIXEL_FORMAT_YV12;
705     std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects;
706     if (img->fmt == VPX_IMG_FMT_I42016 &&
707             mPixelFormatInfo->value != HAL_PIXEL_FORMAT_YCBCR_420_888) {
708         IntfImpl::Lock lock = mIntf->lock();
709         defaultColorAspects = mIntf->getDefaultColorAspects_l();
710         bool allowRGBA1010102 = false;
711         if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
712             defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
713             defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
714             allowRGBA1010102 = true;
715         }
716         format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
717     }
718 
719     if (mHalPixelFormat != format) {
720         C2StreamPixelFormatInfo::output pixelFormat(0u, format);
721         std::vector<std::unique_ptr<C2SettingResult>> failures;
722         c2_status_t err = mIntf->config({&pixelFormat }, C2_MAY_BLOCK, &failures);
723         if (err == C2_OK) {
724             work->worklets.front()->output.configUpdate.push_back(
725                 C2Param::Copy(pixelFormat));
726         } else {
727             ALOGE("Config update pixelFormat failed");
728             mSignalledError = true;
729             work->workletsProcessed = 1u;
730             work->result = C2_CORRUPTED;
731             return UNKNOWN_ERROR;
732         }
733         mHalPixelFormat = format;
734     }
735 
736     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
737     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &block);
738     if (err != C2_OK) {
739         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
740         work->result = err;
741         return UNKNOWN_ERROR;
742     }
743 
744     C2GraphicView wView = block->map().get();
745     if (wView.error()) {
746         ALOGE("graphic view map failed %d", wView.error());
747         work->result = C2_CORRUPTED;
748         return UNKNOWN_ERROR;
749     }
750 
751     ALOGV("provided (%dx%d) required (%dx%d), out frameindex %lld",
752            block->width(), block->height(), mWidth, mHeight,
753            ((c2_cntr64_t *)img->user_priv)->peekll());
754 
755     uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
756     uint8_t *dstU = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
757     uint8_t *dstV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_V]);
758 
759     size_t srcYStride = img->stride[VPX_PLANE_Y];
760     size_t srcUStride = img->stride[VPX_PLANE_U];
761     size_t srcVStride = img->stride[VPX_PLANE_V];
762     C2PlanarLayout layout = wView.layout();
763     size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
764     size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
765 
766     if (img->fmt == VPX_IMG_FMT_I42016) {
767         const uint16_t *srcY = (const uint16_t *)img->planes[VPX_PLANE_Y];
768         const uint16_t *srcU = (const uint16_t *)img->planes[VPX_PLANE_U];
769         const uint16_t *srcV = (const uint16_t *)img->planes[VPX_PLANE_V];
770 
771         if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
772             Mutexed<ConversionQueue>::Locked queue(*mQueue);
773             size_t i = 0;
774             constexpr size_t kHeight = 64;
775             for (; i < mHeight; i += kHeight) {
776                 queue->entries.push_back(
777                         [dstY, srcY, srcU, srcV,
778                          srcYStride, srcUStride, srcVStride, dstYStride,
779                          width = mWidth, height = std::min(mHeight - i, kHeight),
780                          defaultColorAspects] {
781                             convertYUV420Planar16ToY410OrRGBA1010102(
782                                     (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2,
783                                     srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t),
784                                     width, height,
785                                     std::static_pointer_cast<const C2ColorAspectsStruct>(
786                                             defaultColorAspects));
787                         });
788                 srcY += srcYStride / 2 * kHeight;
789                 srcU += srcUStride / 2 * (kHeight / 2);
790                 srcV += srcVStride / 2 * (kHeight / 2);
791                 dstY += dstYStride * kHeight;
792             }
793             CHECK_EQ(0u, queue->numPending);
794             queue->numPending = queue->entries.size();
795             while (queue->numPending > 0) {
796                 queue->cond.signal();
797                 queue.waitForCondition(queue->cond);
798             }
799         } else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
800             convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
801                                         srcYStride / 2, srcUStride / 2, srcVStride / 2,
802                                         dstYStride / 2, dstUVStride / 2, mWidth, mHeight);
803         } else {
804             convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
805                                         srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
806                                         mWidth, mHeight);
807         }
808     } else {
809         const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
810         const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
811         const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
812 
813         convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
814                                    srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
815     }
816     finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
817     return OK;
818 }
819 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)820 c2_status_t C2SoftVpxDec::drainInternal(
821         uint32_t drainMode,
822         const std::shared_ptr<C2BlockPool> &pool,
823         const std::unique_ptr<C2Work> &work) {
824     if (drainMode == NO_DRAIN) {
825         ALOGW("drain with NO_DRAIN: no-op");
826         return C2_OK;
827     }
828     if (drainMode == DRAIN_CHAIN) {
829         ALOGW("DRAIN_CHAIN not supported");
830         return C2_OMITTED;
831     }
832 
833     while (outputBuffer(pool, work) == OK) {
834     }
835 
836     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
837             work && work->workletsProcessed == 0u) {
838         fillEmptyWork(work);
839     }
840 
841     return C2_OK;
842 }
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)843 c2_status_t C2SoftVpxDec::drain(
844         uint32_t drainMode,
845         const std::shared_ptr<C2BlockPool> &pool) {
846     return drainInternal(drainMode, pool, nullptr);
847 }
848 
849 class C2SoftVpxFactory : public C2ComponentFactory {
850 public:
C2SoftVpxFactory()851     C2SoftVpxFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
852         GetCodec2PlatformComponentStore()->getParamReflector())) {
853     }
854 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)855     virtual c2_status_t createComponent(
856             c2_node_id_t id,
857             std::shared_ptr<C2Component>* const component,
858             std::function<void(C2Component*)> deleter) override {
859         *component = std::shared_ptr<C2Component>(
860             new C2SoftVpxDec(COMPONENT_NAME, id,
861                           std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
862             deleter);
863         return C2_OK;
864     }
865 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)866     virtual c2_status_t createInterface(
867             c2_node_id_t id,
868             std::shared_ptr<C2ComponentInterface>* const interface,
869             std::function<void(C2ComponentInterface*)> deleter) override {
870         *interface = std::shared_ptr<C2ComponentInterface>(
871             new SimpleInterface<C2SoftVpxDec::IntfImpl>(
872                 COMPONENT_NAME, id,
873                 std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
874             deleter);
875         return C2_OK;
876     }
877 
878     virtual ~C2SoftVpxFactory() override = default;
879 
880 private:
881     std::shared_ptr<C2ReflectorHelper> mHelper;
882 };
883 
884 }  // namespace android
885 
886 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()887 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
888     ALOGV("in %s", __func__);
889     return new ::android::C2SoftVpxFactory();
890 }
891 
892 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)893 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
894     ALOGV("in %s", __func__);
895     delete factory;
896 }
897