• 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 <media/stagefright/foundation/AUtils.h>
22 #include <media/stagefright/foundation/MediaDefs.h>
23 
24 #include <C2Debug.h>
25 #include <C2PlatformSupport.h>
26 #include <SimpleC2Interface.h>
27 
28 #include "C2SoftVpxDec.h"
29 
30 namespace android {
31 
32 #ifdef VP9
33 constexpr char COMPONENT_NAME[] = "c2.android.vp9.decoder";
34 #else
35 constexpr char COMPONENT_NAME[] = "c2.android.vp8.decoder";
36 #endif
37 
38 class C2SoftVpxDec::IntfImpl : public SimpleInterface<void>::BaseParams {
39 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)40     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
41         : SimpleInterface<void>::BaseParams(
42                 helper,
43                 COMPONENT_NAME,
44                 C2Component::KIND_DECODER,
45                 C2Component::DOMAIN_VIDEO,
46 #ifdef VP9
47                 MEDIA_MIMETYPE_VIDEO_VP9
48 #else
49                 MEDIA_MIMETYPE_VIDEO_VP8
50 #endif
51                 ) {
52         noPrivateBuffers(); // TODO: account for our buffers here
53         noInputReferences();
54         noOutputReferences();
55         noInputLatency();
56         noTimeStretch();
57 
58         // TODO: output latency and reordering
59 
60         addParameter(
61                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
62                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
63                 .build());
64 
65         addParameter(
66                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
67                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
68                 .withFields({
69                     C2F(mSize, width).inRange(2, 2048, 2),
70                     C2F(mSize, height).inRange(2, 2048, 2),
71                 })
72                 .withSetter(SizeSetter)
73                 .build());
74 
75 #ifdef VP9
76         // TODO: Add C2Config::PROFILE_VP9_2HDR ??
77         addParameter(
78                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
79                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
80                         C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5))
81                 .withFields({
82                     C2F(mProfileLevel, profile).oneOf({
83                             C2Config::PROFILE_VP9_0,
84                             C2Config::PROFILE_VP9_2}),
85                     C2F(mProfileLevel, level).oneOf({
86                             C2Config::LEVEL_VP9_1,
87                             C2Config::LEVEL_VP9_1_1,
88                             C2Config::LEVEL_VP9_2,
89                             C2Config::LEVEL_VP9_2_1,
90                             C2Config::LEVEL_VP9_3,
91                             C2Config::LEVEL_VP9_3_1,
92                             C2Config::LEVEL_VP9_4,
93                             C2Config::LEVEL_VP9_4_1,
94                             C2Config::LEVEL_VP9_5,
95                     })
96                 })
97                 .withSetter(ProfileLevelSetter, mSize)
98                 .build());
99 
100         mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
101         addParameter(
102                 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
103                 .withDefault(mHdr10PlusInfoInput)
104                 .withFields({
105                     C2F(mHdr10PlusInfoInput, m.value).any(),
106                 })
107                 .withSetter(Hdr10PlusInfoInputSetter)
108                 .build());
109 
110         mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
111         addParameter(
112                 DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
113                 .withDefault(mHdr10PlusInfoOutput)
114                 .withFields({
115                     C2F(mHdr10PlusInfoOutput, m.value).any(),
116                 })
117                 .withSetter(Hdr10PlusInfoOutputSetter)
118                 .build());
119 
120 #if 0
121         // sample BT.2020 static info
122         mHdrStaticInfo = std::make_shared<C2StreamHdrStaticInfo::output>();
123         mHdrStaticInfo->mastering = {
124             .red   = { .x = 0.708,  .y = 0.292 },
125             .green = { .x = 0.170,  .y = 0.797 },
126             .blue  = { .x = 0.131,  .y = 0.046 },
127             .white = { .x = 0.3127, .y = 0.3290 },
128             .maxLuminance = 1000,
129             .minLuminance = 0.1,
130         };
131         mHdrStaticInfo->maxCll = 1000;
132         mHdrStaticInfo->maxFall = 120;
133 
134         mHdrStaticInfo->maxLuminance = 0; // disable static info
135 
136         helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
137         addParameter(
138                 DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
139                 .withDefault(mHdrStaticInfo)
140                 .withFields({
141                     C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
142                     // TODO
143                 })
144                 .withSetter(HdrStaticInfoSetter)
145                 .build());
146 #endif
147 #else
148         addParameter(
149                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
150                 .withConstValue(new C2StreamProfileLevelInfo::input(0u,
151                         C2Config::PROFILE_UNUSED, C2Config::LEVEL_UNUSED))
152                 .build());
153 #endif
154 
155         addParameter(
156                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
157                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
158                 .withFields({
159                     C2F(mSize, width).inRange(2, 2048, 2),
160                     C2F(mSize, height).inRange(2, 2048, 2),
161                 })
162                 .withSetter(MaxPictureSizeSetter, mSize)
163                 .build());
164 
165         addParameter(
166                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
167                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
168                 .withFields({
169                     C2F(mMaxInputSize, value).any(),
170                 })
171                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
172                 .build());
173 
174         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
175         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
176             C2StreamColorInfo::output::AllocShared(
177                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
178         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
179 
180         defaultColorInfo =
181             C2StreamColorInfo::output::AllocShared(
182                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
183                     0u, 8u /* bitDepth */, C2Color::YUV_420);
184         helper->addStructDescriptors<C2ChromaOffsetStruct>();
185 
186         addParameter(
187                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
188                 .withConstValue(defaultColorInfo)
189                 .build());
190 
191         // TODO: support more formats?
192         addParameter(
193                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
194                 .withConstValue(new C2StreamPixelFormatInfo::output(
195                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
196                 .build());
197     }
198 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2VideoSizeStreamInfo::output> & me)199     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
200                           C2P<C2VideoSizeStreamInfo::output> &me) {
201         (void)mayBlock;
202         C2R res = C2R::Ok();
203         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
204             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
205             me.set().width = oldMe.v.width;
206         }
207         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
208             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
209             me.set().height = oldMe.v.height;
210         }
211         return res;
212     }
213 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)214     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
215                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
216         (void)mayBlock;
217         // TODO: get max width/height from the size's field helpers vs. hardcoding
218         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 2048u);
219         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 2048u);
220         return C2R::Ok();
221     }
222 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)223     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
224                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
225         (void)mayBlock;
226         // assume compression ratio of 2
227         me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
228         return C2R::Ok();
229     }
230 
231 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)232     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
233                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
234         (void)mayBlock;
235         (void)size;
236         (void)me;  // TODO: validate
237         return C2R::Ok();
238     }
239 
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)240     static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input> &me) {
241         (void)mayBlock;
242         (void)me;  // TODO: validate
243         return C2R::Ok();
244     }
245 
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)246     static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output> &me) {
247         (void)mayBlock;
248         (void)me;  // TODO: validate
249         return C2R::Ok();
250     }
251 
252 private:
253     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
254     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
255     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
256     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
257     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
258     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
259 #ifdef VP9
260 #if 0
261     std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
262 #endif
263     std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
264     std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
265 #endif
266 };
267 
C2SoftVpxDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)268 C2SoftVpxDec::C2SoftVpxDec(
269         const char *name,
270         c2_node_id_t id,
271         const std::shared_ptr<IntfImpl> &intfImpl)
272     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
273       mIntf(intfImpl),
274       mCodecCtx(nullptr) {
275 }
276 
~C2SoftVpxDec()277 C2SoftVpxDec::~C2SoftVpxDec() {
278     onRelease();
279 }
280 
onInit()281 c2_status_t C2SoftVpxDec::onInit() {
282     status_t err = initDecoder();
283     return err == OK ? C2_OK : C2_CORRUPTED;
284 }
285 
onStop()286 c2_status_t C2SoftVpxDec::onStop() {
287     mSignalledError = false;
288     mSignalledOutputEos = false;
289 
290     return C2_OK;
291 }
292 
onReset()293 void C2SoftVpxDec::onReset() {
294     (void)onStop();
295     c2_status_t err = onFlush_sm();
296     if (err != C2_OK)
297     {
298         ALOGW("Failed to flush decoder. Try to hard reset decoder");
299         destroyDecoder();
300         (void)initDecoder();
301     }
302 }
303 
onRelease()304 void C2SoftVpxDec::onRelease() {
305     destroyDecoder();
306 }
307 
onFlush_sm()308 c2_status_t C2SoftVpxDec::onFlush_sm() {
309     if (mFrameParallelMode) {
310         // Flush decoder by passing nullptr data ptr and 0 size.
311         // Ideally, this should never fail.
312         if (vpx_codec_decode(mCodecCtx, nullptr, 0, nullptr, 0)) {
313             ALOGE("Failed to flush on2 decoder.");
314             return C2_CORRUPTED;
315         }
316     }
317 
318     // Drop all the decoded frames in decoder.
319     vpx_codec_iter_t iter = nullptr;
320     while (vpx_codec_get_frame(mCodecCtx, &iter)) {
321     }
322 
323     mSignalledError = false;
324     mSignalledOutputEos = false;
325     return C2_OK;
326 }
327 
GetCPUCoreCount()328 static int GetCPUCoreCount() {
329     int cpuCoreCount = 1;
330 #if defined(_SC_NPROCESSORS_ONLN)
331     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
332 #else
333     // _SC_NPROC_ONLN must be defined...
334     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
335 #endif
336     CHECK(cpuCoreCount >= 1);
337     ALOGV("Number of CPU cores: %d", cpuCoreCount);
338     return cpuCoreCount;
339 }
340 
initDecoder()341 status_t C2SoftVpxDec::initDecoder() {
342 #ifdef VP9
343     mMode = MODE_VP9;
344 #else
345     mMode = MODE_VP8;
346 #endif
347 
348     mWidth = 320;
349     mHeight = 240;
350     mFrameParallelMode = false;
351     mSignalledOutputEos = false;
352     mSignalledError = false;
353 
354     if (!mCodecCtx) {
355         mCodecCtx = new vpx_codec_ctx_t;
356     }
357     if (!mCodecCtx) {
358         ALOGE("mCodecCtx is null");
359         return NO_MEMORY;
360     }
361 
362     vpx_codec_dec_cfg_t cfg;
363     memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
364     cfg.threads = GetCPUCoreCount();
365 
366     vpx_codec_flags_t flags;
367     memset(&flags, 0, sizeof(vpx_codec_flags_t));
368     if (mFrameParallelMode) flags |= VPX_CODEC_USE_FRAME_THREADING;
369 
370     vpx_codec_err_t vpx_err;
371     if ((vpx_err = vpx_codec_dec_init(
372                  mCodecCtx, mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
373                  &cfg, flags))) {
374         ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
375         return UNKNOWN_ERROR;
376     }
377 
378     return OK;
379 }
380 
destroyDecoder()381 status_t C2SoftVpxDec::destroyDecoder() {
382     if  (mCodecCtx) {
383         vpx_codec_destroy(mCodecCtx);
384         delete mCodecCtx;
385         mCodecCtx = nullptr;
386     }
387 
388     return OK;
389 }
390 
fillEmptyWork(const std::unique_ptr<C2Work> & work)391 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
392     uint32_t flags = 0;
393     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
394         flags |= C2FrameData::FLAG_END_OF_STREAM;
395         ALOGV("signalling eos");
396     }
397     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
398     work->worklets.front()->output.buffers.clear();
399     work->worklets.front()->output.ordinal = work->input.ordinal;
400     work->workletsProcessed = 1u;
401 }
402 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)403 void C2SoftVpxDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
404                            const std::shared_ptr<C2GraphicBlock> &block) {
405     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block,
406                                                            C2Rect(mWidth, mHeight));
407     auto fillWork = [buffer, index, intf = this->mIntf](
408             const std::unique_ptr<C2Work> &work) {
409         uint32_t flags = 0;
410         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
411                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
412             flags |= C2FrameData::FLAG_END_OF_STREAM;
413             ALOGV("signalling eos");
414         }
415         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
416         work->worklets.front()->output.buffers.clear();
417         work->worklets.front()->output.buffers.push_back(buffer);
418         work->worklets.front()->output.ordinal = work->input.ordinal;
419         work->workletsProcessed = 1u;
420 
421         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
422             if (param) {
423                 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
424                         C2StreamHdr10PlusInfo::input::From(param.get());
425 
426                 if (hdr10PlusInfo != nullptr) {
427                     std::vector<std::unique_ptr<C2SettingResult>> failures;
428                     std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
429                             *param.get(), true /*output*/, param->stream());
430                     c2_status_t err = intf->config(
431                             { outParam.get() }, C2_MAY_BLOCK, &failures);
432                     if (err == C2_OK) {
433                         work->worklets.front()->output.configUpdate.push_back(
434                                 C2Param::Copy(*outParam.get()));
435                     } else {
436                         ALOGE("finishWork: Config update size failed");
437                     }
438                     break;
439                 }
440             }
441         }
442     };
443     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
444         fillWork(work);
445     } else {
446         finish(index, fillWork);
447     }
448 }
449 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)450 void C2SoftVpxDec::process(
451         const std::unique_ptr<C2Work> &work,
452         const std::shared_ptr<C2BlockPool> &pool) {
453     // Initialize output work
454     work->result = C2_OK;
455     work->workletsProcessed = 0u;
456     work->worklets.front()->output.configUpdate.clear();
457     work->worklets.front()->output.flags = work->input.flags;
458 
459     if (mSignalledError || mSignalledOutputEos) {
460         work->result = C2_BAD_VALUE;
461         return;
462     }
463 
464     size_t inOffset = 0u;
465     size_t inSize = 0u;
466     C2ReadView rView = mDummyReadView;
467     if (!work->input.buffers.empty()) {
468         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
469         inSize = rView.capacity();
470         if (inSize && rView.error()) {
471             ALOGE("read view map failed %d", rView.error());
472             work->result = C2_CORRUPTED;
473             return;
474         }
475     }
476 
477     bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) !=0);
478     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
479 
480     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
481           inSize, (int)work->input.ordinal.timestamp.peeku(),
482           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
483 
484     // Software VP9 Decoder does not need the Codec Specific Data (CSD)
485     // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
486     // it was passed.
487     if (codecConfig) {
488         // Ignore CSD buffer for VP9.
489         if (mMode == MODE_VP9) {
490             fillEmptyWork(work);
491             return;
492         } else {
493             // Tolerate the CSD buffer for VP8. This is a workaround
494             // for b/28689536. continue
495             ALOGW("WARNING: Got CSD buffer for VP8. Continue");
496         }
497     }
498 
499     int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
500 
501     if (inSize) {
502         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
503         vpx_codec_err_t err = vpx_codec_decode(
504                 mCodecCtx, bitstream, inSize, &frameIndex, 0);
505         if (err != VPX_CODEC_OK) {
506             ALOGE("on2 decoder failed to decode frame. err: %d", err);
507             mSignalledError = true;
508             work->workletsProcessed = 1u;
509             work->result = C2_CORRUPTED;
510             return;
511         }
512     }
513 
514     (void)outputBuffer(pool, work);
515 
516     if (eos) {
517         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
518         mSignalledOutputEos = true;
519     } else if (!inSize) {
520         fillEmptyWork(work);
521     }
522 }
523 
copyOutputBufferToYV12Frame(uint8_t * dst,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,uint32_t width,uint32_t height,int32_t bpp)524 static void copyOutputBufferToYV12Frame(uint8_t *dst,
525         const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
526         size_t srcYStride, size_t srcUStride, size_t srcVStride,
527         uint32_t width, uint32_t height, int32_t bpp) {
528     size_t dstYStride = align(width, 16) * bpp ;
529     size_t dstUVStride = align(dstYStride / 2, 16);
530     uint8_t *dstStart = dst;
531 
532     for (size_t i = 0; i < height; ++i) {
533          memcpy(dst, srcY, width * bpp);
534          srcY += srcYStride;
535          dst += dstYStride;
536     }
537 
538     dst = dstStart + dstYStride * height;
539     for (size_t i = 0; i < height / 2; ++i) {
540          memcpy(dst, srcV, width / 2 * bpp);
541          srcV += srcVStride;
542          dst += dstUVStride;
543     }
544 
545     dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
546     for (size_t i = 0; i < height / 2; ++i) {
547          memcpy(dst, srcU, width / 2 * bpp);
548          srcU += srcUStride;
549          dst += dstUVStride;
550     }
551 }
552 
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)553 bool C2SoftVpxDec::outputBuffer(
554         const std::shared_ptr<C2BlockPool> &pool,
555         const std::unique_ptr<C2Work> &work)
556 {
557     if (!(work && pool)) return false;
558 
559     vpx_codec_iter_t iter = nullptr;
560     vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
561 
562     if (!img) return false;
563 
564     if (img->d_w != mWidth || img->d_h != mHeight) {
565         mWidth = img->d_w;
566         mHeight = img->d_h;
567 
568         C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
569         std::vector<std::unique_ptr<C2SettingResult>> failures;
570         c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
571         if (err == C2_OK) {
572             work->worklets.front()->output.configUpdate.push_back(
573                 C2Param::Copy(size));
574         } else {
575             ALOGE("Config update size failed");
576             mSignalledError = true;
577             work->workletsProcessed = 1u;
578             work->result = C2_CORRUPTED;
579             return false;
580         }
581 
582     }
583     CHECK(img->fmt == VPX_IMG_FMT_I420 || img->fmt == VPX_IMG_FMT_I42016);
584     int32_t bpp = 1;
585     if (img->fmt == VPX_IMG_FMT_I42016) {
586         bpp = 2;
587     }
588 
589     std::shared_ptr<C2GraphicBlock> block;
590     uint32_t format = HAL_PIXEL_FORMAT_YV12;
591     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
592     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16) * bpp, mHeight, format, usage, &block);
593     if (err != C2_OK) {
594         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
595         work->result = err;
596         return false;
597     }
598 
599     C2GraphicView wView = block->map().get();
600     if (wView.error()) {
601         ALOGE("graphic view map failed %d", wView.error());
602         work->result = C2_CORRUPTED;
603         return false;
604     }
605 
606     ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
607            block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
608 
609     uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
610     size_t srcYStride = img->stride[VPX_PLANE_Y];
611     size_t srcUStride = img->stride[VPX_PLANE_U];
612     size_t srcVStride = img->stride[VPX_PLANE_V];
613     const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
614     const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
615     const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
616     copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV,
617                                 srcYStride, srcUStride, srcVStride, mWidth, mHeight, bpp);
618 
619     finishWork(*(int64_t *)img->user_priv, work, std::move(block));
620     return true;
621 }
622 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)623 c2_status_t C2SoftVpxDec::drainInternal(
624         uint32_t drainMode,
625         const std::shared_ptr<C2BlockPool> &pool,
626         const std::unique_ptr<C2Work> &work) {
627     if (drainMode == NO_DRAIN) {
628         ALOGW("drain with NO_DRAIN: no-op");
629         return C2_OK;
630     }
631     if (drainMode == DRAIN_CHAIN) {
632         ALOGW("DRAIN_CHAIN not supported");
633         return C2_OMITTED;
634     }
635 
636     while ((outputBuffer(pool, work))) {
637     }
638 
639     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
640             work && work->workletsProcessed == 0u) {
641         fillEmptyWork(work);
642     }
643 
644     return C2_OK;
645 }
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)646 c2_status_t C2SoftVpxDec::drain(
647         uint32_t drainMode,
648         const std::shared_ptr<C2BlockPool> &pool) {
649     return drainInternal(drainMode, pool, nullptr);
650 }
651 
652 class C2SoftVpxFactory : public C2ComponentFactory {
653 public:
C2SoftVpxFactory()654     C2SoftVpxFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
655         GetCodec2PlatformComponentStore()->getParamReflector())) {
656     }
657 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)658     virtual c2_status_t createComponent(
659             c2_node_id_t id,
660             std::shared_ptr<C2Component>* const component,
661             std::function<void(C2Component*)> deleter) override {
662         *component = std::shared_ptr<C2Component>(
663             new C2SoftVpxDec(COMPONENT_NAME, id,
664                           std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
665             deleter);
666         return C2_OK;
667     }
668 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)669     virtual c2_status_t createInterface(
670             c2_node_id_t id,
671             std::shared_ptr<C2ComponentInterface>* const interface,
672             std::function<void(C2ComponentInterface*)> deleter) override {
673         *interface = std::shared_ptr<C2ComponentInterface>(
674             new SimpleInterface<C2SoftVpxDec::IntfImpl>(
675                 COMPONENT_NAME, id,
676                 std::make_shared<C2SoftVpxDec::IntfImpl>(mHelper)),
677             deleter);
678         return C2_OK;
679     }
680 
681     virtual ~C2SoftVpxFactory() override = default;
682 
683 private:
684     std::shared_ptr<C2ReflectorHelper> mHelper;
685 };
686 
687 }  // namespace android
688 
CreateCodec2Factory()689 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
690     ALOGV("in %s", __func__);
691     return new ::android::C2SoftVpxFactory();
692 }
693 
DestroyCodec2Factory(::C2ComponentFactory * factory)694 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
695     ALOGV("in %s", __func__);
696     delete factory;
697 }
698