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