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 "C2SoftAomDec"
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 "C2SoftAomDec.h"
29 
30 namespace android {
31 
32 // codecname set and passed in as a compile flag from Android.bp
33 constexpr char COMPONENT_NAME[] = CODECNAME;
34 
35 class C2SoftAomDec::IntfImpl : public SimpleInterface<void>::BaseParams {
36   public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)37     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
38         : SimpleInterface<void>::BaseParams(
39               helper, COMPONENT_NAME, C2Component::KIND_DECODER,
40               C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
41         noPrivateBuffers();  // TODO: account for our buffers here
42         noInputReferences();
43         noOutputReferences();
44         noInputLatency();
45         noTimeStretch();
46 
47         addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
48                          .withConstValue(new C2ComponentAttributesSetting(
49                              C2Component::ATTRIB_IS_TEMPORAL))
50                          .build());
51 
52         addParameter(
53             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
54                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
55                 .withFields({
56                     C2F(mSize, width).inRange(2, 2048, 2),
57                     C2F(mSize, height).inRange(2, 2048, 2),
58                 })
59                 .withSetter(SizeSetter)
60                 .build());
61 
62         addParameter(
63                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
64                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
65                         C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
66                 .withFields({
67                     C2F(mProfileLevel, profile).oneOf({
68                             C2Config::PROFILE_AV1_0,
69                             C2Config::PROFILE_AV1_1}),
70                     C2F(mProfileLevel, level).oneOf({
71                             C2Config::LEVEL_AV1_2,
72                             C2Config::LEVEL_AV1_2_1,
73                             C2Config::LEVEL_AV1_2_2,
74                             C2Config::LEVEL_AV1_3,
75                             C2Config::LEVEL_AV1_3_1,
76                             C2Config::LEVEL_AV1_3_2,
77                     })
78                 })
79                 .withSetter(ProfileLevelSetter, mSize)
80                 .build());
81 
82         mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
83         addParameter(
84                 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
85                 .withDefault(mHdr10PlusInfoInput)
86                 .withFields({
87                     C2F(mHdr10PlusInfoInput, m.value).any(),
88                 })
89                 .withSetter(Hdr10PlusInfoInputSetter)
90                 .build());
91 
92         mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
93         addParameter(
94                 DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
95                 .withDefault(mHdr10PlusInfoOutput)
96                 .withFields({
97                     C2F(mHdr10PlusInfoOutput, m.value).any(),
98                 })
99                 .withSetter(Hdr10PlusInfoOutputSetter)
100                 .build());
101 
102         addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
103                          .withDefault(new C2StreamMaxPictureSizeTuning::output(
104                              0u, 320, 240))
105                          .withFields({
106                              C2F(mSize, width).inRange(2, 2048, 2),
107                              C2F(mSize, height).inRange(2, 2048, 2),
108                          })
109                          .withSetter(MaxPictureSizeSetter, mSize)
110                          .build());
111 
112         addParameter(
113             DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
114                 .withDefault(
115                     new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
116                 .withFields({
117                     C2F(mMaxInputSize, value).any(),
118                 })
119                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
120                 .build());
121 
122         C2ChromaOffsetStruct locations[1] = {
123             C2ChromaOffsetStruct::ITU_YUV_420_0()};
124         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
125             C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
126                                                    C2Color::YUV_420);
127         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
128 
129         defaultColorInfo = C2StreamColorInfo::output::AllocShared(
130             {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
131             C2Color::YUV_420);
132         helper->addStructDescriptors<C2ChromaOffsetStruct>();
133 
134         addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
135                          .withConstValue(defaultColorInfo)
136                          .build());
137 
138         addParameter(
139                 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
140                 .withDefault(new C2StreamColorAspectsTuning::output(
141                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
142                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
143                 .withFields({
144                     C2F(mDefaultColorAspects, range).inRange(
145                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
146                     C2F(mDefaultColorAspects, primaries).inRange(
147                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
148                     C2F(mDefaultColorAspects, transfer).inRange(
149                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
150                     C2F(mDefaultColorAspects, matrix).inRange(
151                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
152                 })
153                 .withSetter(DefaultColorAspectsSetter)
154                 .build());
155 
156         // TODO: support more formats?
157         addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
158                          .withConstValue(new C2StreamPixelFormatInfo::output(
159                              0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
160                          .build());
161     }
162 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)163     static C2R SizeSetter(bool mayBlock,
164                           const C2P<C2StreamPictureSizeInfo::output>& oldMe,
165                           C2P<C2StreamPictureSizeInfo::output>& me) {
166         (void)mayBlock;
167         C2R res = C2R::Ok();
168         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
169             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
170             me.set().width = oldMe.v.width;
171         }
172         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
173             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
174             me.set().height = oldMe.v.height;
175         }
176         return res;
177     }
178 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)179     static C2R MaxPictureSizeSetter(
180         bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output>& me,
181         const C2P<C2StreamPictureSizeInfo::output>& size) {
182         (void)mayBlock;
183         // TODO: get max width/height from the size's field helpers vs.
184         // hardcoding
185         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
186         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
187         return C2R::Ok();
188     }
189 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)190     static C2R MaxInputSizeSetter(
191         bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me,
192         const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
193         (void)mayBlock;
194         // assume compression ratio of 2
195         me.set().value = (((maxSize.v.width + 63) / 64) *
196                           ((maxSize.v.height + 63) / 64) * 3072);
197         return C2R::Ok();
198     }
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)199     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
200         (void)mayBlock;
201         if (me.v.range > C2Color::RANGE_OTHER) {
202             me.set().range = C2Color::RANGE_OTHER;
203         }
204         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
205             me.set().primaries = C2Color::PRIMARIES_OTHER;
206         }
207         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
208             me.set().transfer = C2Color::TRANSFER_OTHER;
209         }
210         if (me.v.matrix > C2Color::MATRIX_OTHER) {
211             me.set().matrix = C2Color::MATRIX_OTHER;
212         }
213         return C2R::Ok();
214     }
215 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)216     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
217                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
218         (void)mayBlock;
219         (void)size;
220         (void)me;  // TODO: validate
221         return C2R::Ok();
222     }
getDefaultColorAspects_l()223     std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
224         return mDefaultColorAspects;
225     }
226 
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)227     static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input> &me) {
228         (void)mayBlock;
229         (void)me;  // TODO: validate
230         return C2R::Ok();
231     }
232 
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)233     static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output> &me) {
234         (void)mayBlock;
235         (void)me;  // TODO: validate
236         return C2R::Ok();
237     }
238 
239   private:
240     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
241     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
242     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
243     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
244     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
245     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
246     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
247     std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
248     std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
249 };
250 
C2SoftAomDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)251 C2SoftAomDec::C2SoftAomDec(const char* name, c2_node_id_t id,
252                            const std::shared_ptr<IntfImpl>& intfImpl)
253     : SimpleC2Component(
254           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
255       mIntf(intfImpl),
256       mCodecCtx(nullptr){
257 
258     GENERATE_FILE_NAMES();
259     CREATE_DUMP_FILE(mInFile);
260     CREATE_DUMP_FILE(mOutFile);
261 
262     gettimeofday(&mTimeStart, nullptr);
263     gettimeofday(&mTimeEnd, nullptr);
264 }
265 
~C2SoftAomDec()266 C2SoftAomDec::~C2SoftAomDec() {
267     onRelease();
268 }
269 
onInit()270 c2_status_t C2SoftAomDec::onInit() {
271     status_t err = initDecoder();
272     return err == OK ? C2_OK : C2_CORRUPTED;
273 }
274 
onStop()275 c2_status_t C2SoftAomDec::onStop() {
276     mSignalledError = false;
277     mSignalledOutputEos = false;
278     return C2_OK;
279 }
280 
onReset()281 void C2SoftAomDec::onReset() {
282     (void)onStop();
283     c2_status_t err = onFlush_sm();
284     if (err != C2_OK) {
285         ALOGW("Failed to flush decoder. Try to hard reset decoder.");
286         destroyDecoder();
287         (void)initDecoder();
288     }
289 }
290 
onRelease()291 void C2SoftAomDec::onRelease() {
292     destroyDecoder();
293 }
294 
onFlush_sm()295 c2_status_t C2SoftAomDec::onFlush_sm() {
296     if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
297         ALOGE("Failed to flush av1 decoder.");
298         return C2_CORRUPTED;
299     }
300 
301     aom_codec_iter_t iter = nullptr;
302     while (aom_codec_get_frame(mCodecCtx, &iter)) {
303     }
304 
305     mSignalledError = false;
306     mSignalledOutputEos = false;
307 
308     return C2_OK;
309 }
310 
GetCPUCoreCount()311 static int GetCPUCoreCount() {
312     int cpuCoreCount = 1;
313 #if defined(_SC_NPROCESSORS_ONLN)
314     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
315 #else
316     // _SC_NPROC_ONLN must be defined...
317     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
318 #endif
319     CHECK(cpuCoreCount >= 1);
320     ALOGV("Number of CPU cores: %d", cpuCoreCount);
321     return cpuCoreCount;
322 }
323 
initDecoder()324 status_t C2SoftAomDec::initDecoder() {
325     mSignalledError = false;
326     mSignalledOutputEos = false;
327     if (!mCodecCtx) {
328         mCodecCtx = new aom_codec_ctx_t;
329     }
330 
331     if (!mCodecCtx) {
332         ALOGE("mCodecCtx is null");
333         return NO_MEMORY;
334     }
335 
336     aom_codec_dec_cfg_t cfg;
337     memset(&cfg, 0, sizeof(aom_codec_dec_cfg_t));
338     cfg.threads = GetCPUCoreCount();
339     cfg.allow_lowbitdepth = 1;
340 
341     aom_codec_flags_t flags;
342     memset(&flags, 0, sizeof(aom_codec_flags_t));
343 
344     ALOGV("Using libaom AV1 software decoder.");
345     aom_codec_err_t err;
346     if ((err = aom_codec_dec_init(mCodecCtx, aom_codec_av1_dx(), &cfg, 0))) {
347         ALOGE("av1 decoder failed to initialize. (%d)", err);
348         return UNKNOWN_ERROR;
349     }
350 
351     return OK;
352 }
353 
destroyDecoder()354 status_t C2SoftAomDec::destroyDecoder() {
355     if (mCodecCtx) {
356         aom_codec_destroy(mCodecCtx);
357         delete mCodecCtx;
358         mCodecCtx = nullptr;
359     }
360     return OK;
361 }
362 
fillEmptyWork(const std::unique_ptr<C2Work> & work)363 void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
364     uint32_t flags = 0;
365     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
366         flags |= C2FrameData::FLAG_END_OF_STREAM;
367         ALOGV("signalling eos");
368     }
369     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
370     work->worklets.front()->output.buffers.clear();
371     work->worklets.front()->output.ordinal = work->input.ordinal;
372     work->workletsProcessed = 1u;
373 }
374 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block)375 void C2SoftAomDec::finishWork(uint64_t index,
376                               const std::unique_ptr<C2Work>& work,
377                               const std::shared_ptr<C2GraphicBlock>& block) {
378     std::shared_ptr<C2Buffer> buffer =
379         createGraphicBuffer(block, C2Rect(mWidth, mHeight));
380     auto fillWork = [buffer, index, intf = this->mIntf](
381             const std::unique_ptr<C2Work>& work) {
382         uint32_t flags = 0;
383         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
384             (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
385             flags |= C2FrameData::FLAG_END_OF_STREAM;
386             ALOGV("signalling eos");
387         }
388         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
389         work->worklets.front()->output.buffers.clear();
390         work->worklets.front()->output.buffers.push_back(buffer);
391         work->worklets.front()->output.ordinal = work->input.ordinal;
392         work->workletsProcessed = 1u;
393 
394         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
395             if (param) {
396                 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
397                         C2StreamHdr10PlusInfo::input::From(param.get());
398 
399                 if (hdr10PlusInfo != nullptr) {
400                     std::vector<std::unique_ptr<C2SettingResult>> failures;
401                     std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
402                             *param.get(), true /*output*/, param->stream());
403                     c2_status_t err = intf->config(
404                             { outParam.get() }, C2_MAY_BLOCK, &failures);
405                     if (err == C2_OK) {
406                         work->worklets.front()->output.configUpdate.push_back(
407                                 C2Param::Copy(*outParam.get()));
408                     } else {
409                         ALOGE("finishWork: Config update size failed");
410                     }
411                     break;
412                 }
413             }
414         }
415     };
416     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
417         fillWork(work);
418     } else {
419         finish(index, fillWork);
420     }
421 }
422 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)423 void C2SoftAomDec::process(const std::unique_ptr<C2Work>& work,
424                            const std::shared_ptr<C2BlockPool>& pool) {
425     work->result = C2_OK;
426     work->workletsProcessed = 0u;
427     work->worklets.front()->output.configUpdate.clear();
428     work->worklets.front()->output.flags = work->input.flags;
429     if (mSignalledError || mSignalledOutputEos) {
430         work->result = C2_BAD_VALUE;
431         return;
432     }
433 
434     size_t inOffset = 0u;
435     size_t inSize = 0u;
436     C2ReadView rView = mDummyReadView;
437     if (!work->input.buffers.empty()) {
438         rView =
439             work->input.buffers[0]->data().linearBlocks().front().map().get();
440         inSize = rView.capacity();
441         if (inSize && rView.error()) {
442             ALOGE("read view map failed %d", rView.error());
443             work->result = C2_CORRUPTED;
444             return;
445         }
446     }
447 
448     bool codecConfig =
449         ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
450     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
451 
452     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
453           inSize, (int)work->input.ordinal.timestamp.peeku(),
454           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
455 
456     if (codecConfig) {
457         fillEmptyWork(work);
458         return;
459     }
460 
461     int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
462     if (inSize) {
463         uint8_t* bitstream = const_cast<uint8_t*>(rView.data() + inOffset);
464         int32_t decodeTime = 0;
465         int32_t delay = 0;
466 
467         DUMP_TO_FILE(mOutFile, bitstream, inSize);
468         GETTIME(&mTimeStart, nullptr);
469         TIME_DIFF(mTimeEnd, mTimeStart, delay);
470 
471         aom_codec_err_t err =
472             aom_codec_decode(mCodecCtx, bitstream, inSize, &frameIndex);
473 
474         GETTIME(&mTimeEnd, nullptr);
475         TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
476         ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
477 
478         if (err != AOM_CODEC_OK) {
479             ALOGE("av1 decoder failed to decode frame err: %d", err);
480             work->result = C2_CORRUPTED;
481             work->workletsProcessed = 1u;
482             mSignalledError = true;
483             return;
484         }
485 
486     } else {
487         if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
488             ALOGE("Failed to flush av1 decoder.");
489             work->result = C2_CORRUPTED;
490             work->workletsProcessed = 1u;
491             mSignalledError = true;
492             return;
493         }
494     }
495 
496     (void)outputBuffer(pool, work);
497 
498     if (eos) {
499         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
500         mSignalledOutputEos = true;
501     } else if (!inSize) {
502         fillEmptyWork(work);
503     }
504 }
505 
copyOutputBufferToYuvPlanarFrame(uint8_t * dst,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,uint32_t width,uint32_t height)506 static void copyOutputBufferToYuvPlanarFrame(
507         uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
508         size_t srcYStride, size_t srcUStride, size_t srcVStride,
509         size_t dstYStride, size_t dstUVStride,
510         uint32_t width, uint32_t height) {
511     uint8_t* dstStart = dst;
512 
513     for (size_t i = 0; i < height; ++i) {
514         memcpy(dst, srcY, width);
515         srcY += srcYStride;
516         dst += dstYStride;
517     }
518 
519     dst = dstStart + dstYStride * height;
520     for (size_t i = 0; i < height / 2; ++i) {
521          memcpy(dst, srcV, width / 2);
522         srcV += srcVStride;
523         dst += dstUVStride;
524     }
525 
526     dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
527     for (size_t i = 0; i < height / 2; ++i) {
528          memcpy(dst, srcU, width / 2);
529         srcU += srcUStride;
530         dst += dstUVStride;
531     }
532 }
533 
convertYUV420Planar16ToY410(uint32_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstStride,size_t width,size_t height)534 static void convertYUV420Planar16ToY410(uint32_t *dst,
535         const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
536         size_t srcYStride, size_t srcUStride, size_t srcVStride,
537         size_t dstStride, size_t width, size_t height) {
538 
539     // Converting two lines at a time, slightly faster
540     for (size_t y = 0; y < height; y += 2) {
541         uint32_t *dstTop = (uint32_t *) dst;
542         uint32_t *dstBot = (uint32_t *) (dst + dstStride);
543         uint16_t *ySrcTop = (uint16_t*) srcY;
544         uint16_t *ySrcBot = (uint16_t*) (srcY + srcYStride);
545         uint16_t *uSrc = (uint16_t*) srcU;
546         uint16_t *vSrc = (uint16_t*) srcV;
547 
548         uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
549         size_t x = 0;
550         for (; x < width - 3; x += 4) {
551 
552             u01 = *((uint32_t*)uSrc); uSrc += 2;
553             v01 = *((uint32_t*)vSrc); vSrc += 2;
554 
555             y01 = *((uint32_t*)ySrcTop); ySrcTop += 2;
556             y23 = *((uint32_t*)ySrcTop); ySrcTop += 2;
557             y45 = *((uint32_t*)ySrcBot); ySrcBot += 2;
558             y67 = *((uint32_t*)ySrcBot); ySrcBot += 2;
559 
560             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
561             uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
562 
563             *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
564             *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
565             *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
566             *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
567 
568             *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
569             *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
570             *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
571             *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
572         }
573 
574         // There should be at most 2 more pixels to process. Note that we don't
575         // need to consider odd case as the buffer is always aligned to even.
576         if (x < width) {
577             u01 = *uSrc;
578             v01 = *vSrc;
579             y01 = *((uint32_t*)ySrcTop);
580             y45 = *((uint32_t*)ySrcBot);
581             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
582             *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
583             *dstTop++ = ((y01 >> 16) << 10) | uv0;
584             *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
585             *dstBot++ = ((y45 >> 16) << 10) | uv0;
586         }
587 
588         srcY += srcYStride * 2;
589         srcU += srcUStride;
590         srcV += srcVStride;
591         dst += dstStride * 2;
592     }
593 
594     return;
595 }
596 
convertYUV420Planar16ToYUV420Planar(uint8_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height)597 static void convertYUV420Planar16ToYUV420Planar(uint8_t *dst,
598         const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
599         size_t srcYStride, size_t srcUStride, size_t srcVStride,
600         size_t dstYStride, size_t dstUVStride, size_t width, size_t height) {
601 
602     uint8_t *dstY = (uint8_t *)dst;
603     size_t dstYSize = dstYStride * height;
604     size_t dstUVSize = dstUVStride * height / 2;
605     uint8_t *dstV = dstY + dstYSize;
606     uint8_t *dstU = dstV + dstUVSize;
607 
608     for (size_t y = 0; y < height; ++y) {
609         for (size_t x = 0; x < width; ++x) {
610             dstY[x] = (uint8_t)(srcY[x] >> 2);
611         }
612 
613         srcY += srcYStride;
614         dstY += dstYStride;
615     }
616 
617     for (size_t y = 0; y < (height + 1) / 2; ++y) {
618         for (size_t x = 0; x < (width + 1) / 2; ++x) {
619             dstU[x] = (uint8_t)(srcU[x] >> 2);
620             dstV[x] = (uint8_t)(srcV[x] >> 2);
621         }
622 
623         srcU += srcUStride;
624         srcV += srcVStride;
625         dstU += dstUVStride;
626         dstV += dstUVStride;
627     }
628     return;
629 }
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)630 bool C2SoftAomDec::outputBuffer(
631         const std::shared_ptr<C2BlockPool> &pool,
632         const std::unique_ptr<C2Work> &work)
633 {
634     if (!(work && pool)) return false;
635 
636     aom_codec_iter_t iter = nullptr;
637     aom_image_t* img = aom_codec_get_frame(mCodecCtx, &iter);
638 
639     if (!img) return false;
640 
641     if (img->d_w != mWidth || img->d_h != mHeight) {
642         mWidth = img->d_w;
643         mHeight = img->d_h;
644 
645         C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
646         std::vector<std::unique_ptr<C2SettingResult>> failures;
647         c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
648         if (err == C2_OK) {
649             work->worklets.front()->output.configUpdate.push_back(
650                 C2Param::Copy(size));
651         } else {
652             ALOGE("Config update size failed");
653             mSignalledError = true;
654             work->result = C2_CORRUPTED;
655             work->workletsProcessed = 1u;
656             return false;
657         }
658     }
659 
660     CHECK(img->fmt == AOM_IMG_FMT_I420 || img->fmt == AOM_IMG_FMT_I42016);
661 
662     std::shared_ptr<C2GraphicBlock> block;
663     uint32_t format = HAL_PIXEL_FORMAT_YV12;
664     if (img->fmt == AOM_IMG_FMT_I42016) {
665         IntfImpl::Lock lock = mIntf->lock();
666         std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = mIntf->getDefaultColorAspects_l();
667 
668         if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
669             defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
670             defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
671             format = HAL_PIXEL_FORMAT_RGBA_1010102;
672         }
673     }
674     C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
675 
676     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight,
677                                               format, usage, &block);
678 
679     if (err != C2_OK) {
680         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
681         work->result = err;
682         return false;
683     }
684 
685     C2GraphicView wView = block->map().get();
686 
687     if (wView.error()) {
688         ALOGE("graphic view map failed %d", wView.error());
689         work->result = C2_CORRUPTED;
690         return false;
691     }
692 
693     ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
694           block->width(), block->height(), mWidth, mHeight,
695           (int)*(int64_t*)img->user_priv);
696 
697     uint8_t* dst = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_Y]);
698     size_t srcYStride = img->stride[AOM_PLANE_Y];
699     size_t srcUStride = img->stride[AOM_PLANE_U];
700     size_t srcVStride = img->stride[AOM_PLANE_V];
701     C2PlanarLayout layout = wView.layout();
702     size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
703     size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
704 
705     if (img->fmt == AOM_IMG_FMT_I42016) {
706         const uint16_t *srcY = (const uint16_t *)img->planes[AOM_PLANE_Y];
707         const uint16_t *srcU = (const uint16_t *)img->planes[AOM_PLANE_U];
708         const uint16_t *srcV = (const uint16_t *)img->planes[AOM_PLANE_V];
709 
710         if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
711             convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2,
712                                     srcUStride / 2, srcVStride / 2,
713                                     dstYStride / sizeof(uint32_t),
714                                     mWidth, mHeight);
715         } else {
716             convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
717                                     srcUStride / 2, srcVStride / 2,
718                                     dstYStride, dstUVStride,
719                                     mWidth, mHeight);
720         }
721     } else {
722         const uint8_t *srcY = (const uint8_t *)img->planes[AOM_PLANE_Y];
723         const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
724         const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
725         copyOutputBufferToYuvPlanarFrame(
726                 dst, srcY, srcU, srcV,
727                 srcYStride, srcUStride, srcVStride,
728                 dstYStride, dstUVStride,
729                 mWidth, mHeight);
730     }
731     finishWork(*(int64_t*)img->user_priv, work, std::move(block));
732     block = nullptr;
733     return true;
734 }
735 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)736 c2_status_t C2SoftAomDec::drainInternal(
737     uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool,
738     const std::unique_ptr<C2Work>& work) {
739     if (drainMode == NO_DRAIN) {
740         ALOGW("drain with NO_DRAIN: no-op");
741         return C2_OK;
742     }
743     if (drainMode == DRAIN_CHAIN) {
744         ALOGW("DRAIN_CHAIN not supported");
745         return C2_OMITTED;
746     }
747 
748     if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
749         ALOGE("Failed to flush av1 decoder.");
750         return C2_CORRUPTED;
751     }
752 
753     while ((outputBuffer(pool, work))) {
754     }
755 
756     if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
757         work->workletsProcessed == 0u) {
758         fillEmptyWork(work);
759     }
760 
761     return C2_OK;
762 }
763 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)764 c2_status_t C2SoftAomDec::drain(uint32_t drainMode,
765                                 const std::shared_ptr<C2BlockPool>& pool) {
766     return drainInternal(drainMode, pool, nullptr);
767 }
768 
769 class C2SoftAomFactory : public C2ComponentFactory {
770    public:
C2SoftAomFactory()771     C2SoftAomFactory()
772         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
773               GetCodec2PlatformComponentStore()->getParamReflector())) {}
774 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)775     virtual c2_status_t createComponent(
776         c2_node_id_t id, std::shared_ptr<C2Component>* const component,
777         std::function<void(C2Component*)> deleter) override {
778         *component = std::shared_ptr<C2Component>(
779             new C2SoftAomDec(COMPONENT_NAME, id,
780                              std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
781             deleter);
782         return C2_OK;
783     }
784 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)785     virtual c2_status_t createInterface(
786         c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
787         std::function<void(C2ComponentInterface*)> deleter) override {
788         *interface = std::shared_ptr<C2ComponentInterface>(
789             new SimpleInterface<C2SoftAomDec::IntfImpl>(
790                 COMPONENT_NAME, id,
791                 std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
792             deleter);
793         return C2_OK;
794     }
795 
796     virtual ~C2SoftAomFactory() override = default;
797 
798    private:
799     std::shared_ptr<C2ReflectorHelper> mHelper;
800 };
801 
802 }  // namespace android
803 
CreateCodec2Factory()804 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
805     ALOGV("in %s", __func__);
806     return new ::android::C2SoftAomFactory();
807 }
808 
DestroyCodec2Factory(::C2ComponentFactory * factory)809 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
810     ALOGV("in %s", __func__);
811     delete factory;
812 }
813