blob: f5620a41fb41c7a973cce9de2a15ad587d889cdd [file] [log] [blame]
Fyodor Kyslovadc71142022-09-15 16:47:03 +00001/*
2 * Copyright (C) 2022 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 "C2SoftAomEnc"
19#include <log/log.h>
20
21#include <media/stagefright/foundation/AUtils.h>
22#include <media/stagefright/foundation/MediaDefs.h>
23
24#include <C2Debug.h>
25#include <C2PlatformSupport.h>
26#include <SimpleC2Interface.h>
27
28#include "C2SoftAomEnc.h"
29
30namespace android {
31
32constexpr char COMPONENT_NAME[] = "c2.android.av1.encoder";
33
34#define DEFAULT_SPEED 10
35
36C2SoftAomEnc::IntfImpl::IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
37 : SimpleInterface<void>::BaseParams(helper, COMPONENT_NAME, C2Component::KIND_ENCODER,
38 C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
39 noPrivateBuffers(); // TODO: account for our buffers here
40 noInputReferences();
41 noOutputReferences();
42 noInputLatency();
43 noTimeStretch();
44 setDerivedInstance(this);
45
46 addParameter(DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
47 .withConstValue(new C2StreamUsageTuning::input(
48 0u, (uint64_t)C2MemoryUsage::CPU_READ))
49 .build());
50
51 addParameter(DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
52 .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
53 .withFields({
54 C2F(mSize, width).inRange(2, 2048, 2),
55 C2F(mSize, height).inRange(2, 2048, 2),
56 })
57 .withSetter(SizeSetter)
58 .build());
59
60 addParameter(DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
61 .withDefault(new C2StreamBitrateModeTuning::output(
62 0u, C2Config::BITRATE_VARIABLE))
63 .withFields({C2F(mBitrateMode, value)
64 .oneOf({C2Config::BITRATE_CONST,
65 C2Config::BITRATE_VARIABLE})})
66 .withSetter(Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
67 .build());
68
69 addParameter(DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
70 .withDefault(new C2StreamFrameRateInfo::output(0u, 30.))
71 // TODO: More restriction?
72 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
73 .withSetter(Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
74 .build());
75
76 addParameter(DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
77 .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
78 .withFields({C2F(mSyncFramePeriod, value).any()})
79 .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
80 .build());
81
82 addParameter(DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
83 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
84 .withFields({C2F(mBitrate, value).inRange(4096, 40000000)})
85 .withSetter(BitrateSetter)
86 .build());
87
88 addParameter(DefineParam(mIntraRefresh, C2_PARAMKEY_INTRA_REFRESH)
89 .withConstValue(new C2StreamIntraRefreshTuning::output(
90 0u, C2Config::INTRA_REFRESH_DISABLED, 0.))
91 .build());
92
93 addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
94 .withDefault(new C2StreamProfileLevelInfo::output(0u, PROFILE_AV1_0,
95 LEVEL_AV1_4_1))
96 .withFields({
97 C2F(mProfileLevel, profile).equalTo(PROFILE_AV1_0),
Fyodor Kyslova8092322022-10-09 02:47:33 +000098 C2F(mProfileLevel, level)
99 .oneOf({LEVEL_AV1_2, LEVEL_AV1_2_1, LEVEL_AV1_2_2,
100 LEVEL_AV1_2_3, LEVEL_AV1_3, LEVEL_AV1_3_1,
101 LEVEL_AV1_3_2, LEVEL_AV1_3_3, LEVEL_AV1_4,
102 LEVEL_AV1_4_1}),
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000103 })
104 .withSetter(ProfileLevelSetter)
105 .build());
106
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000107 addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
108 .withDefault(new C2StreamPixelFormatInfo::output(
109 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
110 .withFields({C2F(mPixelFormat, value).oneOf({
111 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
112 HAL_PIXEL_FORMAT_YCBCR_420_888,
113 HAL_PIXEL_FORMAT_YCBCR_P010
114 })
115 })
116 .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
117 .build());
118
119
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000120 addParameter(DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
121 .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
122 .withFields({C2F(mRequestSync, value).oneOf({C2_FALSE, C2_TRUE})})
123 .withSetter(Setter<decltype(*mRequestSync)>::NonStrictValueWithNoDeps)
124 .build());
125 addParameter(
126 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
127 .withDefault(new C2StreamColorAspectsInfo::input(
128 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
129 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
130 .withFields(
131 {C2F(mColorAspects, range)
132 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
133 C2F(mColorAspects, primaries)
134 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
135 C2Color::PRIMARIES_OTHER),
136 C2F(mColorAspects, transfer)
137 .inRange(C2Color::TRANSFER_UNSPECIFIED,
138 C2Color::TRANSFER_OTHER),
139 C2F(mColorAspects, matrix)
140 .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)})
141 .withSetter(ColorAspectsSetter)
142 .build());
143
144 addParameter(
145 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
146 .withDefault(new C2StreamColorAspectsInfo::output(
147 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
148 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
149 .withFields(
150 {C2F(mCodedColorAspects, range)
151 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
152 C2F(mCodedColorAspects, primaries)
153 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
154 C2Color::PRIMARIES_OTHER),
155 C2F(mCodedColorAspects, transfer)
156 .inRange(C2Color::TRANSFER_UNSPECIFIED,
157 C2Color::TRANSFER_OTHER),
158 C2F(mCodedColorAspects, matrix)
159 .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)})
160 .withSetter(CodedColorAspectsSetter, mColorAspects)
161 .build());
162}
163
164C2R C2SoftAomEnc::IntfImpl::BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output>& me) {
165 (void)mayBlock;
166 C2R res = C2R::Ok();
167 if (me.v.value < 4096) {
168 me.set().value = 4096;
169 }
170 return res;
171}
172
173C2R C2SoftAomEnc::IntfImpl::SizeSetter(bool mayBlock,
174 const C2P<C2StreamPictureSizeInfo::input>& oldMe,
175 C2P<C2StreamPictureSizeInfo::input>& me) {
176 (void)mayBlock;
177 C2R res = C2R::Ok();
178 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
179 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
180 me.set().width = oldMe.v.width;
181 }
182 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
183 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
184 me.set().height = oldMe.v.height;
185 }
186 return res;
187}
188
189C2R C2SoftAomEnc::IntfImpl::ProfileLevelSetter(bool mayBlock,
190 C2P<C2StreamProfileLevelInfo::output>& me) {
191 (void)mayBlock;
192 if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
193 me.set().profile = PROFILE_AV1_0;
194 }
195 if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
196 me.set().level = LEVEL_AV1_4_1;
197 }
198 return C2R::Ok();
199}
200
201uint32_t C2SoftAomEnc::IntfImpl::getSyncFramePeriod() const {
202 if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
203 return 0;
204 }
205 double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
206 return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
207}
208
209C2R C2SoftAomEnc::IntfImpl::ColorAspectsSetter(bool mayBlock,
210 C2P<C2StreamColorAspectsInfo::input>& me) {
211 (void)mayBlock;
212 if (me.v.range > C2Color::RANGE_OTHER) {
213 me.set().range = C2Color::RANGE_OTHER;
214 }
215 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
216 me.set().primaries = C2Color::PRIMARIES_OTHER;
217 }
218 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
219 me.set().transfer = C2Color::TRANSFER_OTHER;
220 }
221 if (me.v.matrix > C2Color::MATRIX_OTHER) {
222 me.set().matrix = C2Color::MATRIX_OTHER;
223 }
224 return C2R::Ok();
225}
226C2R C2SoftAomEnc::IntfImpl::CodedColorAspectsSetter(
227 bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
228 const C2P<C2StreamColorAspectsInfo::input>& coded) {
229 (void)mayBlock;
230 me.set().range = coded.v.range;
231 me.set().primaries = coded.v.primaries;
232 me.set().transfer = coded.v.transfer;
233 me.set().matrix = coded.v.matrix;
234 return C2R::Ok();
235}
236
237C2SoftAomEnc::C2SoftAomEnc(const char* name, c2_node_id_t id,
238 const std::shared_ptr<IntfImpl>& intfImpl)
239 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
240 mIntf(intfImpl),
241 mCodecContext(nullptr),
242 mCodecConfiguration(nullptr),
243 mCodecInterface(nullptr),
244 mStrideAlign(2),
245 mBitrateControlMode(AOM_VBR),
246 mMinQuantizer(0),
247 mMaxQuantizer(0),
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000248 mLastTimestamp(INT64_MAX),
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000249 mSignalledOutputEos(false),
250 mSignalledError(false),
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000251 mHeadersReceived(false),
252 mIs10Bit(false) {
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000253 ALOGV("Constructor");
254}
255
256C2SoftAomEnc::~C2SoftAomEnc() {
257 ALOGV("Destructor");
258 onRelease();
259}
260
261c2_status_t C2SoftAomEnc::onInit() {
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000262 return C2_OK;
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000263}
264
265c2_status_t C2SoftAomEnc::onStop() {
266 onRelease();
267 return C2_OK;
268}
269
270void C2SoftAomEnc::onReset() {
271 (void)onStop();
272}
273
274void C2SoftAomEnc::onRelease() {
275 if (mCodecContext) {
276 aom_codec_destroy(mCodecContext);
277 delete mCodecContext;
278 mCodecContext = nullptr;
279 }
280
281 if (mCodecConfiguration) {
282 delete mCodecConfiguration;
283 mCodecConfiguration = nullptr;
284 }
285
286 // this one is not allocated by us
287 mCodecInterface = nullptr;
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000288 mHeadersReceived = false;
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000289}
290
291c2_status_t C2SoftAomEnc::onFlush_sm() {
292 return onStop();
293}
294
295aom_codec_err_t C2SoftAomEnc::setupCodecParameters() {
296 aom_codec_err_t codec_return = AOM_CODEC_OK;
297
298 codec_return = aom_codec_control(mCodecContext, AOME_SET_CPUUSED, DEFAULT_SPEED);
299 if (codec_return != AOM_CODEC_OK) goto BailOut;
300
301 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ROW_MT, 1);
302 if (codec_return != AOM_CODEC_OK) goto BailOut;
303
304 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_CDEF, 1);
305 if (codec_return != AOM_CODEC_OK) goto BailOut;
306
307 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_TPL_MODEL, 0);
308 if (codec_return != AOM_CODEC_OK) goto BailOut;
309
310 codec_return = aom_codec_control(mCodecContext, AV1E_SET_DELTAQ_MODE, 0);
311 if (codec_return != AOM_CODEC_OK) goto BailOut;
312
313 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_ORDER_HINT, 0);
314 if (codec_return != AOM_CODEC_OK) goto BailOut;
315
316 codec_return = aom_codec_control(mCodecContext, AV1E_SET_AQ_MODE, 3);
317 if (codec_return != AOM_CODEC_OK) goto BailOut;
318
319 codec_return = aom_codec_control(mCodecContext, AV1E_SET_COEFF_COST_UPD_FREQ, 3);
320 if (codec_return != AOM_CODEC_OK) goto BailOut;
321
322 codec_return = aom_codec_control(mCodecContext, AV1E_SET_MODE_COST_UPD_FREQ, 3);
323 if (codec_return != AOM_CODEC_OK) goto BailOut;
324
325 codec_return = aom_codec_control(mCodecContext, AV1E_SET_MV_COST_UPD_FREQ, 3);
326 if (codec_return != AOM_CODEC_OK) goto BailOut;
327
328 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_PALETTE, 0);
329 if (codec_return != AOM_CODEC_OK) goto BailOut;
330
331 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_OBMC, 0);
332 if (codec_return != AOM_CODEC_OK) goto BailOut;
333
334 codec_return = aom_codec_control(mCodecContext, AV1E_SET_NOISE_SENSITIVITY, 0);
335 if (codec_return != AOM_CODEC_OK) goto BailOut;
336
337 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_WARPED_MOTION, 0);
338 if (codec_return != AOM_CODEC_OK) goto BailOut;
339
340 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_GLOBAL_MOTION, 0);
341 if (codec_return != AOM_CODEC_OK) goto BailOut;
342
343 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_REF_FRAME_MVS, 0);
344 if (codec_return != AOM_CODEC_OK) goto BailOut;
345
346 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_CFL_INTRA, 0);
347 if (codec_return != AOM_CODEC_OK) goto BailOut;
348
349 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_SMOOTH_INTRA, 0);
350 if (codec_return != AOM_CODEC_OK) goto BailOut;
351 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_ANGLE_DELTA, 0);
352 if (codec_return != AOM_CODEC_OK) goto BailOut;
353 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_FILTER_INTRA, 0);
354 if (codec_return != AOM_CODEC_OK) goto BailOut;
355
356 codec_return = aom_codec_control(mCodecContext, AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1);
357 if (codec_return != AOM_CODEC_OK) goto BailOut;
358 codec_return = aom_codec_control(mCodecContext, AV1E_SET_DISABLE_TRELLIS_QUANT, 1);
359 if (codec_return != AOM_CODEC_OK) goto BailOut;
360
361 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_DIST_WTD_COMP, 0);
362 if (codec_return != AOM_CODEC_OK) goto BailOut;
363 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_DIFF_WTD_COMP, 0);
364 if (codec_return != AOM_CODEC_OK) goto BailOut;
365 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_DUAL_FILTER, 0);
366 if (codec_return != AOM_CODEC_OK) goto BailOut;
367 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_INTERINTRA_COMP, 0);
368 if (codec_return != AOM_CODEC_OK) goto BailOut;
369 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0);
370 if (codec_return != AOM_CODEC_OK) goto BailOut;
371 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0);
372 if (codec_return != AOM_CODEC_OK) goto BailOut;
373 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_INTRABC, 0);
374 if (codec_return != AOM_CODEC_OK) goto BailOut;
375 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_MASKED_COMP, 0);
376 if (codec_return != AOM_CODEC_OK) goto BailOut;
377 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_PAETH_INTRA, 0);
378 if (codec_return != AOM_CODEC_OK) goto BailOut;
379 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_QM, 0);
380 if (codec_return != AOM_CODEC_OK) goto BailOut;
381 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_RECT_PARTITIONS, 0);
382 if (codec_return != AOM_CODEC_OK) goto BailOut;
383 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_RESTORATION, 0);
384 if (codec_return != AOM_CODEC_OK) goto BailOut;
385 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0);
386 if (codec_return != AOM_CODEC_OK) goto BailOut;
387 codec_return = aom_codec_control(mCodecContext, AV1E_SET_ENABLE_TX64, 0);
388 if (codec_return != AOM_CODEC_OK) goto BailOut;
389
390 codec_return = aom_codec_control(mCodecContext, AV1E_SET_MAX_REFERENCE_FRAMES, 3);
391 if (codec_return != AOM_CODEC_OK) goto BailOut;
392
393BailOut:
394 return codec_return;
395}
396
397status_t C2SoftAomEnc::initEncoder() {
398 aom_codec_err_t codec_return;
399 status_t result = UNKNOWN_ERROR;
400 {
401 IntfImpl::Lock lock = mIntf->lock();
402 // Fetch config
403 mSize = mIntf->getSize_l();
404 mBitrate = mIntf->getBitrate_l();
405 mBitrateMode = mIntf->getBitrateMode_l();
406 mFrameRate = mIntf->getFrameRate_l();
407 mIntraRefresh = mIntf->getIntraRefresh_l();
408 mRequestSync = mIntf->getRequestSync_l();
409 }
410
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000411
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000412 switch (mBitrateMode->value) {
413 case C2Config::BITRATE_CONST:
414 mBitrateControlMode = AOM_CBR;
415 break;
416 case C2Config::BITRATE_VARIABLE:
417 [[fallthrough]];
418 default:
419 mBitrateControlMode = AOM_VBR;
420 break;
421 }
422
423 mCodecInterface = aom_codec_av1_cx();
424 if (!mCodecInterface) goto CleanUp;
425
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000426 ALOGD("AOM: initEncoder. BRMode: %u. KF: %u. QP: %u - %u, 10Bit: %d",
427 (uint32_t)mBitrateControlMode,
428 mIntf->getSyncFramePeriod(), mMinQuantizer, mMaxQuantizer, mIs10Bit);
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000429
430 mCodecConfiguration = new aom_codec_enc_cfg_t;
431 if (!mCodecConfiguration) goto CleanUp;
432
433 codec_return = aom_codec_enc_config_default(mCodecInterface, mCodecConfiguration,
434 AOM_USAGE_REALTIME); // RT mode
435 if (codec_return != AOM_CODEC_OK) {
436 ALOGE("Error populating default configuration for aom encoder.");
437 goto CleanUp;
438 }
439
440 mCodecConfiguration->g_w = mSize->width;
441 mCodecConfiguration->g_h = mSize->height;
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000442 mCodecConfiguration->g_bit_depth = mIs10Bit ? AOM_BITS_10 : AOM_BITS_8;
443 mCodecConfiguration->g_input_bit_depth = mIs10Bit ? 10 : 8;
444
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000445
446 mCodecConfiguration->g_threads = 0;
447 mCodecConfiguration->g_error_resilient = 0;
448
449 // timebase unit is microsecond
450 // g_timebase is in seconds (i.e. 1/1000000 seconds)
451 mCodecConfiguration->g_timebase.num = 1;
452 mCodecConfiguration->g_timebase.den = 1000000;
453 // rc_target_bitrate is in kbps, mBitrate in bps
454 mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
455 mCodecConfiguration->rc_end_usage = AOM_CBR;
456 // Disable frame drop - not allowed in MediaCodec now.
457 mCodecConfiguration->rc_dropframe_thresh = 0;
458 // Disable lagged encoding.
459 mCodecConfiguration->g_lag_in_frames = 0;
460
461 // Disable spatial resizing.
462 mCodecConfiguration->rc_resize_mode = 0;
463 // Single-pass mode.
464 mCodecConfiguration->g_pass = AOM_RC_ONE_PASS;
465
466 // Maximum key frame interval - for CBR boost to 3000
467 mCodecConfiguration->kf_max_dist = 3000;
468 // Encoder determines optimal key frame placement automatically.
469 mCodecConfiguration->kf_mode = AOM_KF_AUTO;
470 // Initial value of the buffer level in ms.
471 mCodecConfiguration->rc_buf_initial_sz = 500;
472 // Amount of data that the encoder should try to maintain in ms.
473 mCodecConfiguration->rc_buf_optimal_sz = 600;
474 // The amount of data that may be buffered by the decoding
475 // application in ms.
476 mCodecConfiguration->rc_buf_sz = 1000;
477
478 if (mBitrateControlMode == AOM_CBR) {
479 // Maximum amount of bits that can be subtracted from the target
480 // bitrate - expressed as percentage of the target bitrate.
481 mCodecConfiguration->rc_undershoot_pct = 100;
482 // Maximum amount of bits that can be added to the target
483 // bitrate - expressed as percentage of the target bitrate.
484 mCodecConfiguration->rc_overshoot_pct = 10;
485 } else {
486 // Maximum amount of bits that can be subtracted from the target
487 // bitrate - expressed as percentage of the target bitrate.
488 mCodecConfiguration->rc_undershoot_pct = 100;
489 // Maximum amount of bits that can be added to the target
490 // bitrate - expressed as percentage of the target bitrate.
491 mCodecConfiguration->rc_overshoot_pct = 25;
492 }
493
494 if (mIntf->getSyncFramePeriod() >= 0) {
495 mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
496 mCodecConfiguration->kf_min_dist = mIntf->getSyncFramePeriod();
497 mCodecConfiguration->kf_mode = AOM_KF_AUTO;
498 }
499 if (mMinQuantizer > 0) {
500 mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
501 }
502 if (mMaxQuantizer > 0) {
503 mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
504 }
505
506 mCodecContext = new aom_codec_ctx_t;
507 if (!mCodecContext) goto CleanUp;
508 codec_return = aom_codec_enc_init(mCodecContext, mCodecInterface, mCodecConfiguration,
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000509 mIs10Bit ? AOM_CODEC_USE_HIGHBITDEPTH : 0);
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000510 if (codec_return != AOM_CODEC_OK) {
511 ALOGE("Error initializing aom encoder");
512 goto CleanUp;
513 }
514
515 codec_return = setupCodecParameters();
516 if (codec_return != AOM_CODEC_OK) {
517 ALOGE("Error setting up codec parameters");
518 goto CleanUp;
519 }
520
521 mHeadersReceived = false;
522
523 {
524 uint32_t width = mSize->width;
525 uint32_t height = mSize->height;
526 if (((uint64_t)width * height) > ((uint64_t)INT32_MAX / 3)) {
527 ALOGE("b/25812794, Buffer size is too big, width=%u, height=%u.", width, height);
528 } else {
529 uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
530 uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000531 mConversionBuffer = MemoryBlock::Allocate(stride * vstride * 3 / (mIs10Bit? 1 : 2));
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000532 if (!mConversionBuffer.size()) {
533 ALOGE("Allocating conversion buffer failed.");
534 } else {
535 mNumInputFrames = -1;
536 return OK;
537 }
538 }
539 }
540
541CleanUp:
542 onRelease();
543 return result;
544}
545
546void C2SoftAomEnc::process(const std::unique_ptr<C2Work>& work,
547 const std::shared_ptr<C2BlockPool>& pool) {
548 // Initialize output work
549 work->result = C2_OK;
550 work->workletsProcessed = 1u;
551 work->worklets.front()->output.flags = work->input.flags;
552
553 if (mSignalledError || mSignalledOutputEos) {
554 work->result = C2_BAD_VALUE;
555 return;
556 }
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000557
558 std::shared_ptr<const C2GraphicView> rView;
559 std::shared_ptr<C2Buffer> inputBuffer;
560 if (!work->input.buffers.empty()) {
561 inputBuffer = work->input.buffers[0];
562 rView = std::make_shared<const C2GraphicView>(
563 inputBuffer->data().graphicBlocks().front().map().get());
564 if (rView->error() != C2_OK) {
565 ALOGE("graphic view map err = %d", rView->error());
566 work->result = C2_CORRUPTED;
567 return;
568 }
569 } else {
570 ALOGV("Empty input Buffer");
571 uint32_t flags = 0;
572 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
573 flags |= C2FrameData::FLAG_END_OF_STREAM;
574 }
575 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
576 work->worklets.front()->output.buffers.clear();
577 work->worklets.front()->output.ordinal = work->input.ordinal;
578 work->workletsProcessed = 1u;
579 return;
580 }
581
582 bool end_of_stream = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
583 aom_image_t raw_frame;
584 const C2PlanarLayout& layout = rView->layout();
585 if (!mHeadersReceived) {
586 mIs10Bit = (layout.planes[layout.PLANE_Y].bitDepth == 10);
587
588 // Re-Initialize encoder
589 if (mCodecContext){
590 onRelease();
591 }
592 }
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000593 if (!mCodecContext && OK != initEncoder()) {
594 ALOGE("Failed to initialize encoder");
595 mSignalledError = true;
596 work->result = C2_CORRUPTED;
597 return;
598 }
599
600 if (!mHeadersReceived) {
601 Av1Config av1_config;
602 constexpr uint32_t header_length = 2048;
603 uint8_t header[header_length];
604 size_t header_bytes;
605 aom_fixed_buf_t* obu_sequence_header = aom_codec_get_global_headers(mCodecContext);
606 int ret = 1;
607 if (obu_sequence_header) {
608 if (get_av1config_from_obu(reinterpret_cast<const uint8_t*>(obu_sequence_header->buf),
609 obu_sequence_header->sz, false, &av1_config) == 0) {
610 ret = write_av1config(&av1_config, header_length, &header_bytes, header);
611
612 } else {
613 ALOGE("Can not get config");
614 }
615 free(obu_sequence_header->buf);
616 free(obu_sequence_header);
617 }
618
619 if (ret) {
620 ALOGE("Can not write config");
621 mSignalledError = true;
622 work->result = C2_NO_MEMORY;
623 work->workletsProcessed = 1u;
624 return;
625 }
626
627 mHeadersReceived = true;
628 std::unique_ptr<C2StreamInitDataInfo::output> csd =
629 C2StreamInitDataInfo::output::AllocUnique(header_bytes, 0u);
630 if (!csd) {
631 ALOGE("CSD allocation failed");
632 mSignalledError = true;
633 work->result = C2_NO_MEMORY;
634 work->workletsProcessed = 1u;
635 return;
636 }
637 memcpy(csd->m.value, header, header_bytes);
638 work->worklets.front()->output.configUpdate.push_back(std::move(csd));
639 ALOGV("CSD Produced of size %zu bytes", header_bytes);
640 }
641
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000642 const C2ConstGraphicBlock inBuffer = inputBuffer->data().graphicBlocks().front();
643 if (inBuffer.width() < mSize->width || inBuffer.height() < mSize->height) {
644 ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)", inBuffer.width(), mSize->width,
645 inBuffer.height(), mSize->height);
646 mSignalledError = true;
647 work->result = C2_BAD_VALUE;
648 return;
649 }
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000650
651
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000652 uint32_t width = mSize->width;
653 uint32_t height = mSize->height;
654 if (width > 0x8000 || height > 0x8000) {
655 ALOGE("Image too big: %u x %u", width, height);
656 work->result = C2_BAD_VALUE;
657 return;
658 }
659 uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
660 uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
661 switch (layout.type) {
662 case C2PlanarLayout::TYPE_RGB:
663 case C2PlanarLayout::TYPE_RGBA: {
664 std::shared_ptr<C2StreamColorAspectsInfo::output> colorAspects;
665 {
666 IntfImpl::Lock lock = mIntf->lock();
667 colorAspects = mIntf->getCodedColorAspects_l();
668 }
669 ConvertRGBToPlanarYUV(mConversionBuffer.data(), stride, vstride,
670 mConversionBuffer.size(), *rView.get(), colorAspects->matrix,
671 colorAspects->range);
672 aom_img_wrap(&raw_frame, AOM_IMG_FMT_I420, width, height, mStrideAlign,
673 mConversionBuffer.data());
674 break;
675 }
676 case C2PlanarLayout::TYPE_YUV: {
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000677 const bool isYUV420_10bit = IsYUV420_10bit(*rView);
678 if (!IsYUV420(*rView) && !isYUV420_10bit) {
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000679 ALOGE("input is not YUV420");
680 work->result = C2_BAD_VALUE;
681 return;
682 }
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000683 if (!isYUV420_10bit) {
684 if (IsI420(*rView)) {
685 // I420 compatible - though with custom offset and stride
686 aom_img_wrap(&raw_frame, AOM_IMG_FMT_I420, width, height, mStrideAlign,
687 (uint8_t*)rView->data()[0]);
688 raw_frame.planes[1] = (uint8_t*)rView->data()[1];
689 raw_frame.planes[2] = (uint8_t*)rView->data()[2];
690 raw_frame.stride[0] = layout.planes[layout.PLANE_Y].rowInc;
691 raw_frame.stride[1] = layout.planes[layout.PLANE_U].rowInc;
692 raw_frame.stride[2] = layout.planes[layout.PLANE_V].rowInc;
693 } else {
694 // TODO(kyslov): Add image wrap for NV12
695 // copy to I420
696 MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, stride, vstride);
697 if (mConversionBuffer.size() >= stride * vstride * 3 / 2) {
698 status_t err = ImageCopy(mConversionBuffer.data(), &img, *rView);
699 if (err != OK) {
700 ALOGE("Buffer conversion failed: %d", err);
701 work->result = C2_BAD_VALUE;
702 return;
703 }
704 aom_img_wrap(&raw_frame, AOM_IMG_FMT_I420, stride, vstride, mStrideAlign,
705 mConversionBuffer.data());
706 aom_img_set_rect(&raw_frame, 0, 0, width, height, 0);
707 } else {
708 ALOGE("Conversion buffer is too small: %u x %u for %zu", stride, vstride,
709 mConversionBuffer.size());
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000710 work->result = C2_BAD_VALUE;
711 return;
712 }
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000713 }
714 } else { // 10 bits
715 if (IsP010(*rView)) {
716 if (mConversionBuffer.size() >= stride * vstride * 3) {
717 uint16_t *dstY, *dstU, *dstV;
718 dstY = (uint16_t*)mConversionBuffer.data();
719 dstU = ((uint16_t*)mConversionBuffer.data()) + stride * vstride;
720 dstV = ((uint16_t*)mConversionBuffer.data()) + (stride * vstride) / 4;
721 convertP010ToYUV420Planar16(dstY, dstU, dstV, (uint16_t*)(rView->data()[0]),
722 (uint16_t*)(rView->data()[1]), stride, stride,
723 stride, stride / 2, stride / 2, stride,
724 vstride);
725 aom_img_wrap(&raw_frame, AOM_IMG_FMT_I42016, stride, vstride, mStrideAlign,
726 mConversionBuffer.data());
727 aom_img_set_rect(&raw_frame, 0, 0, width, height, 0);
728 } else {
729 ALOGE("Conversion buffer is too small: %u x %u for %zu", stride, vstride,
730 mConversionBuffer.size());
731 work->result = C2_BAD_VALUE;
732 return;
733 }
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000734 } else {
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000735 ALOGE("Image format conversion is not supported.");
Fyodor Kyslovadc71142022-09-15 16:47:03 +0000736 work->result = C2_BAD_VALUE;
737 return;
738 }
739 }
740 break;
741 }
742 default:
743 ALOGE("Unrecognized plane type: %d", layout.type);
744 work->result = C2_BAD_VALUE;
745 return;
746 }
747
748 aom_enc_frame_flags_t flags = 0;
749 // handle dynamic config parameters
750 {
751 IntfImpl::Lock lock = mIntf->lock();
752 std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh =
753 mIntf->getIntraRefresh_l();
754 std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
755 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync =
756 mIntf->getRequestSync_l();
757 lock.unlock();
758
759 if (intraRefresh != mIntraRefresh) {
760 mIntraRefresh = intraRefresh;
761 ALOGV("Got mIntraRefresh request");
762 }
763
764 if (requestSync != mRequestSync) {
765 // we can handle IDR immediately
766 if (requestSync->value) {
767 // unset request
768 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
769 std::vector<std::unique_ptr<C2SettingResult>> failures;
770 mIntf->config({&clearSync}, C2_MAY_BLOCK, &failures);
771 ALOGV("Got sync request");
772 flags |= AOM_EFLAG_FORCE_KF;
773 }
774 mRequestSync = requestSync;
775 }
776
777 if (bitrate != mBitrate) {
778 mBitrate = bitrate;
779 mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
780 aom_codec_err_t res = aom_codec_enc_config_set(mCodecContext, mCodecConfiguration);
781 if (res != AOM_CODEC_OK) {
782 ALOGE("aom encoder failed to update bitrate: %s", aom_codec_err_to_string(res));
783 mSignalledError = true;
784 work->result = C2_CORRUPTED;
785 return;
786 }
787 }
788 }
789
790 uint64_t input_timestamp = work->input.ordinal.timestamp.peekull();
791 uint32_t frame_duration;
792 if (input_timestamp > mLastTimestamp) {
793 frame_duration = (uint32_t)(input_timestamp - mLastTimestamp);
794 } else {
795 // Use default of 30 fps in case of 0 frame rate.
796 float frame_rate = mFrameRate->value;
797 if (frame_rate < 0.001) {
798 frame_rate = 30.0;
799 }
800 frame_duration = (uint32_t)(1000000 / frame_rate + 0.5);
801 }
802 mLastTimestamp = input_timestamp;
803
804 aom_codec_err_t codec_return =
805 aom_codec_encode(mCodecContext, &raw_frame, input_timestamp, frame_duration, flags);
806 if (codec_return != AOM_CODEC_OK) {
807 ALOGE("aom encoder failed to encode frame");
808 mSignalledError = true;
809 work->result = C2_CORRUPTED;
810 return;
811 }
812
813 bool populated = false;
814 aom_codec_iter_t encoded_packet_iterator = nullptr;
815 const aom_codec_cx_pkt_t* encoded_packet;
816 while ((encoded_packet = aom_codec_get_cx_data(mCodecContext, &encoded_packet_iterator))) {
817 if (encoded_packet->kind == AOM_CODEC_CX_FRAME_PKT) {
818 std::shared_ptr<C2LinearBlock> block;
819 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
820 c2_status_t err = pool->fetchLinearBlock(encoded_packet->data.frame.sz, usage, &block);
821 if (err != C2_OK) {
822 ALOGE("fetchLinearBlock for Output failed with status %d", err);
823 work->result = C2_NO_MEMORY;
824 return;
825 }
826 C2WriteView wView = block->map().get();
827 if (wView.error()) {
828 ALOGE("write view map failed %d", wView.error());
829 work->result = C2_CORRUPTED;
830 return;
831 }
832
833 memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
834 ++mNumInputFrames;
835
836 ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
837 uint32_t flags = 0;
838 if (end_of_stream) {
839 flags |= C2FrameData::FLAG_END_OF_STREAM;
840 }
841
842 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
843 work->worklets.front()->output.buffers.clear();
844 std::shared_ptr<C2Buffer> buffer =
845 createLinearBuffer(block, 0, encoded_packet->data.frame.sz);
846 if (encoded_packet->data.frame.flags & AOM_FRAME_IS_KEY) {
847 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
848 0u /* stream id */, C2Config::SYNC_FRAME));
849 }
850 work->worklets.front()->output.buffers.push_back(buffer);
851 work->worklets.front()->output.ordinal = work->input.ordinal;
852 work->worklets.front()->output.ordinal.timestamp = encoded_packet->data.frame.pts;
853 work->workletsProcessed = 1u;
854 populated = true;
855 if (end_of_stream) {
856 mSignalledOutputEos = true;
857 ALOGV("signalled End Of Stream");
858 }
859 }
860 }
861 if (!populated) {
862 work->workletsProcessed = 0u;
863 }
864}
865
866c2_status_t C2SoftAomEnc::drain(uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool) {
867 (void)pool;
868 if (drainMode == NO_DRAIN) {
869 ALOGW("drain with NO_DRAIN: no-op");
870 return C2_OK;
871 }
872 if (drainMode == DRAIN_CHAIN) {
873 ALOGW("DRAIN_CHAIN not supported");
874 return C2_OMITTED;
875 }
876
877 return C2_OK;
878}
879
880class C2SoftAomEncFactory : public C2ComponentFactory {
881 public:
882 C2SoftAomEncFactory()
883 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
884 GetCodec2PlatformComponentStore()->getParamReflector())) {}
885
886 virtual c2_status_t createComponent(c2_node_id_t id,
887 std::shared_ptr<C2Component>* const component,
888 std::function<void(C2Component*)> deleter) override {
889 *component = std::shared_ptr<C2Component>(
890 new C2SoftAomEnc(COMPONENT_NAME, id,
891 std::make_shared<C2SoftAomEnc::IntfImpl>(mHelper)),
892 deleter);
893 return C2_OK;
894 }
895
896 virtual c2_status_t createInterface(
897 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
898 std::function<void(C2ComponentInterface*)> deleter) override {
899 *interface = std::shared_ptr<C2ComponentInterface>(
900 new SimpleInterface<C2SoftAomEnc::IntfImpl>(
901 COMPONENT_NAME, id, std::make_shared<C2SoftAomEnc::IntfImpl>(mHelper)),
902 deleter);
903 return C2_OK;
904 }
905
906 virtual ~C2SoftAomEncFactory() override = default;
907
908 private:
909 std::shared_ptr<C2ReflectorHelper> mHelper;
910};
911
912} // namespace android
913
914__attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
915 ALOGV("in %s", __func__);
916 return new ::android::C2SoftAomEncFactory();
917}
918
919__attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory(
920 ::C2ComponentFactory* factory) {
921 ALOGV("in %s", __func__);
922 delete factory;
923}