blob: 60d5875264e01a66f831ae7778e9c8579753a6d1 [file] [log] [blame]
Roma Kauldfe650a2018-08-02 17:48:51 +05301/*
Ray Essick0d11a7e2019-03-02 20:10:30 -08002 * Copyright (C) 2019 The Android Open Source Project
Roma Kauldfe650a2018-08-02 17:48:51 +05303 *
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 "C2SoftHevcEnc"
19#include <log/log.h>
20
21#include <media/hardware/VideoAPI.h>
22#include <media/stagefright/MediaDefs.h>
23#include <media/stagefright/MediaErrors.h>
24#include <media/stagefright/MetaData.h>
25#include <media/stagefright/foundation/AUtils.h>
26
27#include <C2Debug.h>
Manisha Jajoo110682e2019-11-05 11:12:58 -080028#include <Codec2Mapper.h>
Roma Kauldfe650a2018-08-02 17:48:51 +053029#include <C2PlatformSupport.h>
30#include <Codec2BufferUtils.h>
31#include <SimpleC2Interface.h>
32#include <util/C2InterfaceHelper.h>
33
34#include "ihevc_typedefs.h"
35#include "itt_video_api.h"
36#include "ihevce_api.h"
37#include "ihevce_plugin.h"
38#include "C2SoftHevcEnc.h"
39
40namespace android {
41
Manisha Jajoo9acd73d2019-03-12 14:08:05 +053042namespace {
43
44constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
45
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -070046void ParseGop(
47 const C2StreamGopTuning::output &gop,
48 uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
49 uint32_t syncInt = 1;
50 uint32_t iInt = 1;
51 for (size_t i = 0; i < gop.flexCount(); ++i) {
52 const C2GopLayerStruct &layer = gop.m.values[i];
53 if (layer.count == UINT32_MAX) {
54 syncInt = 0;
55 } else if (syncInt <= UINT32_MAX / (layer.count + 1)) {
56 syncInt *= (layer.count + 1);
57 }
58 if ((layer.type_ & I_FRAME) == 0) {
59 if (layer.count == UINT32_MAX) {
60 iInt = 0;
61 } else if (iInt <= UINT32_MAX / (layer.count + 1)) {
62 iInt *= (layer.count + 1);
63 }
64 }
65 if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) {
66 *maxBframes = layer.count;
67 }
68 }
69 if (syncInterval) {
70 *syncInterval = syncInt;
71 }
72 if (iInterval) {
73 *iInterval = iInt;
74 }
75}
Manisha Jajoo9acd73d2019-03-12 14:08:05 +053076} // namepsace
77
78class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
Ray Essick0d11a7e2019-03-02 20:10:30 -080079 public:
Manisha Jajoo9acd73d2019-03-12 14:08:05 +053080 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
81 : SimpleInterface<void>::BaseParams(
82 helper,
83 COMPONENT_NAME,
84 C2Component::KIND_ENCODER,
85 C2Component::DOMAIN_VIDEO,
86 MEDIA_MIMETYPE_VIDEO_HEVC) {
87 noPrivateBuffers(); // TODO: account for our buffers here
88 noInputReferences();
89 noOutputReferences();
Manisha Jajoo9acd73d2019-03-12 14:08:05 +053090 noTimeStretch();
Roma Kauldfe650a2018-08-02 17:48:51 +053091 setDerivedInstance(this);
92
93 addParameter(
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -070094 DefineParam(mGop, C2_PARAMKEY_GOP)
95 .withDefault(C2StreamGopTuning::output::AllocShared(
96 0 /* flexCount */, 0u /* stream */))
97 .withFields({C2F(mGop, m.values[0].type_).any(),
98 C2F(mGop, m.values[0].count).any()})
99 .withSetter(GopSetter)
100 .build());
101
102 addParameter(
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530103 DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
104 .withDefault(new C2PortActualDelayTuning::input(
105 DEFAULT_B_FRAMES + DEFAULT_RC_LOOKAHEAD))
106 .withFields({C2F(mActualInputDelay, value).inRange(
107 0, MAX_B_FRAMES + MAX_RC_LOOKAHEAD)})
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700108 .calculatedAs(InputDelaySetter, mGop)
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530109 .build());
110
111 addParameter(
Manisha Jajoo9acd73d2019-03-12 14:08:05 +0530112 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
113 .withConstValue(new C2ComponentAttributesSetting(
114 C2Component::ATTRIB_IS_TEMPORAL))
Roma Kauldfe650a2018-08-02 17:48:51 +0530115 .build());
116
117 addParameter(
Manisha Jajoo9acd73d2019-03-12 14:08:05 +0530118 DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
119 .withConstValue(new C2StreamUsageTuning::input(
120 0u, (uint64_t)C2MemoryUsage::CPU_READ))
Roma Kauldfe650a2018-08-02 17:48:51 +0530121 .build());
122
Ray Essick0d11a7e2019-03-02 20:10:30 -0800123 // matches size limits in codec library
Roma Kauldfe650a2018-08-02 17:48:51 +0530124 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800125 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
Harish Mahendrakar11d1d502020-04-07 01:55:06 +0530126 .withDefault(new C2StreamPictureSizeInfo::input(0u, 64, 64))
Roma Kauldfe650a2018-08-02 17:48:51 +0530127 .withFields({
Harish Mahendrakarded2fd32019-05-15 15:36:25 -0700128 C2F(mSize, width).inRange(2, 1920, 2),
129 C2F(mSize, height).inRange(2, 1088, 2),
Roma Kauldfe650a2018-08-02 17:48:51 +0530130 })
131 .withSetter(SizeSetter)
132 .build());
133
134 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800135 DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
Harish Mahendrakar11d1d502020-04-07 01:55:06 +0530136 .withDefault(new C2StreamFrameRateInfo::output(0u, 1.))
Roma Kauldfe650a2018-08-02 17:48:51 +0530137 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
138 .withSetter(
139 Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
140 .build());
141
Ray Essick0d11a7e2019-03-02 20:10:30 -0800142 // matches limits in codec library
Roma Kauldfe650a2018-08-02 17:48:51 +0530143 addParameter(
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800144 DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
145 .withDefault(new C2StreamBitrateModeTuning::output(
146 0u, C2Config::BITRATE_VARIABLE))
147 .withFields({
148 C2F(mBitrateMode, value).oneOf({
149 C2Config::BITRATE_CONST,
150 C2Config::BITRATE_VARIABLE,
151 C2Config::BITRATE_IGNORE})
152 })
153 .withSetter(
154 Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
155 .build());
156
157 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800158 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
159 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
Roma Kauldfe650a2018-08-02 17:48:51 +0530160 .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
161 .withSetter(BitrateSetter)
162 .build());
163
Ray Essick0d11a7e2019-03-02 20:10:30 -0800164 // matches levels allowed within codec library
Roma Kauldfe650a2018-08-02 17:48:51 +0530165 addParameter(
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800166 DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
167 .withDefault(new C2StreamComplexityTuning::output(0u, 0))
168 .withFields({C2F(mComplexity, value).inRange(0, 10)})
169 .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
170 .build());
171
172 addParameter(
173 DefineParam(mQuality, C2_PARAMKEY_QUALITY)
174 .withDefault(new C2StreamQualityTuning::output(0u, 80))
175 .withFields({C2F(mQuality, value).inRange(0, 100)})
176 .withSetter(Setter<decltype(*mQuality)>::NonStrictValueWithNoDeps)
177 .build());
178
179 addParameter(
Roma Kauldfe650a2018-08-02 17:48:51 +0530180 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
181 .withDefault(new C2StreamProfileLevelInfo::output(
182 0u, PROFILE_HEVC_MAIN, LEVEL_HEVC_MAIN_1))
183 .withFields({
184 C2F(mProfileLevel, profile)
185 .oneOf({C2Config::PROFILE_HEVC_MAIN,
186 C2Config::PROFILE_HEVC_MAIN_STILL}),
187 C2F(mProfileLevel, level)
188 .oneOf({LEVEL_HEVC_MAIN_1, LEVEL_HEVC_MAIN_2,
189 LEVEL_HEVC_MAIN_2_1, LEVEL_HEVC_MAIN_3,
190 LEVEL_HEVC_MAIN_3_1, LEVEL_HEVC_MAIN_4,
191 LEVEL_HEVC_MAIN_4_1, LEVEL_HEVC_MAIN_5,
192 LEVEL_HEVC_MAIN_5_1, LEVEL_HEVC_MAIN_5_2}),
193 })
194 .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
195 .build());
196
197 addParameter(
198 DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
199 .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
200 .withFields({C2F(mRequestSync, value).oneOf({ C2_FALSE, C2_TRUE }) })
201 .withSetter(Setter<decltype(*mRequestSync)>::NonStrictValueWithNoDeps)
202 .build());
203
204 addParameter(
205 DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
206 .withDefault(
207 new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
208 .withFields({C2F(mSyncFramePeriod, value).any()})
209 .withSetter(
210 Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
211 .build());
Manisha Jajoo110682e2019-11-05 11:12:58 -0800212
213 addParameter(
214 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
215 .withDefault(new C2StreamColorAspectsInfo::input(
216 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
217 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
218 .withFields({
219 C2F(mColorAspects, range).inRange(
220 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
221 C2F(mColorAspects, primaries).inRange(
222 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
223 C2F(mColorAspects, transfer).inRange(
224 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
225 C2F(mColorAspects, matrix).inRange(
226 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
227 })
228 .withSetter(ColorAspectsSetter)
229 .build());
230
231 addParameter(
232 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
233 .withDefault(new C2StreamColorAspectsInfo::output(
234 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
235 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
236 .withFields({
237 C2F(mCodedColorAspects, range).inRange(
238 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
239 C2F(mCodedColorAspects, primaries).inRange(
240 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
241 C2F(mCodedColorAspects, transfer).inRange(
242 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
243 C2F(mCodedColorAspects, matrix).inRange(
244 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
245 })
246 .withSetter(CodedColorAspectsSetter, mColorAspects)
247 .build());
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530248
249 addParameter(
250 DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
251 .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
252 0 /* flexCount */, 0u /* stream */))
253 .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
254 {C2Config::picture_type_t(I_FRAME),
255 C2Config::picture_type_t(P_FRAME),
256 C2Config::picture_type_t(B_FRAME)}),
257 C2F(mPictureQuantization, m.values[0].min).any(),
258 C2F(mPictureQuantization, m.values[0].max).any()})
259 .withSetter(PictureQuantizationSetter)
260 .build());
Roma Kauldfe650a2018-08-02 17:48:51 +0530261 }
262
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700263 static C2R InputDelaySetter(
264 bool mayBlock,
265 C2P<C2PortActualDelayTuning::input> &me,
266 const C2P<C2StreamGopTuning::output> &gop) {
267 (void)mayBlock;
268 uint32_t maxBframes = 0;
269 ParseGop(gop.v, nullptr, nullptr, &maxBframes);
270 me.set().value = maxBframes + DEFAULT_RC_LOOKAHEAD;
271 return C2R::Ok();
272 }
273
Roma Kauldfe650a2018-08-02 17:48:51 +0530274 static C2R BitrateSetter(bool mayBlock,
275 C2P<C2StreamBitrateInfo::output>& me) {
276 (void)mayBlock;
277 C2R res = C2R::Ok();
Ray Essick0d11a7e2019-03-02 20:10:30 -0800278 if (me.v.value < 4096) {
Roma Kauldfe650a2018-08-02 17:48:51 +0530279 me.set().value = 4096;
280 }
281 return res;
282 }
283
284 static C2R SizeSetter(bool mayBlock,
285 const C2P<C2StreamPictureSizeInfo::input>& oldMe,
286 C2P<C2StreamPictureSizeInfo::input>& me) {
287 (void)mayBlock;
288 C2R res = C2R::Ok();
289 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
290 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
291 me.set().width = oldMe.v.width;
292 }
293 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
294 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
295 me.set().height = oldMe.v.height;
296 }
297 return res;
298 }
299
300 static C2R ProfileLevelSetter(
301 bool mayBlock,
302 C2P<C2StreamProfileLevelInfo::output> &me,
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800303 const C2P<C2StreamPictureSizeInfo::input> &size,
Roma Kauldfe650a2018-08-02 17:48:51 +0530304 const C2P<C2StreamFrameRateInfo::output> &frameRate,
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800305 const C2P<C2StreamBitrateInfo::output> &bitrate) {
Roma Kauldfe650a2018-08-02 17:48:51 +0530306 (void)mayBlock;
307 if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
308 me.set().profile = PROFILE_HEVC_MAIN;
309 }
310
311 struct LevelLimits {
312 C2Config::level_t level;
313 uint64_t samplesPerSec;
314 uint64_t samples;
315 uint32_t bitrate;
316 };
317
318 constexpr LevelLimits kLimits[] = {
319 { LEVEL_HEVC_MAIN_1, 552960, 36864, 128000 },
320 { LEVEL_HEVC_MAIN_2, 3686400, 122880, 1500000 },
321 { LEVEL_HEVC_MAIN_2_1, 7372800, 245760, 3000000 },
322 { LEVEL_HEVC_MAIN_3, 16588800, 552960, 6000000 },
323 { LEVEL_HEVC_MAIN_3_1, 33177600, 983040, 10000000 },
324 { LEVEL_HEVC_MAIN_4, 66846720, 2228224, 12000000 },
325 { LEVEL_HEVC_MAIN_4_1, 133693440, 2228224, 20000000 },
326 { LEVEL_HEVC_MAIN_5, 267386880, 8912896, 25000000 },
327 { LEVEL_HEVC_MAIN_5_1, 534773760, 8912896, 40000000 },
328 { LEVEL_HEVC_MAIN_5_2, 1069547520, 8912896, 60000000 },
329 { LEVEL_HEVC_MAIN_6, 1069547520, 35651584, 60000000 },
330 { LEVEL_HEVC_MAIN_6_1, 2139095040, 35651584, 120000000 },
331 { LEVEL_HEVC_MAIN_6_2, 4278190080, 35651584, 240000000 },
332 };
333
334 uint64_t samples = size.v.width * size.v.height;
335 uint64_t samplesPerSec = samples * frameRate.v.value;
336
337 // Check if the supplied level meets the MB / bitrate requirements. If
338 // not, update the level with the lowest level meeting the requirements.
339
340 bool found = false;
341 // By default needsUpdate = false in case the supplied level does meet
342 // the requirements.
343 bool needsUpdate = false;
344 for (const LevelLimits &limit : kLimits) {
345 if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
346 bitrate.v.value <= limit.bitrate) {
347 // This is the lowest level that meets the requirements, and if
348 // we haven't seen the supplied level yet, that means we don't
349 // need the update.
350 if (needsUpdate) {
351 ALOGD("Given level %x does not cover current configuration: "
352 "adjusting to %x", me.v.level, limit.level);
353 me.set().level = limit.level;
354 }
355 found = true;
356 break;
357 }
358 if (me.v.level == limit.level) {
359 // We break out of the loop when the lowest feasible level is
360 // found. The fact that we're here means that our level doesn't
361 // meet the requirement and needs to be updated.
362 needsUpdate = true;
363 }
364 }
365 if (!found) {
366 // We set to the highest supported level.
367 me.set().level = LEVEL_HEVC_MAIN_5_2;
368 }
369 return C2R::Ok();
370 }
371
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700372 static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
373 (void)mayBlock;
374 for (size_t i = 0; i < me.v.flexCount(); ++i) {
375 const C2GopLayerStruct &layer = me.v.m.values[0];
376 if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
377 && layer.count > MAX_B_FRAMES) {
378 me.set().m.values[i].count = MAX_B_FRAMES;
379 }
380 }
381 return C2R::Ok();
382 }
383
Roma Kauldfe650a2018-08-02 17:48:51 +0530384 UWORD32 getProfile_l() const {
385 switch (mProfileLevel->profile) {
386 case PROFILE_HEVC_MAIN: [[fallthrough]];
387 case PROFILE_HEVC_MAIN_STILL: return 1;
388 default:
389 ALOGD("Unrecognized profile: %x", mProfileLevel->profile);
390 return 1;
391 }
392 }
393
394 UWORD32 getLevel_l() const {
395 struct Level {
396 C2Config::level_t c2Level;
397 UWORD32 hevcLevel;
398 };
399 constexpr Level levels[] = {
400 { LEVEL_HEVC_MAIN_1, 30 },
401 { LEVEL_HEVC_MAIN_2, 60 },
402 { LEVEL_HEVC_MAIN_2_1, 63 },
403 { LEVEL_HEVC_MAIN_3, 90 },
404 { LEVEL_HEVC_MAIN_3_1, 93 },
405 { LEVEL_HEVC_MAIN_4, 120 },
406 { LEVEL_HEVC_MAIN_4_1, 123 },
407 { LEVEL_HEVC_MAIN_5, 150 },
408 { LEVEL_HEVC_MAIN_5_1, 153 },
409 { LEVEL_HEVC_MAIN_5_2, 156 },
410 { LEVEL_HEVC_MAIN_6, 180 },
411 { LEVEL_HEVC_MAIN_6_1, 183 },
412 { LEVEL_HEVC_MAIN_6_2, 186 },
413 };
414 for (const Level &level : levels) {
415 if (mProfileLevel->level == level.c2Level) {
416 return level.hevcLevel;
417 }
418 }
419 ALOGD("Unrecognized level: %x", mProfileLevel->level);
420 return 156;
421 }
422 uint32_t getSyncFramePeriod_l() const {
423 if (mSyncFramePeriod->value < 0 ||
424 mSyncFramePeriod->value == INT64_MAX) {
425 return 0;
426 }
427 double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
428 return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
429 }
430
Ray Essick0d11a7e2019-03-02 20:10:30 -0800431 std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
Roma Kauldfe650a2018-08-02 17:48:51 +0530432 return mSize;
433 }
434 std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
435 return mFrameRate;
436 }
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800437 std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const {
438 return mBitrateMode;
439 }
Roma Kauldfe650a2018-08-02 17:48:51 +0530440 std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const {
441 return mBitrate;
442 }
443 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const {
444 return mRequestSync;
445 }
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800446 std::shared_ptr<C2StreamComplexityTuning::output> getComplexity_l() const {
447 return mComplexity;
448 }
449 std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
450 return mQuality;
451 }
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700452 std::shared_ptr<C2StreamGopTuning::output> getGop_l() const {
453 return mGop;
454 }
Manisha Jajoo110682e2019-11-05 11:12:58 -0800455 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
456 (void)mayBlock;
457 if (me.v.range > C2Color::RANGE_OTHER) {
458 me.set().range = C2Color::RANGE_OTHER;
459 }
460 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
461 me.set().primaries = C2Color::PRIMARIES_OTHER;
462 }
463 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
464 me.set().transfer = C2Color::TRANSFER_OTHER;
465 }
466 if (me.v.matrix > C2Color::MATRIX_OTHER) {
467 me.set().matrix = C2Color::MATRIX_OTHER;
468 }
469 return C2R::Ok();
470 }
471 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
472 const C2P<C2StreamColorAspectsInfo::input> &coded) {
473 (void)mayBlock;
474 me.set().range = coded.v.range;
475 me.set().primaries = coded.v.primaries;
476 me.set().transfer = coded.v.transfer;
477 me.set().matrix = coded.v.matrix;
478 return C2R::Ok();
479 }
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530480 static C2R PictureQuantizationSetter(bool mayBlock,
481 C2P<C2StreamPictureQuantizationTuning::output> &me) {
482 (void)mayBlock;
483
484 // these are the ones we're going to set, so want them to default
485 // to the DEFAULT values for the codec
486 int32_t iMin = HEVC_QP_MIN, pMin = HEVC_QP_MIN, bMin = HEVC_QP_MIN;
487 int32_t iMax = HEVC_QP_MAX, pMax = HEVC_QP_MAX, bMax = HEVC_QP_MAX;
488
489 for (size_t i = 0; i < me.v.flexCount(); ++i) {
490 const C2PictureQuantizationStruct &layer = me.v.m.values[i];
491
492 // layerMin is clamped to [HEVC_QP_MIN, layerMax] to avoid error
493 // cases where layer.min > layer.max
494 int32_t layerMax = std::clamp(layer.max, HEVC_QP_MIN, HEVC_QP_MAX);
495 int32_t layerMin = std::clamp(layer.min, HEVC_QP_MIN, layerMax);
496 if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
497 iMax = layerMax;
498 iMin = layerMin;
499 ALOGV("iMin %d iMax %d", iMin, iMax);
500 } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
501 pMax = layerMax;
502 pMin = layerMin;
503 ALOGV("pMin %d pMax %d", pMin, pMax);
504 } else if (layer.type_ == C2Config::picture_type_t(B_FRAME)) {
505 bMax = layerMax;
506 bMin = layerMin;
507 ALOGV("bMin %d bMax %d", bMin, bMax);
508 }
509 }
510
511 ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d b %d-%d",
512 iMin, iMax, pMin, pMax, bMin, bMax);
513
514 int32_t maxFrameQP = std::min(std::min(iMax, pMax), bMax);
515 int32_t minFrameQP = std::max(std::max(iMin, pMin), bMin);
516 if (minFrameQP > maxFrameQP) {
517 minFrameQP = maxFrameQP;
518 }
519
520 // put them back into the structure
521 for (size_t i = 0; i < me.v.flexCount(); ++i) {
522 const C2PictureQuantizationStruct &layer = me.v.m.values[i];
523
524 if (layer.type_ == C2Config::picture_type_t(I_FRAME) ||
525 layer.type_ == C2Config::picture_type_t(P_FRAME) ||
526 layer.type_ == C2Config::picture_type_t(B_FRAME)) {
527 me.set().m.values[i].max = maxFrameQP;
528 me.set().m.values[i].min = minFrameQP;
529 }
530 }
531
532 ALOGV("PictureQuantizationSetter(exit): i = p = b = %d-%d",
533 minFrameQP, maxFrameQP);
534
535 return C2R::Ok();
536 }
Manisha Jajoo110682e2019-11-05 11:12:58 -0800537 std::shared_ptr<C2StreamColorAspectsInfo::output> getCodedColorAspects_l() {
538 return mCodedColorAspects;
539 }
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530540 std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
541 return mPictureQuantization;
542 }
Roma Kauldfe650a2018-08-02 17:48:51 +0530543
544 private:
Roma Kauldfe650a2018-08-02 17:48:51 +0530545 std::shared_ptr<C2StreamUsageTuning::input> mUsage;
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800546 std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
Roma Kauldfe650a2018-08-02 17:48:51 +0530547 std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
548 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800549 std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800550 std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
551 std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
552 std::shared_ptr<C2StreamQualityTuning::output> mQuality;
Roma Kauldfe650a2018-08-02 17:48:51 +0530553 std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
554 std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700555 std::shared_ptr<C2StreamGopTuning::output> mGop;
Manisha Jajoo110682e2019-11-05 11:12:58 -0800556 std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
557 std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530558 std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
Roma Kauldfe650a2018-08-02 17:48:51 +0530559};
Ray Essick0d11a7e2019-03-02 20:10:30 -0800560
Roma Kauldfe650a2018-08-02 17:48:51 +0530561static size_t GetCPUCoreCount() {
Ray Essick0d11a7e2019-03-02 20:10:30 -0800562 long cpuCoreCount = 0;
563
Roma Kauldfe650a2018-08-02 17:48:51 +0530564#if defined(_SC_NPROCESSORS_ONLN)
565 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
566#else
567 // _SC_NPROC_ONLN must be defined...
568 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
569#endif
Ray Essick0d11a7e2019-03-02 20:10:30 -0800570
571 if (cpuCoreCount < 1)
572 cpuCoreCount = 1;
Roma Kauldfe650a2018-08-02 17:48:51 +0530573 return (size_t)cpuCoreCount;
574}
575
576C2SoftHevcEnc::C2SoftHevcEnc(const char* name, c2_node_id_t id,
577 const std::shared_ptr<IntfImpl>& intfImpl)
578 : SimpleC2Component(
579 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
580 mIntf(intfImpl),
581 mIvVideoColorFormat(IV_YUV_420P),
582 mHevcEncProfile(1),
583 mHevcEncLevel(30),
584 mStarted(false),
585 mSpsPpsHeaderReceived(false),
586 mSignalledEos(false),
587 mSignalledError(false),
588 mCodecCtx(nullptr) {
589 // If dump is enabled, then create an empty file
590 GENERATE_FILE_NAMES();
591 CREATE_DUMP_FILE(mInFile);
592 CREATE_DUMP_FILE(mOutFile);
593
Ray Essick24754942022-04-16 09:50:35 -0700594 mTimeStart = mTimeEnd = systemTime();
Roma Kauldfe650a2018-08-02 17:48:51 +0530595}
596
597C2SoftHevcEnc::~C2SoftHevcEnc() {
Harish Mahendrakard493e982019-05-18 19:55:57 -0700598 onRelease();
Roma Kauldfe650a2018-08-02 17:48:51 +0530599}
600
601c2_status_t C2SoftHevcEnc::onInit() {
Harish Mahendrakard493e982019-05-18 19:55:57 -0700602 return C2_OK;
Roma Kauldfe650a2018-08-02 17:48:51 +0530603}
604
605c2_status_t C2SoftHevcEnc::onStop() {
Harish Mahendrakard493e982019-05-18 19:55:57 -0700606 return C2_OK;
Roma Kauldfe650a2018-08-02 17:48:51 +0530607}
608
609void C2SoftHevcEnc::onReset() {
Harish Mahendrakard493e982019-05-18 19:55:57 -0700610 releaseEncoder();
Roma Kauldfe650a2018-08-02 17:48:51 +0530611}
612
613void C2SoftHevcEnc::onRelease() {
Harish Mahendrakard493e982019-05-18 19:55:57 -0700614 releaseEncoder();
Roma Kauldfe650a2018-08-02 17:48:51 +0530615}
616
617c2_status_t C2SoftHevcEnc::onFlush_sm() {
618 return C2_OK;
619}
620
621static void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
622 uint32_t flags = 0;
623 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
624 flags |= C2FrameData::FLAG_END_OF_STREAM;
625 ALOGV("Signalling EOS");
626 }
627 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
628 work->worklets.front()->output.buffers.clear();
629 work->worklets.front()->output.ordinal = work->input.ordinal;
630 work->workletsProcessed = 1u;
631}
632
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800633static int getQpFromQuality(int quality) {
634 int qp;
635#define MIN_QP 4
636#define MAX_QP 50
637 /* Quality: 100 -> Qp : MIN_QP
638 * Quality: 0 -> Qp : MAX_QP
639 * Qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
640 */
641 qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
642 qp = std::min(qp, MAX_QP);
643 qp = std::max(qp, MIN_QP);
644 return qp;
645}
Roma Kauldfe650a2018-08-02 17:48:51 +0530646c2_status_t C2SoftHevcEnc::initEncParams() {
647 mCodecCtx = nullptr;
Ray Essick0d11a7e2019-03-02 20:10:30 -0800648 mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
Roma Kauldfe650a2018-08-02 17:48:51 +0530649 memset(&mEncParams, 0, sizeof(ihevce_static_cfg_params_t));
650
651 // default configuration
652 IHEVCE_PLUGIN_STATUS_T err = ihevce_set_def_params(&mEncParams);
653 if (IHEVCE_EOK != err) {
654 ALOGE("HEVC default init failed : 0x%x", err);
655 return C2_CORRUPTED;
656 }
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700657 mBframes = 0;
658 if (mGop && mGop->flexCount() > 0) {
659 uint32_t syncInterval = 1;
660 uint32_t iInterval = 1;
661 uint32_t maxBframes = 0;
662 ParseGop(*mGop, &syncInterval, &iInterval, &maxBframes);
663 if (syncInterval > 0) {
664 ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
665 mIDRInterval = syncInterval;
666 }
667 if (iInterval > 0) {
668 ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
669 mIInterval = iInterval;
670 }
671 if (mBframes != maxBframes) {
672 ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
673 mBframes = maxBframes;
674 }
675 }
Manisha Jajoo110682e2019-11-05 11:12:58 -0800676 ColorAspects sfAspects;
677 if (!C2Mapper::map(mColorAspects->primaries, &sfAspects.mPrimaries)) {
678 sfAspects.mPrimaries = android::ColorAspects::PrimariesUnspecified;
679 }
680 if (!C2Mapper::map(mColorAspects->range, &sfAspects.mRange)) {
681 sfAspects.mRange = android::ColorAspects::RangeUnspecified;
682 }
683 if (!C2Mapper::map(mColorAspects->matrix, &sfAspects.mMatrixCoeffs)) {
684 sfAspects.mMatrixCoeffs = android::ColorAspects::MatrixUnspecified;
685 }
686 if (!C2Mapper::map(mColorAspects->transfer, &sfAspects.mTransfer)) {
687 sfAspects.mTransfer = android::ColorAspects::TransferUnspecified;
688 }
689 int32_t primaries, transfer, matrixCoeffs;
690 bool range;
691 ColorUtils::convertCodecColorAspectsToIsoAspects(sfAspects,
692 &primaries,
693 &transfer,
694 &matrixCoeffs,
695 &range);
696 mEncParams.s_out_strm_prms.i4_vui_enable = 1;
697 mEncParams.s_vui_sei_prms.u1_colour_description_present_flag = 1;
698 mEncParams.s_vui_sei_prms.u1_colour_primaries = primaries;
699 mEncParams.s_vui_sei_prms.u1_transfer_characteristics = transfer;
700 mEncParams.s_vui_sei_prms.u1_matrix_coefficients = matrixCoeffs;
701 mEncParams.s_vui_sei_prms.u1_video_full_range_flag = range;
Roma Kauldfe650a2018-08-02 17:48:51 +0530702 // update configuration
703 mEncParams.s_src_prms.i4_width = mSize->width;
704 mEncParams.s_src_prms.i4_height = mSize->height;
705 mEncParams.s_src_prms.i4_frm_rate_denom = 1000;
Ray Essick0d11a7e2019-03-02 20:10:30 -0800706 mEncParams.s_src_prms.i4_frm_rate_num =
707 mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
Roma Kauldfe650a2018-08-02 17:48:51 +0530708 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
709 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
710 mBitrate->value;
711 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] =
712 mBitrate->value << 1;
713 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_codec_level = mHevcEncLevel;
714 mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = mIDRInterval;
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700715 mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIInterval;
Roma Kauldfe650a2018-08-02 17:48:51 +0530716 mIvVideoColorFormat = IV_YUV_420P;
717 mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
718 mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530719 mEncParams.s_lap_prms.i4_rc_look_ahead_pics = DEFAULT_RC_LOOKAHEAD;
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700720 if (mBframes == 0) {
721 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 0;
722 } else if (mBframes <= 2) {
723 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 1;
724 } else if (mBframes <= 6) {
725 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 2;
726 } else {
727 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
728 }
Roma Kauldfe650a2018-08-02 17:48:51 +0530729
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530730 // we resolved out-of-bound and unspecified values in PictureQuantizationSetter()
731 // so we can start with defaults that are overridden as needed.
732 int32_t maxFrameQP = mEncParams.s_config_prms.i4_max_frame_qp;
733 int32_t minFrameQP = mEncParams.s_config_prms.i4_min_frame_qp;
734
735 for (size_t i = 0; i < mQpBounds->flexCount(); ++i) {
736 const C2PictureQuantizationStruct &layer = mQpBounds->m.values[i];
737
738 // no need to loop, hevc library takes same range for I/P/B picture type
739 if (layer.type_ == C2Config::picture_type_t(I_FRAME) ||
740 layer.type_ == C2Config::picture_type_t(P_FRAME) ||
741 layer.type_ == C2Config::picture_type_t(B_FRAME)) {
742
743 maxFrameQP = layer.max;
744 minFrameQP = layer.min;
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800745 break;
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530746 }
747 }
748 mEncParams.s_config_prms.i4_max_frame_qp = maxFrameQP;
749 mEncParams.s_config_prms.i4_min_frame_qp = minFrameQP;
750
751 ALOGV("MaxFrameQp: %d MinFrameQp: %d", maxFrameQP, minFrameQP);
752
753 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
754 std::clamp(kDefaultInitQP, minFrameQP, maxFrameQP);
755
756 switch (mBitrateMode->value) {
757 case C2Config::BITRATE_IGNORE: {
758 mEncParams.s_config_prms.i4_rate_control_mode = 3;
759 // ensure initial qp values are within our newly configured bounds
760 int32_t frameQp = getQpFromQuality(mQuality->value);
761 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
762 std::clamp(frameQp, minFrameQP, maxFrameQP);
763 break;
764 }
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800765 case C2Config::BITRATE_CONST:
766 mEncParams.s_config_prms.i4_rate_control_mode = 5;
767 break;
768 case C2Config::BITRATE_VARIABLE:
769 [[fallthrough]];
770 default:
771 mEncParams.s_config_prms.i4_rate_control_mode = 2;
772 break;
773 break;
774 }
775
776 if (mComplexity->value == 10) {
777 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P0;
778 } else if (mComplexity->value >= 8) {
779 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P2;
780 } else if (mComplexity->value >= 7) {
781 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P3;
782 } else if (mComplexity->value >= 5) {
783 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P4;
784 } else {
785 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
786 }
787
Roma Kauldfe650a2018-08-02 17:48:51 +0530788 return C2_OK;
789}
790
791c2_status_t C2SoftHevcEnc::releaseEncoder() {
792 mSpsPpsHeaderReceived = false;
793 mSignalledEos = false;
794 mSignalledError = false;
795 mStarted = false;
796
797 if (mCodecCtx) {
798 IHEVCE_PLUGIN_STATUS_T err = ihevce_close(mCodecCtx);
799 if (IHEVCE_EOK != err) return C2_CORRUPTED;
800 mCodecCtx = nullptr;
801 }
802 return C2_OK;
803}
804
805c2_status_t C2SoftHevcEnc::drain(uint32_t drainMode,
806 const std::shared_ptr<C2BlockPool>& pool) {
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530807 return drainInternal(drainMode, pool, nullptr);
Roma Kauldfe650a2018-08-02 17:48:51 +0530808}
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530809
Roma Kauldfe650a2018-08-02 17:48:51 +0530810c2_status_t C2SoftHevcEnc::initEncoder() {
811 CHECK(!mCodecCtx);
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700812
Roma Kauldfe650a2018-08-02 17:48:51 +0530813 {
814 IntfImpl::Lock lock = mIntf->lock();
815 mSize = mIntf->getSize_l();
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800816 mBitrateMode = mIntf->getBitrateMode_l();
Roma Kauldfe650a2018-08-02 17:48:51 +0530817 mBitrate = mIntf->getBitrate_l();
818 mFrameRate = mIntf->getFrameRate_l();
819 mHevcEncProfile = mIntf->getProfile_l();
820 mHevcEncLevel = mIntf->getLevel_l();
821 mIDRInterval = mIntf->getSyncFramePeriod_l();
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700822 mIInterval = mIntf->getSyncFramePeriod_l();
Harish Mahendrakar57d7cc92019-02-05 08:34:55 -0800823 mComplexity = mIntf->getComplexity_l();
824 mQuality = mIntf->getQuality_l();
Harish Mahendrakarfbccd2e2019-05-22 15:20:21 -0700825 mGop = mIntf->getGop_l();
Rakesh Kumarb17576c2019-07-30 20:10:54 +0530826 mRequestSync = mIntf->getRequestSync_l();
Manisha Jajoo110682e2019-11-05 11:12:58 -0800827 mColorAspects = mIntf->getCodedColorAspects_l();
Manisha Jajoo21b9f842021-05-06 22:19:30 +0530828 mQpBounds = mIntf->getPictureQuantization_l();;
Roma Kauldfe650a2018-08-02 17:48:51 +0530829 }
830
831 c2_status_t status = initEncParams();
832
833 if (C2_OK != status) {
834 ALOGE("Failed to initialize encoder params : 0x%x", status);
835 mSignalledError = true;
836 return status;
837 }
838
839 IHEVCE_PLUGIN_STATUS_T err = IHEVCE_EOK;
840 err = ihevce_init(&mEncParams, &mCodecCtx);
841 if (IHEVCE_EOK != err) {
842 ALOGE("HEVC encoder init failed : 0x%x", err);
843 return C2_CORRUPTED;
844 }
845
846 mStarted = true;
847 return C2_OK;
848}
849
850c2_status_t C2SoftHevcEnc::setEncodeArgs(ihevce_inp_buf_t* ps_encode_ip,
851 const C2GraphicView* const input,
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530852 uint64_t workIndex) {
Roma Kauldfe650a2018-08-02 17:48:51 +0530853 ihevce_static_cfg_params_t* params = &mEncParams;
Ray Essick0d11a7e2019-03-02 20:10:30 -0800854 memset(ps_encode_ip, 0, sizeof(*ps_encode_ip));
Roma Kauldfe650a2018-08-02 17:48:51 +0530855
856 if (!input) {
857 return C2_OK;
858 }
859
860 if (input->width() < mSize->width ||
861 input->height() < mSize->height) {
862 /* Expect width height to be configured */
863 ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", input->width(),
864 mSize->width, input->height(), mSize->height);
865 return C2_BAD_VALUE;
866 }
867
868 const C2PlanarLayout& layout = input->layout();
869 uint8_t* yPlane =
870 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
871 uint8_t* uPlane =
872 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
873 uint8_t* vPlane =
874 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_V]);
875 int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
876 int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
877 int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
878
Ray Essick0d11a7e2019-03-02 20:10:30 -0800879 const uint32_t width = mSize->width;
880 const uint32_t height = mSize->height;
Roma Kauldfe650a2018-08-02 17:48:51 +0530881
Ray Essick0d11a7e2019-03-02 20:10:30 -0800882 // width and height must be even
883 if (width & 1u || height & 1u) {
884 ALOGW("height(%u) and width(%u) must both be even", height, width);
885 return C2_BAD_VALUE;
886 }
Roma Kauldfe650a2018-08-02 17:48:51 +0530887
888 size_t yPlaneSize = width * height;
889
890 switch (layout.type) {
891 case C2PlanarLayout::TYPE_RGB:
892 [[fallthrough]];
893 case C2PlanarLayout::TYPE_RGBA: {
894 MemoryBlock conversionBuffer =
895 mConversionBuffers.fetch(yPlaneSize * 3 / 2);
896 mConversionBuffersInUse.emplace(conversionBuffer.data(),
897 conversionBuffer);
898 yPlane = conversionBuffer.data();
899 uPlane = yPlane + yPlaneSize;
900 vPlane = uPlane + yPlaneSize / 4;
901 yStride = width;
902 uStride = vStride = yStride / 2;
903 ConvertRGBToPlanarYUV(yPlane, yStride, height,
Manisha Jajood9f98442021-06-02 11:27:07 +0530904 conversionBuffer.size(), *input,
905 mColorAspects->matrix, mColorAspects->range);
Roma Kauldfe650a2018-08-02 17:48:51 +0530906 break;
907 }
908 case C2PlanarLayout::TYPE_YUV: {
909 if (!IsYUV420(*input)) {
910 ALOGE("input is not YUV420");
911 return C2_BAD_VALUE;
912 }
913
914 if (layout.planes[layout.PLANE_Y].colInc == 1 &&
915 layout.planes[layout.PLANE_U].colInc == 1 &&
916 layout.planes[layout.PLANE_V].colInc == 1 &&
917 uStride == vStride && yStride == 2 * vStride) {
918 // I420 compatible - already set up above
919 break;
920 }
921
922 // copy to I420
923 yStride = width;
924 uStride = vStride = yStride / 2;
925 MemoryBlock conversionBuffer =
926 mConversionBuffers.fetch(yPlaneSize * 3 / 2);
927 mConversionBuffersInUse.emplace(conversionBuffer.data(),
928 conversionBuffer);
929 MediaImage2 img =
930 CreateYUV420PlanarMediaImage2(width, height, yStride, height);
931 status_t err = ImageCopy(conversionBuffer.data(), &img, *input);
932 if (err != OK) {
933 ALOGE("Buffer conversion failed: %d", err);
934 return C2_BAD_VALUE;
935 }
936 yPlane = conversionBuffer.data();
937 uPlane = yPlane + yPlaneSize;
938 vPlane = uPlane + yPlaneSize / 4;
939 break;
940 }
941
942 case C2PlanarLayout::TYPE_YUVA:
943 ALOGE("YUVA plane type is not supported");
944 return C2_BAD_VALUE;
945
946 default:
947 ALOGE("Unrecognized plane type: %d", layout.type);
948 return C2_BAD_VALUE;
949 }
950
951 switch (mIvVideoColorFormat) {
952 case IV_YUV_420P: {
953 // input buffer is supposed to be const but Ittiam API wants bare
954 // pointer.
955 ps_encode_ip->apv_inp_planes[0] = yPlane;
956 ps_encode_ip->apv_inp_planes[1] = uPlane;
957 ps_encode_ip->apv_inp_planes[2] = vPlane;
958
959 ps_encode_ip->ai4_inp_strd[0] = yStride;
960 ps_encode_ip->ai4_inp_strd[1] = uStride;
961 ps_encode_ip->ai4_inp_strd[2] = vStride;
962
963 ps_encode_ip->ai4_inp_size[0] = yStride * height;
964 ps_encode_ip->ai4_inp_size[1] = uStride * height >> 1;
965 ps_encode_ip->ai4_inp_size[2] = vStride * height >> 1;
966 break;
967 }
968
969 case IV_YUV_422ILE: {
970 // TODO
971 break;
972 }
973
974 case IV_YUV_420SP_UV:
975 case IV_YUV_420SP_VU:
976 default: {
977 ps_encode_ip->apv_inp_planes[0] = yPlane;
978 ps_encode_ip->apv_inp_planes[1] = uPlane;
979 ps_encode_ip->apv_inp_planes[2] = nullptr;
980
981 ps_encode_ip->ai4_inp_strd[0] = yStride;
982 ps_encode_ip->ai4_inp_strd[1] = uStride;
983 ps_encode_ip->ai4_inp_strd[2] = 0;
984
985 ps_encode_ip->ai4_inp_size[0] = yStride * height;
986 ps_encode_ip->ai4_inp_size[1] = uStride * height >> 1;
987 ps_encode_ip->ai4_inp_size[2] = 0;
988 break;
989 }
990 }
991
992 ps_encode_ip->i4_curr_bitrate =
993 params->s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0];
994 ps_encode_ip->i4_curr_peak_bitrate =
995 params->s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0];
996 ps_encode_ip->i4_curr_rate_factor = params->s_config_prms.i4_rate_factor;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +0530997 ps_encode_ip->u8_pts = workIndex;
998 return C2_OK;
999}
1000
1001void C2SoftHevcEnc::finishWork(uint64_t index,
1002 const std::unique_ptr<C2Work>& work,
1003 const std::shared_ptr<C2BlockPool>& pool,
1004 ihevce_out_buf_t* ps_encode_op) {
1005 std::shared_ptr<C2LinearBlock> block;
1006 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
1007 c2_status_t status =
1008 pool->fetchLinearBlock(ps_encode_op->i4_bytes_generated, usage, &block);
1009 if (C2_OK != status) {
1010 ALOGE("fetchLinearBlock for Output failed with status 0x%x", status);
1011 mSignalledError = true;
1012 work->result = status;
1013 work->workletsProcessed = 1u;
1014 return;
1015 }
1016 C2WriteView wView = block->map().get();
1017 if (C2_OK != wView.error()) {
1018 ALOGE("write view map failed with status 0x%x", wView.error());
1019 mSignalledError = true;
1020 work->result = wView.error();
1021 work->workletsProcessed = 1u;
1022 return;
1023 }
1024 memcpy(wView.data(), ps_encode_op->pu1_output_buf,
1025 ps_encode_op->i4_bytes_generated);
1026
1027 std::shared_ptr<C2Buffer> buffer =
1028 createLinearBuffer(block, 0, ps_encode_op->i4_bytes_generated);
1029
1030 DUMP_TO_FILE(mOutFile, ps_encode_op->pu1_output_buf,
1031 ps_encode_op->i4_bytes_generated);
1032
1033 if (ps_encode_op->i4_is_key_frame) {
1034 ALOGV("IDR frame produced");
1035 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
1036 0u /* stream id */, C2Config::SYNC_FRAME));
1037 }
1038
1039 auto fillWork = [buffer](const std::unique_ptr<C2Work>& work) {
1040 work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
1041 work->worklets.front()->output.buffers.clear();
1042 work->worklets.front()->output.buffers.push_back(buffer);
1043 work->worklets.front()->output.ordinal = work->input.ordinal;
1044 work->workletsProcessed = 1u;
1045 };
1046 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
1047 fillWork(work);
1048 if (mSignalledEos) {
1049 work->worklets.front()->output.flags =
1050 C2FrameData::FLAG_END_OF_STREAM;
1051 }
1052 } else {
1053 finish(index, fillWork);
1054 }
1055}
1056
1057c2_status_t C2SoftHevcEnc::drainInternal(
1058 uint32_t drainMode,
1059 const std::shared_ptr<C2BlockPool> &pool,
1060 const std::unique_ptr<C2Work> &work) {
1061
1062 if (drainMode == NO_DRAIN) {
1063 ALOGW("drain with NO_DRAIN: no-op");
1064 return C2_OK;
1065 }
1066 if (drainMode == DRAIN_CHAIN) {
1067 ALOGW("DRAIN_CHAIN not supported");
1068 return C2_OMITTED;
1069 }
1070
1071 while (true) {
1072 ihevce_out_buf_t s_encode_op{};
1073 memset(&s_encode_op, 0, sizeof(s_encode_op));
1074
1075 ihevce_encode(mCodecCtx, nullptr, &s_encode_op);
1076 if (s_encode_op.i4_bytes_generated) {
1077 finishWork(s_encode_op.u8_pts, work, pool, &s_encode_op);
1078 } else {
1079 if (work->workletsProcessed != 1u) fillEmptyWork(work);
1080 break;
1081 }
1082 }
Roma Kauldfe650a2018-08-02 17:48:51 +05301083 return C2_OK;
1084}
1085
1086void C2SoftHevcEnc::process(const std::unique_ptr<C2Work>& work,
1087 const std::shared_ptr<C2BlockPool>& pool) {
1088 // Initialize output work
1089 work->result = C2_OK;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301090 work->workletsProcessed = 0u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301091 work->worklets.front()->output.flags = work->input.flags;
1092
1093 if (mSignalledError || mSignalledEos) {
1094 work->result = C2_BAD_VALUE;
1095 ALOGD("Signalled Error / Signalled Eos");
1096 return;
1097 }
1098 c2_status_t status = C2_OK;
1099
1100 // Initialize encoder if not already initialized
1101 if (!mStarted) {
1102 status = initEncoder();
1103 if (C2_OK != status) {
1104 ALOGE("Failed to initialize encoder : 0x%x", status);
1105 mSignalledError = true;
1106 work->result = status;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301107 work->workletsProcessed = 1u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301108 return;
1109 }
1110 }
1111
1112 std::shared_ptr<const C2GraphicView> view;
1113 std::shared_ptr<C2Buffer> inputBuffer = nullptr;
1114 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301115 if (eos) mSignalledEos = true;
1116
Roma Kauldfe650a2018-08-02 17:48:51 +05301117 if (!work->input.buffers.empty()) {
1118 inputBuffer = work->input.buffers[0];
1119 view = std::make_shared<const C2GraphicView>(
1120 inputBuffer->data().graphicBlocks().front().map().get());
1121 if (view->error() != C2_OK) {
1122 ALOGE("graphic view map err = %d", view->error());
1123 mSignalledError = true;
Ray Essick0d11a7e2019-03-02 20:10:30 -08001124 work->result = C2_CORRUPTED;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301125 work->workletsProcessed = 1u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301126 return;
1127 }
1128 }
Roma Kauldfe650a2018-08-02 17:48:51 +05301129 IHEVCE_PLUGIN_STATUS_T err = IHEVCE_EOK;
1130
Roma Kauldfe650a2018-08-02 17:48:51 +05301131 if (!mSpsPpsHeaderReceived) {
1132 ihevce_out_buf_t s_header_op{};
1133 err = ihevce_encode_header(mCodecCtx, &s_header_op);
1134 if (err == IHEVCE_EOK && s_header_op.i4_bytes_generated) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001135 std::unique_ptr<C2StreamInitDataInfo::output> csd =
1136 C2StreamInitDataInfo::output::AllocUnique(
Roma Kauldfe650a2018-08-02 17:48:51 +05301137 s_header_op.i4_bytes_generated, 0u);
1138 if (!csd) {
1139 ALOGE("CSD allocation failed");
1140 mSignalledError = true;
1141 work->result = C2_NO_MEMORY;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301142 work->workletsProcessed = 1u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301143 return;
1144 }
1145 memcpy(csd->m.value, s_header_op.pu1_output_buf,
1146 s_header_op.i4_bytes_generated);
1147 DUMP_TO_FILE(mOutFile, csd->m.value, csd->flexCount());
1148 work->worklets.front()->output.configUpdate.push_back(
1149 std::move(csd));
1150 mSpsPpsHeaderReceived = true;
1151 }
1152 if (!inputBuffer) {
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301153 work->workletsProcessed = 1u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301154 return;
1155 }
1156 }
Harish Mahendrakar8045d592019-05-18 18:59:21 -07001157
Rakesh Kumarb17576c2019-07-30 20:10:54 +05301158 // handle dynamic bitrate change
Harish Mahendrakar8045d592019-05-18 18:59:21 -07001159 {
1160 IntfImpl::Lock lock = mIntf->lock();
1161 std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
1162 lock.unlock();
1163
1164 if (bitrate != mBitrate) {
1165 mBitrate = bitrate;
1166 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
1167 mBitrate->value;
1168 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] =
1169 mBitrate->value << 1;
1170 }
1171 }
1172
Roma Kauldfe650a2018-08-02 17:48:51 +05301173 ihevce_inp_buf_t s_encode_ip{};
1174 ihevce_out_buf_t s_encode_op{};
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301175 uint64_t workIndex = work->input.ordinal.frameIndex.peekull();
Roma Kauldfe650a2018-08-02 17:48:51 +05301176
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301177 status = setEncodeArgs(&s_encode_ip, view.get(), workIndex);
Roma Kauldfe650a2018-08-02 17:48:51 +05301178 if (C2_OK != status) {
Roma Kauldfe650a2018-08-02 17:48:51 +05301179 ALOGE("setEncodeArgs failed : 0x%x", status);
Ray Essick0d11a7e2019-03-02 20:10:30 -08001180 mSignalledError = true;
Roma Kauldfe650a2018-08-02 17:48:51 +05301181 work->result = status;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301182 work->workletsProcessed = 1u;
Roma Kauldfe650a2018-08-02 17:48:51 +05301183 return;
1184 }
Rakesh Kumarb17576c2019-07-30 20:10:54 +05301185 // handle request key frame
1186 {
1187 IntfImpl::Lock lock = mIntf->lock();
1188 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync;
1189 requestSync = mIntf->getRequestSync_l();
1190 lock.unlock();
1191 if (requestSync != mRequestSync) {
1192 // we can handle IDR immediately
1193 if (requestSync->value) {
1194 // unset request
1195 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
1196 std::vector<std::unique_ptr<C2SettingResult>> failures;
1197 mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
1198 ALOGV("Got sync request");
1199 //Force this as an IDR frame
1200 s_encode_ip.i4_force_idr_flag = 1;
1201 }
1202 mRequestSync = requestSync;
1203 }
1204 }
Roma Kauldfe650a2018-08-02 17:48:51 +05301205
Ray Essick24754942022-04-16 09:50:35 -07001206 nsecs_t timeDelay = 0;
1207 nsecs_t timeTaken = 0;
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301208 memset(&s_encode_op, 0, sizeof(s_encode_op));
Ray Essick24754942022-04-16 09:50:35 -07001209 mTimeStart = systemTime();
1210 timeDelay = mTimeStart - mTimeEnd;
Roma Kauldfe650a2018-08-02 17:48:51 +05301211
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301212 if (inputBuffer) {
1213 err = ihevce_encode(mCodecCtx, &s_encode_ip, &s_encode_op);
1214 if (IHEVCE_EOK != err) {
1215 ALOGE("Encode Frame failed : 0x%x", err);
1216 mSignalledError = true;
1217 work->result = C2_CORRUPTED;
1218 work->workletsProcessed = 1u;
1219 return;
1220 }
1221 } else if (!eos) {
1222 fillEmptyWork(work);
Roma Kauldfe650a2018-08-02 17:48:51 +05301223 }
1224
Roma Kauldfe650a2018-08-02 17:48:51 +05301225 /* Compute time taken for decode() */
Ray Essick24754942022-04-16 09:50:35 -07001226 mTimeEnd = systemTime();
1227 timeTaken = mTimeEnd - mTimeStart;
Roma Kauldfe650a2018-08-02 17:48:51 +05301228
Ray Essick24754942022-04-16 09:50:35 -07001229 ALOGV("timeTaken=%6" PRId64 " delay=%6" PRId64 " numBytes=%6d", timeTaken,
1230 timeDelay, s_encode_op.i4_bytes_generated);
Roma Kauldfe650a2018-08-02 17:48:51 +05301231
1232 if (s_encode_op.i4_bytes_generated) {
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301233 finishWork(s_encode_op.u8_pts, work, pool, &s_encode_op);
Roma Kauldfe650a2018-08-02 17:48:51 +05301234 }
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301235
Roma Kauldfe650a2018-08-02 17:48:51 +05301236 if (eos) {
Manisha Jajoo863bcfc2019-03-22 16:32:55 +05301237 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
Roma Kauldfe650a2018-08-02 17:48:51 +05301238 }
1239}
1240
1241class C2SoftHevcEncFactory : public C2ComponentFactory {
1242 public:
1243 C2SoftHevcEncFactory()
1244 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1245 GetCodec2PlatformComponentStore()->getParamReflector())) {}
1246
Ray Essick0d11a7e2019-03-02 20:10:30 -08001247 c2_status_t createComponent(
1248 c2_node_id_t id,
1249 std::shared_ptr<C2Component>* const component,
Roma Kauldfe650a2018-08-02 17:48:51 +05301250 std::function<void(C2Component*)> deleter) override {
1251 *component = std::shared_ptr<C2Component>(
1252 new C2SoftHevcEnc(
1253 COMPONENT_NAME, id,
1254 std::make_shared<C2SoftHevcEnc::IntfImpl>(mHelper)),
1255 deleter);
1256 return C2_OK;
1257 }
1258
Ray Essick0d11a7e2019-03-02 20:10:30 -08001259 c2_status_t createInterface(
1260 c2_node_id_t id,
1261 std::shared_ptr<C2ComponentInterface>* const interface,
Roma Kauldfe650a2018-08-02 17:48:51 +05301262 std::function<void(C2ComponentInterface*)> deleter) override {
1263 *interface = std::shared_ptr<C2ComponentInterface>(
1264 new SimpleInterface<C2SoftHevcEnc::IntfImpl>(
1265 COMPONENT_NAME, id,
1266 std::make_shared<C2SoftHevcEnc::IntfImpl>(mHelper)),
1267 deleter);
1268 return C2_OK;
1269 }
1270
Ray Essick0d11a7e2019-03-02 20:10:30 -08001271 ~C2SoftHevcEncFactory() override = default;
Roma Kauldfe650a2018-08-02 17:48:51 +05301272
1273 private:
1274 std::shared_ptr<C2ReflectorHelper> mHelper;
1275};
1276
1277} // namespace android
1278
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -08001279__attribute__((cfi_canonical_jump_table))
Roma Kauldfe650a2018-08-02 17:48:51 +05301280extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1281 ALOGV("in %s", __func__);
1282 return new ::android::C2SoftHevcEncFactory();
1283}
1284
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -08001285__attribute__((cfi_canonical_jump_table))
Roma Kauldfe650a2018-08-02 17:48:51 +05301286extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1287 ALOGV("in %s", __func__);
1288 delete factory;
1289}