blob: 7bd33581d957043fb5022faee0aac44ed20b131b [file] [log] [blame]
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -07001/*
2 * Copyright (C) 2019 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 "C2SoftGav1Dec"
19#include "C2SoftGav1Dec.h"
20
21#include <C2Debug.h>
22#include <C2PlatformSupport.h>
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +053023#include <Codec2Mapper.h>
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -070024#include <SimpleC2Interface.h>
25#include <log/log.h>
26#include <media/stagefright/foundation/AUtils.h>
27#include <media/stagefright/foundation/MediaDefs.h>
28
29namespace android {
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -080030namespace {
31
32constexpr uint8_t NEUTRAL_UV_VALUE = 128;
33
34} // namespace
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -070035
Ray Essickc2cc4372019-08-21 14:02:28 -070036// codecname set and passed in as a compile flag from Android.bp
37constexpr char COMPONENT_NAME[] = CODECNAME;
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -070038
39class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
40 public:
41 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
42 : SimpleInterface<void>::BaseParams(
43 helper, COMPONENT_NAME, C2Component::KIND_DECODER,
44 C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
45 noPrivateBuffers(); // TODO: account for our buffers here.
46 noInputReferences();
47 noOutputReferences();
48 noInputLatency();
49 noTimeStretch();
50
51 addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
52 .withConstValue(new C2ComponentAttributesSetting(
53 C2Component::ATTRIB_IS_TEMPORAL))
54 .build());
55
56 addParameter(
57 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
58 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
59 .withFields({
Vignesh Venkatasubramanian2d8d4702021-01-25 09:42:44 -080060 C2F(mSize, width).inRange(2, 4096, 2),
61 C2F(mSize, height).inRange(2, 4096, 2),
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -070062 })
63 .withSetter(SizeSetter)
64 .build());
65
66 addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
67 .withDefault(new C2StreamProfileLevelInfo::input(
68 0u, C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
69 .withFields({C2F(mProfileLevel, profile)
70 .oneOf({C2Config::PROFILE_AV1_0,
71 C2Config::PROFILE_AV1_1}),
72 C2F(mProfileLevel, level)
73 .oneOf({
Harish Mahendrakar1ad8c3b2021-06-04 15:42:31 -070074 C2Config::LEVEL_AV1_2, C2Config::LEVEL_AV1_2_1,
75 C2Config::LEVEL_AV1_2_2, C2Config::LEVEL_AV1_2_3,
76 C2Config::LEVEL_AV1_3, C2Config::LEVEL_AV1_3_1,
77 C2Config::LEVEL_AV1_3_2, C2Config::LEVEL_AV1_3_3,
78 C2Config::LEVEL_AV1_4, C2Config::LEVEL_AV1_4_1,
79 C2Config::LEVEL_AV1_4_2, C2Config::LEVEL_AV1_4_3,
80 C2Config::LEVEL_AV1_5, C2Config::LEVEL_AV1_5_1,
81 C2Config::LEVEL_AV1_5_2, C2Config::LEVEL_AV1_5_3,
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -070082 })})
83 .withSetter(ProfileLevelSetter, mSize)
84 .build());
85
86 mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
87 addParameter(
88 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
89 .withDefault(mHdr10PlusInfoInput)
90 .withFields({
91 C2F(mHdr10PlusInfoInput, m.value).any(),
92 })
93 .withSetter(Hdr10PlusInfoInputSetter)
94 .build());
95
96 mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
97 addParameter(
98 DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
99 .withDefault(mHdr10PlusInfoOutput)
100 .withFields({
101 C2F(mHdr10PlusInfoOutput, m.value).any(),
102 })
103 .withSetter(Hdr10PlusInfoOutputSetter)
104 .build());
105
106 addParameter(
107 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
108 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
109 .withFields({
110 C2F(mSize, width).inRange(2, 2048, 2),
111 C2F(mSize, height).inRange(2, 2048, 2),
112 })
113 .withSetter(MaxPictureSizeSetter, mSize)
114 .build());
115
116 addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
117 .withDefault(new C2StreamMaxBufferSizeInfo::input(
118 0u, 320 * 240 * 3 / 4))
119 .withFields({
120 C2F(mMaxInputSize, value).any(),
121 })
122 .calculatedAs(MaxInputSizeSetter, mMaxSize)
123 .build());
124
125 C2ChromaOffsetStruct locations[1] = {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)
147 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
148 C2F(mDefaultColorAspects, primaries)
149 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
150 C2Color::PRIMARIES_OTHER),
151 C2F(mDefaultColorAspects, transfer)
152 .inRange(C2Color::TRANSFER_UNSPECIFIED,
153 C2Color::TRANSFER_OTHER),
154 C2F(mDefaultColorAspects, matrix)
155 .inRange(C2Color::MATRIX_UNSPECIFIED,
156 C2Color::MATRIX_OTHER)})
157 .withSetter(DefaultColorAspectsSetter)
158 .build());
159
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530160 addParameter(
161 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
162 .withDefault(new C2StreamColorAspectsInfo::input(
163 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
164 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
165 .withFields({
166 C2F(mCodedColorAspects, range).inRange(
167 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
168 C2F(mCodedColorAspects, primaries).inRange(
169 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
170 C2F(mCodedColorAspects, transfer).inRange(
171 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
172 C2F(mCodedColorAspects, matrix).inRange(
173 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
174 })
175 .withSetter(CodedColorAspectsSetter)
176 .build());
177
178 addParameter(
179 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
180 .withDefault(new C2StreamColorAspectsInfo::output(
181 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
182 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
183 .withFields({
184 C2F(mColorAspects, range).inRange(
185 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
186 C2F(mColorAspects, primaries).inRange(
187 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
188 C2F(mColorAspects, transfer).inRange(
189 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
190 C2F(mColorAspects, matrix).inRange(
191 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
192 })
193 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
194 .build());
195
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700196 // TODO: support more formats?
197 addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
198 .withConstValue(new C2StreamPixelFormatInfo::output(
199 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
200 .build());
201 }
202
203 static C2R SizeSetter(bool mayBlock,
204 const C2P<C2StreamPictureSizeInfo::output> &oldMe,
205 C2P<C2StreamPictureSizeInfo::output> &me) {
206 (void)mayBlock;
207 C2R res = C2R::Ok();
208 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
209 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
210 me.set().width = oldMe.v.width;
211 }
212 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
213 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
214 me.set().height = oldMe.v.height;
215 }
216 return res;
217 }
218
219 static C2R MaxPictureSizeSetter(
220 bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
221 const C2P<C2StreamPictureSizeInfo::output> &size) {
222 (void)mayBlock;
223 // TODO: get max width/height from the size's field helpers vs.
224 // hardcoding
225 me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
226 me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
227 return C2R::Ok();
228 }
229
230 static C2R MaxInputSizeSetter(
231 bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
232 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
233 (void)mayBlock;
234 // assume compression ratio of 2
235 me.set().value =
236 (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
237 return C2R::Ok();
238 }
239
240 static C2R DefaultColorAspectsSetter(
241 bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
242 (void)mayBlock;
243 if (me.v.range > C2Color::RANGE_OTHER) {
244 me.set().range = C2Color::RANGE_OTHER;
245 }
246 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
247 me.set().primaries = C2Color::PRIMARIES_OTHER;
248 }
249 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
250 me.set().transfer = C2Color::TRANSFER_OTHER;
251 }
252 if (me.v.matrix > C2Color::MATRIX_OTHER) {
253 me.set().matrix = C2Color::MATRIX_OTHER;
254 }
255 return C2R::Ok();
256 }
257
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530258 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
259 (void)mayBlock;
260 if (me.v.range > C2Color::RANGE_OTHER) {
261 me.set().range = C2Color::RANGE_OTHER;
262 }
263 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
264 me.set().primaries = C2Color::PRIMARIES_OTHER;
265 }
266 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
267 me.set().transfer = C2Color::TRANSFER_OTHER;
268 }
269 if (me.v.matrix > C2Color::MATRIX_OTHER) {
270 me.set().matrix = C2Color::MATRIX_OTHER;
271 }
272 return C2R::Ok();
273 }
274
275 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
276 const C2P<C2StreamColorAspectsTuning::output> &def,
277 const C2P<C2StreamColorAspectsInfo::input> &coded) {
278 (void)mayBlock;
279 // take default values for all unspecified fields, and coded values for specified ones
280 me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
281 me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
282 ? def.v.primaries : coded.v.primaries;
283 me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
284 ? def.v.transfer : coded.v.transfer;
285 me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
286 return C2R::Ok();
287 }
288
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700289 static C2R ProfileLevelSetter(
290 bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
291 const C2P<C2StreamPictureSizeInfo::output> &size) {
292 (void)mayBlock;
293 (void)size;
294 (void)me; // TODO: validate
295 return C2R::Ok();
296 }
297
298 std::shared_ptr<C2StreamColorAspectsTuning::output>
299 getDefaultColorAspects_l() {
300 return mDefaultColorAspects;
301 }
302
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530303 std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
304 return mColorAspects;
305 }
306
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700307 static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
308 C2P<C2StreamHdr10PlusInfo::input> &me) {
309 (void)mayBlock;
310 (void)me; // TODO: validate
311 return C2R::Ok();
312 }
313
314 static C2R Hdr10PlusInfoOutputSetter(bool mayBlock,
315 C2P<C2StreamHdr10PlusInfo::output> &me) {
316 (void)mayBlock;
317 (void)me; // TODO: validate
318 return C2R::Ok();
319 }
320
321 private:
322 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
323 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
324 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
325 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
326 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
327 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
328 std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530329 std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
330 std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700331 std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
332 std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
333};
334
335C2SoftGav1Dec::C2SoftGav1Dec(const char *name, c2_node_id_t id,
336 const std::shared_ptr<IntfImpl> &intfImpl)
337 : SimpleC2Component(
338 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700339 mIntf(intfImpl),
340 mCodecCtx(nullptr) {
341 gettimeofday(&mTimeStart, nullptr);
342 gettimeofday(&mTimeEnd, nullptr);
343}
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700344
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700345C2SoftGav1Dec::~C2SoftGav1Dec() { onRelease(); }
346
347c2_status_t C2SoftGav1Dec::onInit() {
348 return initDecoder() ? C2_OK : C2_CORRUPTED;
349}
350
351c2_status_t C2SoftGav1Dec::onStop() {
352 mSignalledError = false;
353 mSignalledOutputEos = false;
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700354 return C2_OK;
355}
356
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700357void C2SoftGav1Dec::onReset() {
358 (void)onStop();
359 c2_status_t err = onFlush_sm();
360 if (err != C2_OK) {
361 ALOGW("Failed to flush the av1 decoder. Trying to hard reset.");
362 destroyDecoder();
363 if (!initDecoder()) {
364 ALOGE("Hard reset failed.");
365 }
366 }
367}
368
369void C2SoftGav1Dec::onRelease() { destroyDecoder(); }
370
371c2_status_t C2SoftGav1Dec::onFlush_sm() {
James Zernb7aee6e2020-06-26 13:49:53 -0700372 Libgav1StatusCode status = mCodecCtx->SignalEOS();
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700373 if (status != kLibgav1StatusOk) {
374 ALOGE("Failed to flush av1 decoder. status: %d.", status);
375 return C2_CORRUPTED;
376 }
377
378 // Dequeue frame (if any) that was enqueued previously.
379 const libgav1::DecoderBuffer *buffer;
380 status = mCodecCtx->DequeueFrame(&buffer);
James Zernb7aee6e2020-06-26 13:49:53 -0700381 if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) {
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700382 ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d",
383 status);
384 return C2_CORRUPTED;
385 }
386
387 mSignalledError = false;
388 mSignalledOutputEos = false;
389
390 return C2_OK;
391}
392
393static int GetCPUCoreCount() {
394 int cpuCoreCount = 1;
395#if defined(_SC_NPROCESSORS_ONLN)
396 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
397#else
398 // _SC_NPROC_ONLN must be defined...
399 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
400#endif
401 CHECK(cpuCoreCount >= 1);
402 ALOGV("Number of CPU cores: %d", cpuCoreCount);
403 return cpuCoreCount;
404}
405
406bool C2SoftGav1Dec::initDecoder() {
407 mSignalledError = false;
408 mSignalledOutputEos = false;
409 mCodecCtx.reset(new libgav1::Decoder());
410
411 if (mCodecCtx == nullptr) {
412 ALOGE("mCodecCtx is null");
413 return false;
414 }
415
416 libgav1::DecoderSettings settings = {};
417 settings.threads = GetCPUCoreCount();
418
Vignesh Venkatasubramanian61ba2cf2019-06-24 10:04:00 -0700419 ALOGV("Using libgav1 AV1 software decoder.");
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700420 Libgav1StatusCode status = mCodecCtx->Init(&settings);
421 if (status != kLibgav1StatusOk) {
422 ALOGE("av1 decoder failed to initialize. status: %d.", status);
423 return false;
424 }
425
426 return true;
427}
428
429void C2SoftGav1Dec::destroyDecoder() { mCodecCtx = nullptr; }
430
431void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
432 uint32_t flags = 0;
433 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
434 flags |= C2FrameData::FLAG_END_OF_STREAM;
435 ALOGV("signalling eos");
436 }
437 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
438 work->worklets.front()->output.buffers.clear();
439 work->worklets.front()->output.ordinal = work->input.ordinal;
440 work->workletsProcessed = 1u;
441}
442
443void C2SoftGav1Dec::finishWork(uint64_t index,
444 const std::unique_ptr<C2Work> &work,
445 const std::shared_ptr<C2GraphicBlock> &block) {
446 std::shared_ptr<C2Buffer> buffer =
447 createGraphicBuffer(block, C2Rect(mWidth, mHeight));
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530448 {
449 IntfImpl::Lock lock = mIntf->lock();
450 buffer->setInfo(mIntf->getColorAspects_l());
451 }
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700452 auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
453 uint32_t flags = 0;
454 if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
455 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
456 flags |= C2FrameData::FLAG_END_OF_STREAM;
457 ALOGV("signalling eos");
458 }
459 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
460 work->worklets.front()->output.buffers.clear();
461 work->worklets.front()->output.buffers.push_back(buffer);
462 work->worklets.front()->output.ordinal = work->input.ordinal;
463 work->workletsProcessed = 1u;
464 };
465 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
466 fillWork(work);
467 } else {
468 finish(index, fillWork);
469 }
470}
471
472void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work,
473 const std::shared_ptr<C2BlockPool> &pool) {
474 work->result = C2_OK;
475 work->workletsProcessed = 0u;
476 work->worklets.front()->output.configUpdate.clear();
477 work->worklets.front()->output.flags = work->input.flags;
478 if (mSignalledError || mSignalledOutputEos) {
479 work->result = C2_BAD_VALUE;
480 return;
481 }
482
483 size_t inOffset = 0u;
484 size_t inSize = 0u;
485 C2ReadView rView = mDummyReadView;
486 if (!work->input.buffers.empty()) {
487 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
488 inSize = rView.capacity();
489 if (inSize && rView.error()) {
490 ALOGE("read view map failed %d", rView.error());
491 work->result = C2_CORRUPTED;
492 return;
493 }
494 }
495
496 bool codecConfig =
497 ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
498 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
499
500 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
501 (int)work->input.ordinal.timestamp.peeku(),
502 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
503
504 if (codecConfig) {
505 fillEmptyWork(work);
506 return;
507 }
508
509 int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
510 if (inSize) {
511 uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
512 int32_t decodeTime = 0;
513 int32_t delay = 0;
514
515 GETTIME(&mTimeStart, nullptr);
516 TIME_DIFF(mTimeEnd, mTimeStart, delay);
517
518 const Libgav1StatusCode status =
James Zernb7aee6e2020-06-26 13:49:53 -0700519 mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex,
520 /*buffer_private_data=*/nullptr);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700521
522 GETTIME(&mTimeEnd, nullptr);
523 TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
524 ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
525
526 if (status != kLibgav1StatusOk) {
527 ALOGE("av1 decoder failed to decode frame. status: %d.", status);
528 work->result = C2_CORRUPTED;
529 work->workletsProcessed = 1u;
530 mSignalledError = true;
531 return;
532 }
533
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700534 }
535
536 (void)outputBuffer(pool, work);
537
538 if (eos) {
539 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
540 mSignalledOutputEos = true;
541 } else if (!inSize) {
542 fillEmptyWork(work);
543 }
544}
545
ming.zhouac19c3d2019-10-11 11:14:07 +0800546static void copyOutputBufferToYV12Frame(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
547 const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
548 size_t srcYStride, size_t srcUStride, size_t srcVStride,
549 size_t dstYStride, size_t dstUVStride,
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800550 uint32_t width, uint32_t height,
551 bool isMonochrome) {
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700552
553 for (size_t i = 0; i < height; ++i) {
ming.zhouac19c3d2019-10-11 11:14:07 +0800554 memcpy(dstY, srcY, width);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700555 srcY += srcYStride;
ming.zhouac19c3d2019-10-11 11:14:07 +0800556 dstY += dstYStride;
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700557 }
558
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800559 if (isMonochrome) {
560 // Fill with neutral U/V values.
561 for (size_t i = 0; i < height / 2; ++i) {
562 memset(dstV, NEUTRAL_UV_VALUE, width / 2);
563 memset(dstU, NEUTRAL_UV_VALUE, width / 2);
564 dstV += dstUVStride;
565 dstU += dstUVStride;
566 }
567 return;
568 }
569
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700570 for (size_t i = 0; i < height / 2; ++i) {
ming.zhouac19c3d2019-10-11 11:14:07 +0800571 memcpy(dstV, srcV, width / 2);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700572 srcV += srcVStride;
ming.zhouac19c3d2019-10-11 11:14:07 +0800573 dstV += dstUVStride;
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700574 }
575
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700576 for (size_t i = 0; i < height / 2; ++i) {
ming.zhouac19c3d2019-10-11 11:14:07 +0800577 memcpy(dstU, srcU, width / 2);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700578 srcU += srcUStride;
ming.zhouac19c3d2019-10-11 11:14:07 +0800579 dstU += dstUVStride;
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700580 }
581}
582
583static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY,
584 const uint16_t *srcU,
585 const uint16_t *srcV, size_t srcYStride,
586 size_t srcUStride, size_t srcVStride,
587 size_t dstStride, size_t width,
588 size_t height) {
589 // Converting two lines at a time, slightly faster
590 for (size_t y = 0; y < height; y += 2) {
591 uint32_t *dstTop = (uint32_t *)dst;
592 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
593 uint16_t *ySrcTop = (uint16_t *)srcY;
594 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
595 uint16_t *uSrc = (uint16_t *)srcU;
596 uint16_t *vSrc = (uint16_t *)srcV;
597
598 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
599 size_t x = 0;
600 for (; x < width - 3; x += 4) {
601 u01 = *((uint32_t *)uSrc);
602 uSrc += 2;
603 v01 = *((uint32_t *)vSrc);
604 vSrc += 2;
605
606 y01 = *((uint32_t *)ySrcTop);
607 ySrcTop += 2;
608 y23 = *((uint32_t *)ySrcTop);
609 ySrcTop += 2;
610 y45 = *((uint32_t *)ySrcBot);
611 ySrcBot += 2;
612 y67 = *((uint32_t *)ySrcBot);
613 ySrcBot += 2;
614
615 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
616 uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
617
618 *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
619 *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
620 *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
621 *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
622
623 *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
624 *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
625 *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
626 *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
627 }
628
629 // There should be at most 2 more pixels to process. Note that we don't
630 // need to consider odd case as the buffer is always aligned to even.
631 if (x < width) {
632 u01 = *uSrc;
633 v01 = *vSrc;
634 y01 = *((uint32_t *)ySrcTop);
635 y45 = *((uint32_t *)ySrcBot);
636 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
637 *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
638 *dstTop++ = ((y01 >> 16) << 10) | uv0;
639 *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
640 *dstBot++ = ((y45 >> 16) << 10) | uv0;
641 }
642
643 srcY += srcYStride * 2;
644 srcU += srcUStride;
645 srcV += srcVStride;
646 dst += dstStride * 2;
647 }
648}
649
650static void convertYUV420Planar16ToYUV420Planar(
ming.zhouac19c3d2019-10-11 11:14:07 +0800651 uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
652 const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
653 size_t srcYStride, size_t srcUStride, size_t srcVStride,
654 size_t dstYStride, size_t dstUVStride,
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800655 size_t width, size_t height, bool isMonochrome) {
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700656
657 for (size_t y = 0; y < height; ++y) {
658 for (size_t x = 0; x < width; ++x) {
659 dstY[x] = (uint8_t)(srcY[x] >> 2);
660 }
661
662 srcY += srcYStride;
ming.zhouac19c3d2019-10-11 11:14:07 +0800663 dstY += dstYStride;
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700664 }
665
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800666 if (isMonochrome) {
667 // Fill with neutral U/V values.
668 for (size_t y = 0; y < (height + 1) / 2; ++y) {
669 memset(dstV, NEUTRAL_UV_VALUE, (width + 1) / 2);
670 memset(dstU, NEUTRAL_UV_VALUE, (width + 1) / 2);
671 dstV += dstUVStride;
672 dstU += dstUVStride;
673 }
674 return;
675 }
676
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700677 for (size_t y = 0; y < (height + 1) / 2; ++y) {
678 for (size_t x = 0; x < (width + 1) / 2; ++x) {
679 dstU[x] = (uint8_t)(srcU[x] >> 2);
680 dstV[x] = (uint8_t)(srcV[x] >> 2);
681 }
682
683 srcU += srcUStride;
684 srcV += srcVStride;
685 dstU += dstUVStride;
686 dstV += dstUVStride;
687 }
688}
689
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530690void C2SoftGav1Dec::getVuiParams(const libgav1::DecoderBuffer *buffer) {
691 VuiColorAspects vuiColorAspects;
692 vuiColorAspects.primaries = buffer->color_primary;
693 vuiColorAspects.transfer = buffer->transfer_characteristics;
694 vuiColorAspects.coeffs = buffer->matrix_coefficients;
695 vuiColorAspects.fullRange = buffer->color_range;
696
697 // convert vui aspects to C2 values if changed
698 if (!(vuiColorAspects == mBitstreamColorAspects)) {
699 mBitstreamColorAspects = vuiColorAspects;
700 ColorAspects sfAspects;
701 C2StreamColorAspectsInfo::input codedAspects = { 0u };
702 ColorUtils::convertIsoColorAspectsToCodecAspects(
703 vuiColorAspects.primaries, vuiColorAspects.transfer, vuiColorAspects.coeffs,
704 vuiColorAspects.fullRange, sfAspects);
705 if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
706 codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
707 }
708 if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
709 codedAspects.range = C2Color::RANGE_UNSPECIFIED;
710 }
711 if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
712 codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
713 }
714 if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
715 codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
716 }
717 std::vector<std::unique_ptr<C2SettingResult>> failures;
718 mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
719 }
720}
721
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700722bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
723 const std::unique_ptr<C2Work> &work) {
724 if (!(work && pool)) return false;
725
726 const libgav1::DecoderBuffer *buffer;
727 const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer);
728
James Zernb7aee6e2020-06-26 13:49:53 -0700729 if (status != kLibgav1StatusOk && status != kLibgav1StatusNothingToDequeue) {
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700730 ALOGE("av1 decoder DequeueFrame failed. status: %d.", status);
731 return false;
732 }
733
James Zernb7aee6e2020-06-26 13:49:53 -0700734 // |buffer| can be NULL if status was equal to kLibgav1StatusOk or
735 // kLibgav1StatusNothingToDequeue. This is not an error. This could mean one
736 // of two things:
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700737 // - The EnqueueFrame() call was either a flush (called with nullptr).
738 // - The enqueued frame did not have any displayable frames.
739 if (!buffer) {
740 return false;
741 }
742
743 const int width = buffer->displayed_width[0];
744 const int height = buffer->displayed_height[0];
745 if (width != mWidth || height != mHeight) {
746 mWidth = width;
747 mHeight = height;
748
749 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
750 std::vector<std::unique_ptr<C2SettingResult>> failures;
751 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
752 if (err == C2_OK) {
753 work->worklets.front()->output.configUpdate.push_back(
754 C2Param::Copy(size));
755 } else {
756 ALOGE("Config update size failed");
757 mSignalledError = true;
758 work->result = C2_CORRUPTED;
759 work->workletsProcessed = 1u;
760 return false;
761 }
762 }
763
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530764 getVuiParams(buffer);
James Zern4d25d652021-06-22 18:10:13 -0700765 if (!(buffer->image_format == libgav1::kImageFormatYuv420 ||
766 buffer->image_format == libgav1::kImageFormatMonochrome400)) {
767 ALOGE("image_format %d not supported", buffer->image_format);
768 mSignalledError = true;
769 work->workletsProcessed = 1u;
770 work->result = C2_CORRUPTED;
771 return false;
772 }
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800773 const bool isMonochrome =
774 buffer->image_format == libgav1::kImageFormatMonochrome400;
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700775
776 std::shared_ptr<C2GraphicBlock> block;
777 uint32_t format = HAL_PIXEL_FORMAT_YV12;
778 if (buffer->bitdepth == 10) {
779 IntfImpl::Lock lock = mIntf->lock();
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530780 std::shared_ptr<C2StreamColorAspectsInfo::output> codedColorAspects =
781 mIntf->getColorAspects_l();
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700782
Neelkamal Semwalc13a76a2021-09-01 17:07:30 +0530783 if (codedColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
784 codedColorAspects->matrix == C2Color::MATRIX_BT2020 &&
785 codedColorAspects->transfer == C2Color::TRANSFER_ST2084) {
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800786 if (buffer->image_format != libgav1::kImageFormatYuv420) {
787 ALOGE("Only YUV420 output is supported when targeting RGBA_1010102");
788 mSignalledError = true;
789 work->result = C2_OMITTED;
790 work->workletsProcessed = 1u;
791 return false;
792 }
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700793 format = HAL_PIXEL_FORMAT_RGBA_1010102;
794 }
795 }
796 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
797
798 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format,
799 usage, &block);
800
801 if (err != C2_OK) {
802 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
803 work->result = err;
804 return false;
805 }
806
807 C2GraphicView wView = block->map().get();
808
809 if (wView.error()) {
810 ALOGE("graphic view map failed %d", wView.error());
811 work->result = C2_CORRUPTED;
812 return false;
813 }
814
815 ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d", block->width(),
816 block->height(), mWidth, mHeight, (int)buffer->user_private_data);
817
ming.zhouac19c3d2019-10-11 11:14:07 +0800818 uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
819 uint8_t *dstU = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
820 uint8_t *dstV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_V]);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700821 size_t srcYStride = buffer->stride[0];
822 size_t srcUStride = buffer->stride[1];
823 size_t srcVStride = buffer->stride[2];
824
ming.zhouac19c3d2019-10-11 11:14:07 +0800825 C2PlanarLayout layout = wView.layout();
826 size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
827 size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
828
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700829 if (buffer->bitdepth == 10) {
830 const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
831 const uint16_t *srcU = (const uint16_t *)buffer->plane[1];
832 const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
833
834 if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
835 convertYUV420Planar16ToY410(
ming.zhouac19c3d2019-10-11 11:14:07 +0800836 (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
James Zern8dfb3f22020-08-07 18:49:51 -0700837 srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700838 } else {
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800839 convertYUV420Planar16ToYUV420Planar(
840 dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
841 srcVStride / 2, dstYStride, dstUVStride, mWidth, mHeight,
842 isMonochrome);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700843 }
844 } else {
845 const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
846 const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
847 const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
Vignesh Venkatasubramanianca7d1ab2021-02-04 12:39:06 -0800848 copyOutputBufferToYV12Frame(
849 dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
850 dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700851 }
852 finishWork(buffer->user_private_data, work, std::move(block));
853 block = nullptr;
854 return true;
855}
856
857c2_status_t C2SoftGav1Dec::drainInternal(
858 uint32_t drainMode, const std::shared_ptr<C2BlockPool> &pool,
859 const std::unique_ptr<C2Work> &work) {
860 if (drainMode == NO_DRAIN) {
861 ALOGW("drain with NO_DRAIN: no-op");
862 return C2_OK;
863 }
864 if (drainMode == DRAIN_CHAIN) {
865 ALOGW("DRAIN_CHAIN not supported");
866 return C2_OMITTED;
867 }
868
James Zernb7aee6e2020-06-26 13:49:53 -0700869 const Libgav1StatusCode status = mCodecCtx->SignalEOS();
Vignesh Venkatasubramanian0f3e7422019-06-17 16:21:36 -0700870 if (status != kLibgav1StatusOk) {
871 ALOGE("Failed to flush av1 decoder. status: %d.", status);
872 return C2_CORRUPTED;
873 }
874
875 while (outputBuffer(pool, work)) {
876 }
877
878 if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
879 work->workletsProcessed == 0u) {
880 fillEmptyWork(work);
881 }
882
883 return C2_OK;
884}
885
886c2_status_t C2SoftGav1Dec::drain(uint32_t drainMode,
887 const std::shared_ptr<C2BlockPool> &pool) {
888 return drainInternal(drainMode, pool, nullptr);
889}
890
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700891class C2SoftGav1Factory : public C2ComponentFactory {
892 public:
893 C2SoftGav1Factory()
894 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
895 GetCodec2PlatformComponentStore()->getParamReflector())) {}
896
897 virtual c2_status_t createComponent(
898 c2_node_id_t id, std::shared_ptr<C2Component> *const component,
899 std::function<void(C2Component *)> deleter) override {
900 *component = std::shared_ptr<C2Component>(
901 new C2SoftGav1Dec(COMPONENT_NAME, id,
902 std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
903 deleter);
904 return C2_OK;
905 }
906
907 virtual c2_status_t createInterface(
908 c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
909 std::function<void(C2ComponentInterface *)> deleter) override {
910 *interface = std::shared_ptr<C2ComponentInterface>(
911 new SimpleInterface<C2SoftGav1Dec::IntfImpl>(
912 COMPONENT_NAME, id,
913 std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
914 deleter);
915 return C2_OK;
916 }
917
918 virtual ~C2SoftGav1Factory() override = default;
919
920 private:
921 std::shared_ptr<C2ReflectorHelper> mHelper;
922};
923
924} // namespace android
925
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -0800926__attribute__((cfi_canonical_jump_table))
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700927extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
928 ALOGV("in %s", __func__);
929 return new ::android::C2SoftGav1Factory();
930}
931
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -0800932__attribute__((cfi_canonical_jump_table))
Vignesh Venkatasubramanianb6d383d2019-06-10 15:11:58 -0700933extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
934 ALOGV("in %s", __func__);
935 delete factory;
936}