1 /*
2  * Copyright (C) 2023 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 "C2SoftDav1dDec"
19 #include <android-base/properties.h>
20 #include <cutils/properties.h>
21 #include <thread>
22 
23 #include <C2Debug.h>
24 #include <C2PlatformSupport.h>
25 #include <Codec2BufferUtils.h>
26 #include <Codec2CommonUtils.h>
27 #include <Codec2Mapper.h>
28 #include <SimpleC2Interface.h>
29 #include <log/log.h>
30 #include <media/stagefright/foundation/AUtils.h>
31 #include <media/stagefright/foundation/MediaDefs.h>
32 #include "C2SoftDav1dDec.h"
33 
34 namespace android {
35 
36 // The number of threads used for the dav1d decoder.
37 static const int NUM_THREADS_DAV1D_DEFAULT = 0;
38 static const char NUM_THREADS_DAV1D_PROPERTY[] = "debug.dav1d.numthreads";
39 
40 // codecname set and passed in as a compile flag from Android.bp
41 constexpr char COMPONENT_NAME[] = CODECNAME;
42 
43 constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
44 
45 constexpr uint32_t kOutputDelay = 4;
46 
47 class C2SoftDav1dDec::IntfImpl : public SimpleInterface<void>::BaseParams {
48   public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)49     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
50         : SimpleInterface<void>::BaseParams(helper, COMPONENT_NAME, C2Component::KIND_DECODER,
51                                             C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
52         noPrivateBuffers();
53         noInputReferences();
54         noOutputReferences();
55         noInputLatency();
56         noTimeStretch();
57 
58         addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
59                              .withConstValue(new C2ComponentAttributesSetting(
60                                      C2Component::ATTRIB_IS_TEMPORAL))
61                              .build());
62 
63         addParameter(DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
64                              .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
65                              .withFields({
66                                      C2F(mSize, width).inRange(2, 4096),
67                                      C2F(mSize, height).inRange(2, 4096),
68                              })
69                              .withSetter(SizeSetter)
70                              .build());
71 
72         addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
73                              .withDefault(new C2StreamProfileLevelInfo::input(
74                                      0u, C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
75                              .withFields({C2F(mProfileLevel, profile)
76                                                   .oneOf({C2Config::PROFILE_AV1_0,
77                                                           C2Config::PROFILE_AV1_1}),
78                                           C2F(mProfileLevel, level)
79                                                   .oneOf({
80                                                           C2Config::LEVEL_AV1_2,
81                                                           C2Config::LEVEL_AV1_2_1,
82                                                           C2Config::LEVEL_AV1_2_2,
83                                                           C2Config::LEVEL_AV1_2_3,
84                                                           C2Config::LEVEL_AV1_3,
85                                                           C2Config::LEVEL_AV1_3_1,
86                                                           C2Config::LEVEL_AV1_3_2,
87                                                           C2Config::LEVEL_AV1_3_3,
88                                                           C2Config::LEVEL_AV1_4,
89                                                           C2Config::LEVEL_AV1_4_1,
90                                                           C2Config::LEVEL_AV1_4_2,
91                                                           C2Config::LEVEL_AV1_4_3,
92                                                           C2Config::LEVEL_AV1_5,
93                                                           C2Config::LEVEL_AV1_5_1,
94                                                           C2Config::LEVEL_AV1_5_2,
95                                                           C2Config::LEVEL_AV1_5_3,
96                                                   })})
97                              .withSetter(ProfileLevelSetter, mSize)
98                              .build());
99 
100         mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
101         addParameter(DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
102                              .withDefault(mHdr10PlusInfoInput)
103                              .withFields({
104                                      C2F(mHdr10PlusInfoInput, m.value).any(),
105                              })
106                              .withSetter(Hdr10PlusInfoInputSetter)
107                              .build());
108 
109         mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
110         addParameter(DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
111                              .withDefault(mHdr10PlusInfoOutput)
112                              .withFields({
113                                      C2F(mHdr10PlusInfoOutput, m.value).any(),
114                              })
115                              .withSetter(Hdr10PlusInfoOutputSetter)
116                              .build());
117 
118         // default static info
119         C2HdrStaticMetadataStruct defaultStaticInfo{};
120         helper->addStructDescriptors<C2MasteringDisplayColorVolumeStruct, C2ColorXyStruct>();
121         addParameter(
122                 DefineParam(mHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
123                         .withDefault(new C2StreamHdrStaticInfo::output(0u, defaultStaticInfo))
124                         .withFields({C2F(mHdrStaticInfo, mastering.red.x).inRange(0, 1),
125                                      C2F(mHdrStaticInfo, mastering.red.y).inRange(0, 1),
126                                      C2F(mHdrStaticInfo, mastering.green.x).inRange(0, 1),
127                                      C2F(mHdrStaticInfo, mastering.green.y).inRange(0, 1),
128                                      C2F(mHdrStaticInfo, mastering.blue.x).inRange(0, 1),
129                                      C2F(mHdrStaticInfo, mastering.blue.y).inRange(0, 1),
130                                      C2F(mHdrStaticInfo, mastering.white.x).inRange(0, 1),
131                                      C2F(mHdrStaticInfo, mastering.white.x).inRange(0, 1),
132                                      C2F(mHdrStaticInfo, mastering.maxLuminance).inRange(0, 65535),
133                                      C2F(mHdrStaticInfo, mastering.minLuminance).inRange(0, 6.5535),
134                                      C2F(mHdrStaticInfo, maxCll).inRange(0, 0XFFFF),
135                                      C2F(mHdrStaticInfo, maxFall).inRange(0, 0XFFFF)})
136                         .withSetter(HdrStaticInfoSetter)
137                         .build());
138 
139         addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
140                              .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
141                              .withFields({
142                                      C2F(mSize, width).inRange(2, 2048, 2),
143                                      C2F(mSize, height).inRange(2, 2048, 2),
144                              })
145                              .withSetter(MaxPictureSizeSetter, mSize)
146                              .build());
147 
148         addParameter(
149                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
150                         .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
151                         .withFields({
152                                 C2F(mMaxInputSize, value).any(),
153                         })
154                         .calculatedAs(MaxInputSizeSetter, mMaxSize)
155                         .build());
156 
157         C2ChromaOffsetStruct locations[1] = {C2ChromaOffsetStruct::ITU_YUV_420_0()};
158         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
159                 C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
160         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
161 
162         defaultColorInfo = C2StreamColorInfo::output::AllocShared(
163                 {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */, C2Color::YUV_420);
164         helper->addStructDescriptors<C2ChromaOffsetStruct>();
165 
166         addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
167                              .withConstValue(defaultColorInfo)
168                              .build());
169 
170         addParameter(DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
171                              .withDefault(new C2StreamColorAspectsTuning::output(
172                                      0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
173                                      C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
174                              .withFields({C2F(mDefaultColorAspects, range)
175                                                   .inRange(C2Color::RANGE_UNSPECIFIED,
176                                                            C2Color::RANGE_OTHER),
177                                           C2F(mDefaultColorAspects, primaries)
178                                                   .inRange(C2Color::PRIMARIES_UNSPECIFIED,
179                                                            C2Color::PRIMARIES_OTHER),
180                                           C2F(mDefaultColorAspects, transfer)
181                                                   .inRange(C2Color::TRANSFER_UNSPECIFIED,
182                                                            C2Color::TRANSFER_OTHER),
183                                           C2F(mDefaultColorAspects, matrix)
184                                                   .inRange(C2Color::MATRIX_UNSPECIFIED,
185                                                            C2Color::MATRIX_OTHER)})
186                              .withSetter(DefaultColorAspectsSetter)
187                              .build());
188 
189         addParameter(DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
190                              .withDefault(new C2StreamColorAspectsInfo::input(
191                                      0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
192                                      C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
193                              .withFields({C2F(mCodedColorAspects, range)
194                                                   .inRange(C2Color::RANGE_UNSPECIFIED,
195                                                            C2Color::RANGE_OTHER),
196                                           C2F(mCodedColorAspects, primaries)
197                                                   .inRange(C2Color::PRIMARIES_UNSPECIFIED,
198                                                            C2Color::PRIMARIES_OTHER),
199                                           C2F(mCodedColorAspects, transfer)
200                                                   .inRange(C2Color::TRANSFER_UNSPECIFIED,
201                                                            C2Color::TRANSFER_OTHER),
202                                           C2F(mCodedColorAspects, matrix)
203                                                   .inRange(C2Color::MATRIX_UNSPECIFIED,
204                                                            C2Color::MATRIX_OTHER)})
205                              .withSetter(CodedColorAspectsSetter)
206                              .build());
207 
208         addParameter(
209                 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
210                         .withDefault(new C2StreamColorAspectsInfo::output(
211                                 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
212                                 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
213                         .withFields(
214                                 {C2F(mColorAspects, range)
215                                          .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
216                                  C2F(mColorAspects, primaries)
217                                          .inRange(C2Color::PRIMARIES_UNSPECIFIED,
218                                                   C2Color::PRIMARIES_OTHER),
219                                  C2F(mColorAspects, transfer)
220                                          .inRange(C2Color::TRANSFER_UNSPECIFIED,
221                                                   C2Color::TRANSFER_OTHER),
222                                  C2F(mColorAspects, matrix)
223                                          .inRange(C2Color::MATRIX_UNSPECIFIED,
224                                                   C2Color::MATRIX_OTHER)})
225                         .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
226                         .build());
227 
228         std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_YCBCR_420_888};
229         if (isHalPixelFormatSupported((AHardwareBuffer_Format)HAL_PIXEL_FORMAT_YCBCR_P010)) {
230             pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
231         }
232         // If color format surface isn't added to supported formats, there is no way to know
233         // when the color-format is configured to surface. This is necessary to be able to
234         // choose 10-bit format while decoding 10-bit clips in surface mode.
235         pixelFormats.push_back(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
236 
237         // TODO: support more formats?
238         addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
239                              .withDefault(new C2StreamPixelFormatInfo::output(
240                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
241                              .withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
242                              .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
243                              .build());
244 
245         addParameter(
246                 DefineParam(mLowLatencyMode, C2_PARAMKEY_LOW_LATENCY_MODE)
247                 .withDefault(new C2GlobalLowLatencyModeTuning(0))
248                 .withFields({C2F(mLowLatencyMode, value).oneOf({0,1})})
249                 .withSetter(Setter<decltype(*mLowLatencyMode)>::StrictValueWithNoDeps)
250                 .build());
251 
252         addParameter(
253                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
254                 .withDefault(new C2PortActualDelayTuning::output(kOutputDelay))
255                 .withFields({C2F(mActualOutputDelay, value).inRange(0, kOutputDelay)})
256                 .withSetter(ActualOutputDelaySetter, mLowLatencyMode)
257                 .build());
258     }
259 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)260     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output>& oldMe,
261                           C2P<C2StreamPictureSizeInfo::output>& me) {
262         (void)mayBlock;
263         C2R res = C2R::Ok();
264         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
265             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
266             me.set().width = oldMe.v.width;
267         }
268         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
269             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
270             me.set().height = oldMe.v.height;
271         }
272         return res;
273     }
274 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)275     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output>& me,
276                                     const C2P<C2StreamPictureSizeInfo::output>& size) {
277         (void)mayBlock;
278         // TODO: get max width/height from the size's field helpers vs.
279         // hardcoding
280         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
281         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
282         return C2R::Ok();
283     }
284 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)285     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me,
286                                   const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
287         (void)mayBlock;
288         // assume compression ratio of 2, but enforce a floor
289         me.set().value =
290                 c2_max((((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072),
291                        kMinInputBufferSize);
292         return C2R::Ok();
293     }
294 
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)295     static C2R DefaultColorAspectsSetter(bool mayBlock,
296                                          C2P<C2StreamColorAspectsTuning::output>& me) {
297         (void)mayBlock;
298         if (me.v.range > C2Color::RANGE_OTHER) {
299             me.set().range = C2Color::RANGE_OTHER;
300         }
301         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
302             me.set().primaries = C2Color::PRIMARIES_OTHER;
303         }
304         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
305             me.set().transfer = C2Color::TRANSFER_OTHER;
306         }
307         if (me.v.matrix > C2Color::MATRIX_OTHER) {
308             me.set().matrix = C2Color::MATRIX_OTHER;
309         }
310         return C2R::Ok();
311     }
312 
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)313     static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input>& me) {
314         (void)mayBlock;
315         if (me.v.range > C2Color::RANGE_OTHER) {
316             me.set().range = C2Color::RANGE_OTHER;
317         }
318         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
319             me.set().primaries = C2Color::PRIMARIES_OTHER;
320         }
321         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
322             me.set().transfer = C2Color::TRANSFER_OTHER;
323         }
324         if (me.v.matrix > C2Color::MATRIX_OTHER) {
325             me.set().matrix = C2Color::MATRIX_OTHER;
326         }
327         return C2R::Ok();
328     }
329 
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)330     static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
331                                   const C2P<C2StreamColorAspectsTuning::output>& def,
332                                   const C2P<C2StreamColorAspectsInfo::input>& coded) {
333         (void)mayBlock;
334         // take default values for all unspecified fields, and coded values for specified ones
335         me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
336         me.set().primaries =
337                 coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries;
338         me.set().transfer =
339                 coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer;
340         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
341         return C2R::Ok();
342     }
343 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)344     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input>& me,
345                                   const C2P<C2StreamPictureSizeInfo::output>& size) {
346         (void)mayBlock;
347         (void)size;
348         (void)me;  // TODO: validate
349         return C2R::Ok();
350     }
351 
getDefaultColorAspects_l()352     std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
353         return mDefaultColorAspects;
354     }
355 
getColorAspects_l()356     std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() { return mColorAspects; }
357 
Hdr10PlusInfoInputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::input> & me)358     static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input>& me) {
359         (void)mayBlock;
360         (void)me;  // TODO: validate
361         return C2R::Ok();
362     }
363 
Hdr10PlusInfoOutputSetter(bool mayBlock,C2P<C2StreamHdr10PlusInfo::output> & me)364     static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output>& me) {
365         (void)mayBlock;
366         (void)me;  // TODO: validate
367         return C2R::Ok();
368     }
369 
370     // unsafe getters
getPixelFormat_l() const371     std::shared_ptr<C2StreamPixelFormatInfo::output> getPixelFormat_l() const {
372         return mPixelFormat;
373     }
374 
getActualOutputDelay_l() const375     std::shared_ptr<C2PortActualDelayTuning::output> getActualOutputDelay_l() const {
376         return mActualOutputDelay;
377     }
378 
HdrStaticInfoSetter(bool mayBlock,C2P<C2StreamHdrStaticInfo::output> & me)379     static C2R HdrStaticInfoSetter(bool mayBlock, C2P<C2StreamHdrStaticInfo::output>& me) {
380         (void)mayBlock;
381         if (me.v.mastering.red.x > 1) {
382             me.set().mastering.red.x = 1;
383         }
384         if (me.v.mastering.red.y > 1) {
385             me.set().mastering.red.y = 1;
386         }
387         if (me.v.mastering.green.x > 1) {
388             me.set().mastering.green.x = 1;
389         }
390         if (me.v.mastering.green.y > 1) {
391             me.set().mastering.green.y = 1;
392         }
393         if (me.v.mastering.blue.x > 1) {
394             me.set().mastering.blue.x = 1;
395         }
396         if (me.v.mastering.blue.y > 1) {
397             me.set().mastering.blue.y = 1;
398         }
399         if (me.v.mastering.white.x > 1) {
400             me.set().mastering.white.x = 1;
401         }
402         if (me.v.mastering.white.y > 1) {
403             me.set().mastering.white.y = 1;
404         }
405         if (me.v.mastering.maxLuminance > 65535.0) {
406             me.set().mastering.maxLuminance = 65535.0;
407         }
408         if (me.v.mastering.minLuminance > 6.5535) {
409             me.set().mastering.minLuminance = 6.5535;
410         }
411         if (me.v.maxCll > 65535.0) {
412             me.set().maxCll = 65535.0;
413         }
414         if (me.v.maxFall > 65535.0) {
415             me.set().maxFall = 65535.0;
416         }
417         return C2R::Ok();
418     }
419 
ActualOutputDelaySetter(bool mayBlock,C2P<C2PortActualDelayTuning::output> & me,const C2P<C2GlobalLowLatencyModeTuning> & lowLatencyMode)420     static C2R ActualOutputDelaySetter(bool mayBlock, C2P<C2PortActualDelayTuning::output>& me,
421                                   const C2P<C2GlobalLowLatencyModeTuning>& lowLatencyMode) {
422         (void)mayBlock;
423         me.set().value = lowLatencyMode.v.value ? 1 : kOutputDelay;
424         return C2R::Ok();
425     }
426 
427   private:
428     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
429     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
430     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
431     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
432     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
433     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
434     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
435     std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
436     std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
437     std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
438     std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
439     std::shared_ptr<C2StreamHdrStaticInfo::output> mHdrStaticInfo;
440     std::shared_ptr<C2GlobalLowLatencyModeTuning> mLowLatencyMode;
441 };
442 
C2SoftDav1dDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)443 C2SoftDav1dDec::C2SoftDav1dDec(const char* name, c2_node_id_t id,
444                                const std::shared_ptr<IntfImpl>& intfImpl)
445     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
446       mIntf(intfImpl) {
447     mTimeStart = mTimeEnd = systemTime();
448 }
449 
~C2SoftDav1dDec()450 C2SoftDav1dDec::~C2SoftDav1dDec() {
451     onRelease();
452 }
453 
onInit()454 c2_status_t C2SoftDav1dDec::onInit() {
455     return initDecoder() ? C2_OK : C2_CORRUPTED;
456 }
457 
onStop()458 c2_status_t C2SoftDav1dDec::onStop() {
459     // TODO: b/277797541 - investigate if the decoder needs to be flushed.
460     mSignalledError = false;
461     mSignalledOutputEos = false;
462     return C2_OK;
463 }
464 
onReset()465 void C2SoftDav1dDec::onReset() {
466     (void)onStop();
467     c2_status_t err = onFlush_sm();
468     if (err != C2_OK) {
469         ALOGW("Failed to flush the av1 decoder. Trying to hard reset.");
470         destroyDecoder();
471         if (!initDecoder()) {
472             ALOGE("Hard reset failed.");
473         }
474     }
475 }
476 
flushDav1d()477 void C2SoftDav1dDec::flushDav1d() {
478     if (mDav1dCtx) {
479         Dav1dPicture p;
480 
481         int res = 0;
482         while (true) {
483             memset(&p, 0, sizeof(p));
484 
485             if ((res = dav1d_get_picture(mDav1dCtx, &p)) < 0) {
486                 if (res != DAV1D_ERR(EAGAIN)) {
487                     ALOGE("Error decoding frame: %s\n", strerror(DAV1D_ERR(res)));
488                     break;
489                 } else {
490                     res = 0;
491                     break;
492                 }
493             } else {
494                 dav1d_picture_unref(&p);
495             }
496         }
497 
498         dav1d_flush(mDav1dCtx);
499     }
500 }
501 
onRelease()502 void C2SoftDav1dDec::onRelease() {
503     destroyDecoder();
504 }
505 
onFlush_sm()506 c2_status_t C2SoftDav1dDec::onFlush_sm() {
507     flushDav1d();
508 
509     mSignalledError = false;
510     mSignalledOutputEos = false;
511 
512     return C2_OK;
513 }
514 
GetCPUCoreCount()515 static int GetCPUCoreCount() {
516     int cpuCoreCount = 1;
517 #if defined(_SC_NPROCESSORS_ONLN)
518     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
519 #else
520     // _SC_NPROC_ONLN must be defined...
521     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
522 #endif
523     CHECK(cpuCoreCount >= 1);
524     ALOGV("Number of CPU cores: %d", cpuCoreCount);
525     return cpuCoreCount;
526 }
527 
initDecoder()528 bool C2SoftDav1dDec::initDecoder() {
529 #ifdef FILE_DUMP_ENABLE
530     mC2SoftDav1dDump.initDumping();
531 #endif
532     mSignalledError = false;
533     mSignalledOutputEos = false;
534     mHalPixelFormat = HAL_PIXEL_FORMAT_YV12;
535     {
536         IntfImpl::Lock lock = mIntf->lock();
537         mPixelFormatInfo = mIntf->getPixelFormat_l();
538         mActualOutputDelayInfo = mIntf->getActualOutputDelay_l();
539     }
540 
541     const char* version = dav1d_version();
542 
543     Dav1dSettings lib_settings;
544     dav1d_default_settings(&lib_settings);
545     int cpu_count = GetCPUCoreCount();
546     lib_settings.n_threads = std::max(cpu_count / 2, 1);  // use up to half the cores by default.
547 
548     int32_t numThreads =
549             android::base::GetIntProperty(NUM_THREADS_DAV1D_PROPERTY, NUM_THREADS_DAV1D_DEFAULT);
550     if (numThreads > 0) lib_settings.n_threads = numThreads;
551 
552     lib_settings.max_frame_delay = mActualOutputDelayInfo->value;
553 
554     int res = 0;
555     if ((res = dav1d_open(&mDav1dCtx, &lib_settings))) {
556         ALOGE("dav1d_open failed. status: %d.", res);
557         return false;
558     } else {
559         ALOGD("dav1d_open succeeded(n_threads=%d,version=%s).", lib_settings.n_threads, version);
560     }
561 
562     return true;
563 }
564 
destroyDecoder()565 void C2SoftDav1dDec::destroyDecoder() {
566     if (mDav1dCtx) {
567         dav1d_close(&mDav1dCtx);
568         mDav1dCtx = nullptr;
569         mOutputBufferIndex = 0;
570         mInputBufferIndex = 0;
571     }
572 #ifdef FILE_DUMP_ENABLE
573     mC2SoftDav1dDump.destroyDumping();
574 #endif
575 }
576 
fillEmptyWork(const std::unique_ptr<C2Work> & work)577 void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
578     uint32_t flags = 0;
579     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
580         flags |= C2FrameData::FLAG_END_OF_STREAM;
581         ALOGV("signalling end_of_stream.");
582     }
583     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
584     work->worklets.front()->output.buffers.clear();
585     work->worklets.front()->output.ordinal = work->input.ordinal;
586     work->workletsProcessed = 1u;
587 }
588 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2GraphicBlock> & block,const Dav1dPicture & img)589 void C2SoftDav1dDec::finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
590                                 const std::shared_ptr<C2GraphicBlock>& block,
591                                 const Dav1dPicture &img) {
592     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block, C2Rect(mWidth, mHeight));
593     {
594         IntfImpl::Lock lock = mIntf->lock();
595         buffer->setInfo(mIntf->getColorAspects_l());
596     }
597 
598     auto fillWork = [buffer, index, img, this](const std::unique_ptr<C2Work>& work) {
599         uint32_t flags = 0;
600         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
601             (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
602             flags |= C2FrameData::FLAG_END_OF_STREAM;
603             ALOGV("signalling end_of_stream.");
604         }
605         getHDRStaticParams(&img, work);
606         getHDR10PlusInfoData(&img, work);
607 
608         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
609         work->worklets.front()->output.buffers.clear();
610         work->worklets.front()->output.buffers.push_back(buffer);
611         work->worklets.front()->output.ordinal = work->input.ordinal;
612         work->workletsProcessed = 1u;
613     };
614     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
615         fillWork(work);
616     } else {
617         finish(index, fillWork);
618     }
619 }
620 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)621 void C2SoftDav1dDec::process(const std::unique_ptr<C2Work>& work,
622                              const std::shared_ptr<C2BlockPool>& pool) {
623     work->result = C2_OK;
624     work->workletsProcessed = 0u;
625     work->worklets.front()->output.configUpdate.clear();
626     work->worklets.front()->output.flags = work->input.flags;
627     if (mSignalledError || mSignalledOutputEos) {
628         work->result = C2_BAD_VALUE;
629         return;
630     }
631 
632     size_t inOffset = 0u;
633     size_t inSize = 0u;
634     C2ReadView rView = mDummyReadView;
635     if (!work->input.buffers.empty()) {
636         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
637         inSize = rView.capacity();
638         if (inSize && rView.error()) {
639             ALOGE("read view map failed %d", rView.error());
640             work->result = C2_CORRUPTED;
641             return;
642         }
643     }
644 
645     bool codecConfig = ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
646     bool end_of_stream = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
647 
648     if (codecConfig) {
649         fillEmptyWork(work);
650         return;
651     }
652 
653     int64_t in_frameIndex = work->input.ordinal.frameIndex.peekll();
654     if (inSize) {
655         mInputBufferIndex = in_frameIndex;
656 
657         uint8_t* bitstream = const_cast<uint8_t*>(rView.data() + inOffset);
658 
659         mTimeStart = systemTime();
660         nsecs_t delay = mTimeStart - mTimeEnd;
661 
662         // Send the bitstream data (inputBuffer) to dav1d.
663         if (mDav1dCtx) {
664             int i_ret = 0;
665 
666             Dav1dSequenceHeader seq;
667             int res = dav1d_parse_sequence_header(&seq, bitstream, inSize);
668             if (res == 0) {
669                 ALOGV("dav1d found a sequenceHeader (%dx%d) for in_frameIndex=%ld.", seq.max_width,
670                       seq.max_height, (long)in_frameIndex);
671                 if (seq.max_width != mWidth || seq.max_height != mHeight) {
672                     drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
673                     mWidth = seq.max_width;
674                     mHeight = seq.max_height;
675 
676                     C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
677                     std::vector<std::unique_ptr<C2SettingResult>> failures;
678                     c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
679                     if (err == C2_OK) {
680                         work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
681                     } else {
682                         ALOGE("Config update size failed");
683                         mSignalledError = true;
684                         work->result = C2_CORRUPTED;
685                         work->workletsProcessed = 1u;
686                         return;
687                     }
688                 }
689             }
690 
691             // insert OBU TD if it is not present.
692             // TODO: b/286852962
693             uint8_t obu_type = (bitstream[0] >> 3) & 0xf;
694             Dav1dData data;
695 
696             uint8_t* ptr = (obu_type == DAV1D_OBU_TD) ? dav1d_data_create(&data, inSize)
697                                                       : dav1d_data_create(&data, inSize + 2);
698             if (ptr == nullptr) {
699                 ALOGE("dav1d_data_create failed!");
700                 i_ret = -1;
701 
702             } else {
703                 data.m.timestamp = in_frameIndex;
704 
705                 int new_Size;
706                 if (obu_type != DAV1D_OBU_TD) {
707                     new_Size = (int)(inSize + 2);
708 
709                     // OBU TD
710                     ptr[0] = 0x12;
711                     ptr[1] = 0;
712 
713                     memcpy(ptr + 2, bitstream, inSize);
714                 } else {
715                     new_Size = (int)(inSize);
716                     // TODO: b/277797541 - investigate how to wrap this pointer in Dav1dData to
717                     // avoid memcopy operations.
718                     memcpy(ptr, bitstream, new_Size);
719                 }
720 
721                 // ALOGV("memcpy(ptr,bitstream,inSize=%ld,new_Size=%d,in_frameIndex=%ld,timestamp=%ld,"
722                 //       "ptr[0,1,2,3,4]=%x,%x,%x,%x,%x)",
723                 //       inSize, new_Size, frameIndex, data.m.timestamp, ptr[0], ptr[1], ptr[2],
724                 //       ptr[3], ptr[4]);
725 
726                 // Dump the bitstream data (inputBuffer) if dumping is enabled.
727 #ifdef FILE_DUMP_ENABLE
728                 mC2SoftDav1dDump.dumpInput(ptr, new_Size);
729 #endif
730 
731                 bool b_draining = false;
732                 int res;
733 
734                 do {
735                     res = dav1d_send_data(mDav1dCtx, &data);
736                     if (res < 0 && res != DAV1D_ERR(EAGAIN)) {
737                         ALOGE("Decoder feed error %s!", strerror(DAV1D_ERR(res)));
738                         /* bitstream decoding errors (typically DAV1D_ERR(EINVAL), are assumed
739                          * to be recoverable. Other errors returned from this function are
740                          * either unexpected, or considered critical failures.
741                          */
742                         i_ret = res == DAV1D_ERR(EINVAL) ? 0 : -1;
743                         break;
744                     }
745 
746                     outputBuffer(pool, work);
747 
748                 } while (res == DAV1D_ERR(EAGAIN));
749 
750                 if (data.sz > 0) {
751                     ALOGE("unexpected data.sz=%zu after dav1d_send_data", data.sz);
752                     dav1d_data_unref(&data);
753                 }
754             }
755 
756             mTimeEnd = systemTime();
757             nsecs_t decodeTime = mTimeEnd - mTimeStart;
758             // ALOGV("decodeTime=%4" PRId64 " delay=%4" PRId64 "\n", decodeTime, delay);
759 
760             if (i_ret != 0) {
761                 ALOGE("av1 decoder failed to decode frame. status: %d.", i_ret);
762                 work->result = C2_CORRUPTED;
763                 work->workletsProcessed = 1u;
764                 mSignalledError = true;
765                 return;
766             }
767         }
768     }
769 
770     if (end_of_stream) {
771         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
772         mSignalledOutputEos = true;
773     } else if (!inSize) {
774         fillEmptyWork(work);
775     }
776 }
777 
getHDRStaticParams(const Dav1dPicture * picture,const std::unique_ptr<C2Work> & work)778 void C2SoftDav1dDec::getHDRStaticParams(const Dav1dPicture* picture,
779                                         const std::unique_ptr<C2Work>& work) {
780     C2StreamHdrStaticMetadataInfo::output hdrStaticMetadataInfo{};
781     bool infoPresent = false;
782 
783     if (picture != nullptr) {
784         if (picture->mastering_display != nullptr) {
785             hdrStaticMetadataInfo.mastering.red.x =
786                     picture->mastering_display->primaries[0][0] / 65536.0;
787             hdrStaticMetadataInfo.mastering.red.y =
788                     picture->mastering_display->primaries[0][1] / 65536.0;
789 
790             hdrStaticMetadataInfo.mastering.green.x =
791                     picture->mastering_display->primaries[1][0] / 65536.0;
792             hdrStaticMetadataInfo.mastering.green.y =
793                     picture->mastering_display->primaries[1][1] / 65536.0;
794 
795             hdrStaticMetadataInfo.mastering.blue.x =
796                     picture->mastering_display->primaries[2][0] / 65536.0;
797             hdrStaticMetadataInfo.mastering.blue.y =
798                     picture->mastering_display->primaries[2][1] / 65536.0;
799 
800             hdrStaticMetadataInfo.mastering.white.x =
801                     picture->mastering_display->white_point[0] / 65536.0;
802             hdrStaticMetadataInfo.mastering.white.y =
803                     picture->mastering_display->white_point[1] / 65536.0;
804 
805             hdrStaticMetadataInfo.mastering.maxLuminance =
806                     picture->mastering_display->max_luminance / 256.0;
807             hdrStaticMetadataInfo.mastering.minLuminance =
808                     picture->mastering_display->min_luminance / 16384.0;
809 
810             infoPresent = true;
811         }
812 
813         if (picture->content_light != nullptr) {
814             hdrStaticMetadataInfo.maxCll = picture->content_light->max_content_light_level;
815             hdrStaticMetadataInfo.maxFall = picture->content_light->max_frame_average_light_level;
816             infoPresent = true;
817         }
818     }
819 
820     // if (infoPresent) {
821     //   ALOGD("received a hdrStaticMetadataInfo (mastering.red=%f,%f mastering.green=%f,%f
822     //   mastering.blue=%f,%f mastering.white=%f,%f mastering.maxLuminance=%f
823     //   mastering.minLuminance=%f maxCll=%f maxFall=%f) at mOutputBufferIndex=%d.",
824     //   hdrStaticMetadataInfo.mastering.red.x,hdrStaticMetadataInfo.mastering.red.y,
825     //   hdrStaticMetadataInfo.mastering.green.x,hdrStaticMetadataInfo.mastering.green.y,
826     //   hdrStaticMetadataInfo.mastering.blue.x,hdrStaticMetadataInfo.mastering.blue.y,
827     //   hdrStaticMetadataInfo.mastering.white.x,hdrStaticMetadataInfo.mastering.white.y,
828     //   hdrStaticMetadataInfo.mastering.maxLuminance,hdrStaticMetadataInfo.mastering.minLuminance,
829     //   hdrStaticMetadataInfo.maxCll,
830     //   hdrStaticMetadataInfo.maxFall,
831     //   mOutputBufferIndex);
832     // }
833 
834     // config if static info has changed
835     if (infoPresent && !(hdrStaticMetadataInfo == mHdrStaticMetadataInfo)) {
836         mHdrStaticMetadataInfo = hdrStaticMetadataInfo;
837         work->worklets.front()->output.configUpdate.push_back(
838                 C2Param::Copy(mHdrStaticMetadataInfo));
839     }
840 }
841 
getHDR10PlusInfoData(const Dav1dPicture * picture,const std::unique_ptr<C2Work> & work)842 void C2SoftDav1dDec::getHDR10PlusInfoData(const Dav1dPicture* picture,
843                                           const std::unique_ptr<C2Work>& work) {
844     if (picture != nullptr) {
845         if (picture->itut_t35 != nullptr) {
846             std::vector<uint8_t> payload;
847             size_t payloadSize = picture->itut_t35->payload_size;
848             if (payloadSize > 0) {
849                 payload.push_back(picture->itut_t35->country_code);
850                 if (picture->itut_t35->country_code == 0xFF) {
851                     payload.push_back(picture->itut_t35->country_code_extension_byte);
852                 }
853                 payload.insert(payload.end(), picture->itut_t35->payload,
854                                picture->itut_t35->payload + picture->itut_t35->payload_size);
855             }
856 
857             std::unique_ptr<C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
858                     C2StreamHdr10PlusInfo::output::AllocUnique(payload.size());
859             if (!hdr10PlusInfo) {
860                 ALOGE("Hdr10PlusInfo allocation failed");
861                 mSignalledError = true;
862                 work->result = C2_NO_MEMORY;
863                 return;
864             }
865             memcpy(hdr10PlusInfo->m.value, payload.data(), payload.size());
866 
867             // ALOGD("Received a hdr10PlusInfo from picture->itut_t32
868             // (payload_size=%ld,country_code=%d) at mOutputBufferIndex=%d.",
869             // picture->itut_t35->payload_size,
870             // picture->itut_t35->country_code,
871             // mOutputBufferIndex);
872 
873             // config if hdr10Plus info has changed
874             if (nullptr == mHdr10PlusInfo || !(*hdr10PlusInfo == *mHdr10PlusInfo)) {
875                 mHdr10PlusInfo = std::move(hdr10PlusInfo);
876                 work->worklets.front()->output.configUpdate.push_back(std::move(mHdr10PlusInfo));
877             }
878         }
879     }
880 }
881 
getVuiParams(const Dav1dPicture * picture)882 void C2SoftDav1dDec::getVuiParams(const Dav1dPicture* picture) {
883     VuiColorAspects vuiColorAspects;
884 
885     if (picture) {
886         vuiColorAspects.primaries = picture->seq_hdr->pri;
887         vuiColorAspects.transfer = picture->seq_hdr->trc;
888         vuiColorAspects.coeffs = picture->seq_hdr->mtrx;
889         vuiColorAspects.fullRange = picture->seq_hdr->color_range;
890 
891         // ALOGD("Received a vuiColorAspects from dav1d
892         //       (primaries = % d, transfer = % d, coeffs = % d, fullRange = % d)
893         //               at mOutputBufferIndex = % d,
894         //       out_frameIndex = % ld.",
895         //                          vuiColorAspects.primaries,
896         //       vuiColorAspects.transfer, vuiColorAspects.coeffs, vuiColorAspects.fullRange,
897         //       mOutputBufferIndex, picture->m.timestamp);
898     }
899 
900     // convert vui aspects to C2 values if changed
901     if (!(vuiColorAspects == mBitstreamColorAspects)) {
902         mBitstreamColorAspects = vuiColorAspects;
903         ColorAspects sfAspects;
904         C2StreamColorAspectsInfo::input codedAspects = {0u};
905         ColorUtils::convertIsoColorAspectsToCodecAspects(
906                 vuiColorAspects.primaries, vuiColorAspects.transfer, vuiColorAspects.coeffs,
907                 vuiColorAspects.fullRange, sfAspects);
908         if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
909             codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
910         }
911         if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
912             codedAspects.range = C2Color::RANGE_UNSPECIFIED;
913         }
914         if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
915             codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
916         }
917         if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
918             codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
919         }
920         std::vector<std::unique_ptr<C2SettingResult>> failures;
921         mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
922     }
923 }
924 
setError(const std::unique_ptr<C2Work> & work,c2_status_t error)925 void C2SoftDav1dDec::setError(const std::unique_ptr<C2Work>& work, c2_status_t error) {
926     mSignalledError = true;
927     work->result = error;
928     work->workletsProcessed = 1u;
929 }
930 
allocTmpFrameBuffer(size_t size)931 bool C2SoftDav1dDec::allocTmpFrameBuffer(size_t size) {
932     if (size > mTmpFrameBufferSize) {
933         mTmpFrameBuffer = std::make_unique<uint16_t[]>(size);
934         if (mTmpFrameBuffer == nullptr) {
935             mTmpFrameBufferSize = 0;
936             return false;
937         }
938         mTmpFrameBufferSize = size;
939     }
940     return true;
941 }
942 
outputBuffer(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)943 bool C2SoftDav1dDec::outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
944                                   const std::unique_ptr<C2Work>& work) {
945     if (!(work && pool)) return false;
946     if (mDav1dCtx == nullptr) return false;
947 
948     // Get a decoded picture from dav1d if it is enabled.
949     Dav1dPicture img;
950     memset(&img, 0, sizeof(img));
951 
952     int res = 0;
953     res = dav1d_get_picture(mDav1dCtx, &img);
954     if (res == DAV1D_ERR(EAGAIN)) {
955         ALOGV("Not enough data to output a picture.");
956         return false;
957     } else if (res != 0) {
958         ALOGE("The AV1 decoder failed to get a picture (res=%s).", strerror(DAV1D_ERR(res)));
959         return false;
960     }
961 
962     getVuiParams(&img);
963 
964     // out_frameIndex that the decoded picture returns from dav1d.
965     int64_t out_frameIndex = img.m.timestamp;
966 
967     const bool isMonochrome = img.p.layout == DAV1D_PIXEL_LAYOUT_I400;
968 
969     int bitdepth = img.p.bpc;
970 
971     std::shared_ptr<C2GraphicBlock> block;
972     uint32_t format = HAL_PIXEL_FORMAT_YV12;
973     std::shared_ptr<C2StreamColorAspectsInfo::output> codedColorAspects;
974     if (bitdepth == 10 && mPixelFormatInfo->value != HAL_PIXEL_FORMAT_YCBCR_420_888) {
975         IntfImpl::Lock lock = mIntf->lock();
976         codedColorAspects = mIntf->getColorAspects_l();
977         bool allowRGBA1010102 = false;
978         if (codedColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
979             codedColorAspects->matrix == C2Color::MATRIX_BT2020 &&
980             codedColorAspects->transfer == C2Color::TRANSFER_ST2084) {
981             allowRGBA1010102 = true;
982         }
983         format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
984     }
985 
986     if (mHalPixelFormat != format) {
987         C2StreamPixelFormatInfo::output pixelFormat(0u, format);
988         std::vector<std::unique_ptr<C2SettingResult>> failures;
989         c2_status_t err = mIntf->config({&pixelFormat}, C2_MAY_BLOCK, &failures);
990         if (err == C2_OK) {
991             work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(pixelFormat));
992         } else {
993             ALOGE("Config update pixelFormat failed");
994             mSignalledError = true;
995             work->workletsProcessed = 1u;
996             work->result = C2_CORRUPTED;
997             return UNKNOWN_ERROR;
998         }
999         mHalPixelFormat = format;
1000     }
1001 
1002     C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
1003 
1004     // We always create a graphic block that is width aligned to 16 and height
1005     // aligned to 2. We set the correct "crop" value of the image in the call to
1006     // createGraphicBuffer() by setting the correct image dimensions.
1007     c2_status_t err =
1008             pool->fetchGraphicBlock(align(mWidth, 16), align(mHeight, 2), format, usage, &block);
1009 
1010     if (err != C2_OK) {
1011         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
1012         work->result = err;
1013         return false;
1014     }
1015 
1016     C2GraphicView wView = block->map().get();
1017 
1018     if (wView.error()) {
1019         ALOGE("graphic view map failed %d", wView.error());
1020         work->result = C2_CORRUPTED;
1021         return false;
1022     }
1023 
1024     // ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d", block->width(),
1025     //       block->height(), mWidth, mHeight, (int)out_frameIndex);
1026 
1027     mOutputBufferIndex = out_frameIndex;
1028 
1029     uint8_t* dstY = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_Y]);
1030     uint8_t* dstU = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_U]);
1031     uint8_t* dstV = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_V]);
1032 
1033     C2PlanarLayout layout = wView.layout();
1034     size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
1035     size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
1036     size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
1037 
1038     CONV_FORMAT_T convFormat;
1039     switch (img.p.layout) {
1040         case DAV1D_PIXEL_LAYOUT_I444:
1041             convFormat = CONV_FORMAT_I444;
1042             break;
1043         case DAV1D_PIXEL_LAYOUT_I422:
1044             convFormat = CONV_FORMAT_I422;
1045             break;
1046         default:
1047             convFormat = CONV_FORMAT_I420;
1048             break;
1049     }
1050 
1051     if (bitdepth == 10) {
1052         // TODO: b/277797541 - Investigate if we can ask DAV1D to output the required format during
1053         // decompression to avoid color conversion.
1054         const uint16_t* srcY = (const uint16_t*)img.data[0];
1055         const uint16_t* srcU = (const uint16_t*)img.data[1];
1056         const uint16_t* srcV = (const uint16_t*)img.data[2];
1057         size_t srcYStride = img.stride[0] / 2;
1058         size_t srcUStride = img.stride[1] / 2;
1059         size_t srcVStride = img.stride[1] / 2;
1060 
1061         if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
1062             if (isMonochrome) {
1063                 const size_t tmpSize = mWidth;
1064                 const bool needFill = tmpSize > mTmpFrameBufferSize;
1065                 if (!allocTmpFrameBuffer(tmpSize)) {
1066                     ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
1067                     setError(work, C2_NO_MEMORY);
1068                     return false;
1069                 }
1070                 srcU = srcV = mTmpFrameBuffer.get();
1071                 srcUStride = srcVStride = 0;
1072                 if (needFill) {
1073                     std::fill_n(mTmpFrameBuffer.get(), tmpSize, 512);
1074                 }
1075             }
1076             convertPlanar16ToY410OrRGBA1010102(
1077                     dstY, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
1078                     dstYStride, mWidth, mHeight,
1079                     std::static_pointer_cast<const C2ColorAspectsStruct>(codedColorAspects),
1080                     convFormat);
1081         } else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
1082             dstYStride /= 2;
1083             dstUStride /= 2;
1084             dstVStride /= 2;
1085             size_t tmpSize = 0;
1086             if ((img.p.layout == DAV1D_PIXEL_LAYOUT_I444) ||
1087                 (img.p.layout == DAV1D_PIXEL_LAYOUT_I422)) {
1088                 tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
1089                 if (!allocTmpFrameBuffer(tmpSize)) {
1090                     ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
1091                     setError(work, C2_NO_MEMORY);
1092                     return false;
1093                 }
1094             }
1095             convertPlanar16ToP010((uint16_t*)dstY, (uint16_t*)dstU, srcY, srcU, srcV, srcYStride,
1096                                   srcUStride, srcVStride, dstYStride, dstUStride, dstVStride,
1097                                   mWidth, mHeight, isMonochrome, convFormat, mTmpFrameBuffer.get(),
1098                                   tmpSize);
1099         } else {
1100             size_t tmpSize = 0;
1101             if (img.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
1102                 tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
1103                 if (!allocTmpFrameBuffer(tmpSize)) {
1104                     ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
1105                     setError(work, C2_NO_MEMORY);
1106                     return false;
1107                 }
1108             }
1109             convertPlanar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
1110                                   srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight,
1111                                   isMonochrome, convFormat, mTmpFrameBuffer.get(), tmpSize);
1112         }
1113 
1114         // if(mOutputBufferIndex % 100 == 0)
1115         ALOGV("output a 10bit picture %dx%d from dav1d "
1116               "(mInputBufferIndex=%d,mOutputBufferIndex=%d,format=%d).",
1117               mWidth, mHeight, mInputBufferIndex, mOutputBufferIndex, format);
1118 
1119         // Dump the output buffer if dumping is enabled (debug only).
1120 #ifdef FILE_DUMP_ENABLE
1121         mC2SoftDav1dDump.dumpOutput<uint16_t>(srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
1122                                               mWidth, mHeight);
1123 #endif
1124     } else {
1125         const uint8_t* srcY = (const uint8_t*)img.data[0];
1126         const uint8_t* srcU = (const uint8_t*)img.data[1];
1127         const uint8_t* srcV = (const uint8_t*)img.data[2];
1128 
1129         size_t srcYStride = img.stride[0];
1130         size_t srcUStride = img.stride[1];
1131         size_t srcVStride = img.stride[1];
1132 
1133         // if(mOutputBufferIndex % 100 == 0)
1134         ALOGV("output a 8bit picture %dx%d from dav1d "
1135               "(mInputBufferIndex=%d,mOutputBufferIndex=%d,format=%d).",
1136               mWidth, mHeight, mInputBufferIndex, mOutputBufferIndex, format);
1137 
1138         // Dump the output buffer is dumping is enabled (debug only)
1139 #ifdef FILE_DUMP_ENABLE
1140         mC2SoftDav1dDump.dumpOutput<uint8_t>(srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
1141                                              mWidth, mHeight);
1142 #endif
1143         convertPlanar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
1144                              dstYStride, dstUStride, dstVStride, mWidth, mHeight, isMonochrome,
1145                              convFormat);
1146     }
1147 
1148     finishWork(out_frameIndex, work, std::move(block), img);
1149     dav1d_picture_unref(&img);
1150     block = nullptr;
1151     return true;
1152 }
1153 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1154 c2_status_t C2SoftDav1dDec::drainInternal(uint32_t drainMode,
1155                                           const std::shared_ptr<C2BlockPool>& pool,
1156                                           const std::unique_ptr<C2Work>& work) {
1157     if (drainMode == NO_DRAIN) {
1158         ALOGW("drain with NO_DRAIN: no-op");
1159         return C2_OK;
1160     }
1161     if (drainMode == DRAIN_CHAIN) {
1162         ALOGW("DRAIN_CHAIN not supported");
1163         return C2_OMITTED;
1164     }
1165 
1166     while (outputBuffer(pool, work)) {
1167     }
1168 
1169     if (drainMode == DRAIN_COMPONENT_WITH_EOS && work && work->workletsProcessed == 0u) {
1170         fillEmptyWork(work);
1171     }
1172 
1173     return C2_OK;
1174 }
1175 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1176 c2_status_t C2SoftDav1dDec::drain(uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool) {
1177     return drainInternal(drainMode, pool, nullptr);
1178 }
1179 
1180 class C2SoftDav1dFactory : public C2ComponentFactory {
1181   public:
C2SoftDav1dFactory()1182     C2SoftDav1dFactory()
1183         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1184                   GetCodec2PlatformComponentStore()->getParamReflector())) {}
1185 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1186     virtual c2_status_t createComponent(c2_node_id_t id,
1187                                         std::shared_ptr<C2Component>* const component,
1188                                         std::function<void(C2Component*)> deleter) override {
1189         *component = std::shared_ptr<C2Component>(
1190                 new C2SoftDav1dDec(COMPONENT_NAME, id,
1191                                    std::make_shared<C2SoftDav1dDec::IntfImpl>(mHelper)),
1192                 deleter);
1193         return C2_OK;
1194     }
1195 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1196     virtual c2_status_t createInterface(
1197             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
1198             std::function<void(C2ComponentInterface*)> deleter) override {
1199         *interface = std::shared_ptr<C2ComponentInterface>(
1200                 new SimpleInterface<C2SoftDav1dDec::IntfImpl>(
1201                         COMPONENT_NAME, id, std::make_shared<C2SoftDav1dDec::IntfImpl>(mHelper)),
1202                 deleter);
1203         return C2_OK;
1204     }
1205 
1206     virtual ~C2SoftDav1dFactory() override = default;
1207 
1208   private:
1209     std::shared_ptr<C2ReflectorHelper> mHelper;
1210 };
1211 
1212 }  // namespace android
1213 
CreateCodec2Factory()1214 __attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1215     ALOGV("in %s", __func__);
1216     return new ::android::C2SoftDav1dFactory();
1217 }
1218 
DestroyCodec2Factory(::C2ComponentFactory * factory)1219 __attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory(
1220         ::C2ComponentFactory* factory) {
1221     ALOGV("in %s", __func__);
1222     delete factory;
1223 }
1224