1 /*
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 "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>
28 #include <Codec2Mapper.h>
29 #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
40 namespace android {
41
42 namespace {
43
44 constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
45
ParseGop(const C2StreamGopTuning::output & gop,uint32_t * syncInterval,uint32_t * iInterval,uint32_t * maxBframes)46 void 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 }
76 } // namepsace
77
78 class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
79 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)80 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();
90 noTimeStretch();
91 setDerivedInstance(this);
92
93 addParameter(
94 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(
103 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)})
108 .calculatedAs(InputDelaySetter, mGop)
109 .build());
110
111 addParameter(
112 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
113 .withConstValue(new C2ComponentAttributesSetting(
114 C2Component::ATTRIB_IS_TEMPORAL))
115 .build());
116
117 addParameter(
118 DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
119 .withConstValue(new C2StreamUsageTuning::input(
120 0u, (uint64_t)C2MemoryUsage::CPU_READ))
121 .build());
122
123 // matches size limits in codec library
124 addParameter(
125 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
126 .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
127 .withFields({
128 C2F(mSize, width).inRange(2, 1920, 2),
129 C2F(mSize, height).inRange(2, 1088, 2),
130 })
131 .withSetter(SizeSetter)
132 .build());
133
134 addParameter(
135 DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
136 .withDefault(new C2StreamFrameRateInfo::output(0u, 30.))
137 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
138 .withSetter(
139 Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
140 .build());
141
142 // matches limits in codec library
143 addParameter(
144 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(
158 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
159 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
160 .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
161 .withSetter(BitrateSetter)
162 .build());
163
164 // matches levels allowed within codec library
165 addParameter(
166 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(
180 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());
212
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());
248 }
249
InputDelaySetter(bool mayBlock,C2P<C2PortActualDelayTuning::input> & me,const C2P<C2StreamGopTuning::output> & gop)250 static C2R InputDelaySetter(
251 bool mayBlock,
252 C2P<C2PortActualDelayTuning::input> &me,
253 const C2P<C2StreamGopTuning::output> &gop) {
254 (void)mayBlock;
255 uint32_t maxBframes = 0;
256 ParseGop(gop.v, nullptr, nullptr, &maxBframes);
257 me.set().value = maxBframes + DEFAULT_RC_LOOKAHEAD;
258 return C2R::Ok();
259 }
260
BitrateSetter(bool mayBlock,C2P<C2StreamBitrateInfo::output> & me)261 static C2R BitrateSetter(bool mayBlock,
262 C2P<C2StreamBitrateInfo::output>& me) {
263 (void)mayBlock;
264 C2R res = C2R::Ok();
265 if (me.v.value < 4096) {
266 me.set().value = 4096;
267 }
268 return res;
269 }
270
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::input> & oldMe,C2P<C2StreamPictureSizeInfo::input> & me)271 static C2R SizeSetter(bool mayBlock,
272 const C2P<C2StreamPictureSizeInfo::input>& oldMe,
273 C2P<C2StreamPictureSizeInfo::input>& me) {
274 (void)mayBlock;
275 C2R res = C2R::Ok();
276 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
277 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
278 me.set().width = oldMe.v.width;
279 }
280 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
281 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
282 me.set().height = oldMe.v.height;
283 }
284 return res;
285 }
286
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::output> & me,const C2P<C2StreamPictureSizeInfo::input> & size,const C2P<C2StreamFrameRateInfo::output> & frameRate,const C2P<C2StreamBitrateInfo::output> & bitrate)287 static C2R ProfileLevelSetter(
288 bool mayBlock,
289 C2P<C2StreamProfileLevelInfo::output> &me,
290 const C2P<C2StreamPictureSizeInfo::input> &size,
291 const C2P<C2StreamFrameRateInfo::output> &frameRate,
292 const C2P<C2StreamBitrateInfo::output> &bitrate) {
293 (void)mayBlock;
294 if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
295 me.set().profile = PROFILE_HEVC_MAIN;
296 }
297
298 struct LevelLimits {
299 C2Config::level_t level;
300 uint64_t samplesPerSec;
301 uint64_t samples;
302 uint32_t bitrate;
303 };
304
305 constexpr LevelLimits kLimits[] = {
306 { LEVEL_HEVC_MAIN_1, 552960, 36864, 128000 },
307 { LEVEL_HEVC_MAIN_2, 3686400, 122880, 1500000 },
308 { LEVEL_HEVC_MAIN_2_1, 7372800, 245760, 3000000 },
309 { LEVEL_HEVC_MAIN_3, 16588800, 552960, 6000000 },
310 { LEVEL_HEVC_MAIN_3_1, 33177600, 983040, 10000000 },
311 { LEVEL_HEVC_MAIN_4, 66846720, 2228224, 12000000 },
312 { LEVEL_HEVC_MAIN_4_1, 133693440, 2228224, 20000000 },
313 { LEVEL_HEVC_MAIN_5, 267386880, 8912896, 25000000 },
314 { LEVEL_HEVC_MAIN_5_1, 534773760, 8912896, 40000000 },
315 { LEVEL_HEVC_MAIN_5_2, 1069547520, 8912896, 60000000 },
316 { LEVEL_HEVC_MAIN_6, 1069547520, 35651584, 60000000 },
317 { LEVEL_HEVC_MAIN_6_1, 2139095040, 35651584, 120000000 },
318 { LEVEL_HEVC_MAIN_6_2, 4278190080, 35651584, 240000000 },
319 };
320
321 uint64_t samples = size.v.width * size.v.height;
322 uint64_t samplesPerSec = samples * frameRate.v.value;
323
324 // Check if the supplied level meets the MB / bitrate requirements. If
325 // not, update the level with the lowest level meeting the requirements.
326
327 bool found = false;
328 // By default needsUpdate = false in case the supplied level does meet
329 // the requirements.
330 bool needsUpdate = false;
331 for (const LevelLimits &limit : kLimits) {
332 if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
333 bitrate.v.value <= limit.bitrate) {
334 // This is the lowest level that meets the requirements, and if
335 // we haven't seen the supplied level yet, that means we don't
336 // need the update.
337 if (needsUpdate) {
338 ALOGD("Given level %x does not cover current configuration: "
339 "adjusting to %x", me.v.level, limit.level);
340 me.set().level = limit.level;
341 }
342 found = true;
343 break;
344 }
345 if (me.v.level == limit.level) {
346 // We break out of the loop when the lowest feasible level is
347 // found. The fact that we're here means that our level doesn't
348 // meet the requirement and needs to be updated.
349 needsUpdate = true;
350 }
351 }
352 if (!found) {
353 // We set to the highest supported level.
354 me.set().level = LEVEL_HEVC_MAIN_5_2;
355 }
356 return C2R::Ok();
357 }
358
GopSetter(bool mayBlock,C2P<C2StreamGopTuning::output> & me)359 static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
360 (void)mayBlock;
361 for (size_t i = 0; i < me.v.flexCount(); ++i) {
362 const C2GopLayerStruct &layer = me.v.m.values[0];
363 if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
364 && layer.count > MAX_B_FRAMES) {
365 me.set().m.values[i].count = MAX_B_FRAMES;
366 }
367 }
368 return C2R::Ok();
369 }
370
getProfile_l() const371 UWORD32 getProfile_l() const {
372 switch (mProfileLevel->profile) {
373 case PROFILE_HEVC_MAIN: [[fallthrough]];
374 case PROFILE_HEVC_MAIN_STILL: return 1;
375 default:
376 ALOGD("Unrecognized profile: %x", mProfileLevel->profile);
377 return 1;
378 }
379 }
380
getLevel_l() const381 UWORD32 getLevel_l() const {
382 struct Level {
383 C2Config::level_t c2Level;
384 UWORD32 hevcLevel;
385 };
386 constexpr Level levels[] = {
387 { LEVEL_HEVC_MAIN_1, 30 },
388 { LEVEL_HEVC_MAIN_2, 60 },
389 { LEVEL_HEVC_MAIN_2_1, 63 },
390 { LEVEL_HEVC_MAIN_3, 90 },
391 { LEVEL_HEVC_MAIN_3_1, 93 },
392 { LEVEL_HEVC_MAIN_4, 120 },
393 { LEVEL_HEVC_MAIN_4_1, 123 },
394 { LEVEL_HEVC_MAIN_5, 150 },
395 { LEVEL_HEVC_MAIN_5_1, 153 },
396 { LEVEL_HEVC_MAIN_5_2, 156 },
397 { LEVEL_HEVC_MAIN_6, 180 },
398 { LEVEL_HEVC_MAIN_6_1, 183 },
399 { LEVEL_HEVC_MAIN_6_2, 186 },
400 };
401 for (const Level &level : levels) {
402 if (mProfileLevel->level == level.c2Level) {
403 return level.hevcLevel;
404 }
405 }
406 ALOGD("Unrecognized level: %x", mProfileLevel->level);
407 return 156;
408 }
getSyncFramePeriod_l() const409 uint32_t getSyncFramePeriod_l() const {
410 if (mSyncFramePeriod->value < 0 ||
411 mSyncFramePeriod->value == INT64_MAX) {
412 return 0;
413 }
414 double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
415 return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
416 }
417
getSize_l() const418 std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
419 return mSize;
420 }
getFrameRate_l() const421 std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
422 return mFrameRate;
423 }
getBitrateMode_l() const424 std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const {
425 return mBitrateMode;
426 }
getBitrate_l() const427 std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const {
428 return mBitrate;
429 }
getRequestSync_l() const430 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const {
431 return mRequestSync;
432 }
getComplexity_l() const433 std::shared_ptr<C2StreamComplexityTuning::output> getComplexity_l() const {
434 return mComplexity;
435 }
getQuality_l() const436 std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
437 return mQuality;
438 }
getGop_l() const439 std::shared_ptr<C2StreamGopTuning::output> getGop_l() const {
440 return mGop;
441 }
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)442 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
443 (void)mayBlock;
444 if (me.v.range > C2Color::RANGE_OTHER) {
445 me.set().range = C2Color::RANGE_OTHER;
446 }
447 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
448 me.set().primaries = C2Color::PRIMARIES_OTHER;
449 }
450 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
451 me.set().transfer = C2Color::TRANSFER_OTHER;
452 }
453 if (me.v.matrix > C2Color::MATRIX_OTHER) {
454 me.set().matrix = C2Color::MATRIX_OTHER;
455 }
456 return C2R::Ok();
457 }
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsInfo::input> & coded)458 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
459 const C2P<C2StreamColorAspectsInfo::input> &coded) {
460 (void)mayBlock;
461 me.set().range = coded.v.range;
462 me.set().primaries = coded.v.primaries;
463 me.set().transfer = coded.v.transfer;
464 me.set().matrix = coded.v.matrix;
465 return C2R::Ok();
466 }
getCodedColorAspects_l()467 std::shared_ptr<C2StreamColorAspectsInfo::output> getCodedColorAspects_l() {
468 return mCodedColorAspects;
469 }
470
471 private:
472 std::shared_ptr<C2StreamUsageTuning::input> mUsage;
473 std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
474 std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
475 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
476 std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
477 std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
478 std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
479 std::shared_ptr<C2StreamQualityTuning::output> mQuality;
480 std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
481 std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
482 std::shared_ptr<C2StreamGopTuning::output> mGop;
483 std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
484 std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
485 };
486
GetCPUCoreCount()487 static size_t GetCPUCoreCount() {
488 long cpuCoreCount = 0;
489
490 #if defined(_SC_NPROCESSORS_ONLN)
491 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
492 #else
493 // _SC_NPROC_ONLN must be defined...
494 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
495 #endif
496
497 if (cpuCoreCount < 1)
498 cpuCoreCount = 1;
499 return (size_t)cpuCoreCount;
500 }
501
C2SoftHevcEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)502 C2SoftHevcEnc::C2SoftHevcEnc(const char* name, c2_node_id_t id,
503 const std::shared_ptr<IntfImpl>& intfImpl)
504 : SimpleC2Component(
505 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
506 mIntf(intfImpl),
507 mIvVideoColorFormat(IV_YUV_420P),
508 mHevcEncProfile(1),
509 mHevcEncLevel(30),
510 mStarted(false),
511 mSpsPpsHeaderReceived(false),
512 mSignalledEos(false),
513 mSignalledError(false),
514 mCodecCtx(nullptr) {
515 // If dump is enabled, then create an empty file
516 GENERATE_FILE_NAMES();
517 CREATE_DUMP_FILE(mInFile);
518 CREATE_DUMP_FILE(mOutFile);
519
520 gettimeofday(&mTimeStart, nullptr);
521 gettimeofday(&mTimeEnd, nullptr);
522 }
523
~C2SoftHevcEnc()524 C2SoftHevcEnc::~C2SoftHevcEnc() {
525 onRelease();
526 }
527
onInit()528 c2_status_t C2SoftHevcEnc::onInit() {
529 return C2_OK;
530 }
531
onStop()532 c2_status_t C2SoftHevcEnc::onStop() {
533 return C2_OK;
534 }
535
onReset()536 void C2SoftHevcEnc::onReset() {
537 releaseEncoder();
538 }
539
onRelease()540 void C2SoftHevcEnc::onRelease() {
541 releaseEncoder();
542 }
543
onFlush_sm()544 c2_status_t C2SoftHevcEnc::onFlush_sm() {
545 return C2_OK;
546 }
547
fillEmptyWork(const std::unique_ptr<C2Work> & work)548 static void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
549 uint32_t flags = 0;
550 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
551 flags |= C2FrameData::FLAG_END_OF_STREAM;
552 ALOGV("Signalling EOS");
553 }
554 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
555 work->worklets.front()->output.buffers.clear();
556 work->worklets.front()->output.ordinal = work->input.ordinal;
557 work->workletsProcessed = 1u;
558 }
559
getQpFromQuality(int quality)560 static int getQpFromQuality(int quality) {
561 int qp;
562 #define MIN_QP 4
563 #define MAX_QP 50
564 /* Quality: 100 -> Qp : MIN_QP
565 * Quality: 0 -> Qp : MAX_QP
566 * Qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
567 */
568 qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
569 qp = std::min(qp, MAX_QP);
570 qp = std::max(qp, MIN_QP);
571 return qp;
572 }
initEncParams()573 c2_status_t C2SoftHevcEnc::initEncParams() {
574 mCodecCtx = nullptr;
575 mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
576 memset(&mEncParams, 0, sizeof(ihevce_static_cfg_params_t));
577
578 // default configuration
579 IHEVCE_PLUGIN_STATUS_T err = ihevce_set_def_params(&mEncParams);
580 if (IHEVCE_EOK != err) {
581 ALOGE("HEVC default init failed : 0x%x", err);
582 return C2_CORRUPTED;
583 }
584 mBframes = 0;
585 if (mGop && mGop->flexCount() > 0) {
586 uint32_t syncInterval = 1;
587 uint32_t iInterval = 1;
588 uint32_t maxBframes = 0;
589 ParseGop(*mGop, &syncInterval, &iInterval, &maxBframes);
590 if (syncInterval > 0) {
591 ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
592 mIDRInterval = syncInterval;
593 }
594 if (iInterval > 0) {
595 ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
596 mIInterval = iInterval;
597 }
598 if (mBframes != maxBframes) {
599 ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
600 mBframes = maxBframes;
601 }
602 }
603 ColorAspects sfAspects;
604 if (!C2Mapper::map(mColorAspects->primaries, &sfAspects.mPrimaries)) {
605 sfAspects.mPrimaries = android::ColorAspects::PrimariesUnspecified;
606 }
607 if (!C2Mapper::map(mColorAspects->range, &sfAspects.mRange)) {
608 sfAspects.mRange = android::ColorAspects::RangeUnspecified;
609 }
610 if (!C2Mapper::map(mColorAspects->matrix, &sfAspects.mMatrixCoeffs)) {
611 sfAspects.mMatrixCoeffs = android::ColorAspects::MatrixUnspecified;
612 }
613 if (!C2Mapper::map(mColorAspects->transfer, &sfAspects.mTransfer)) {
614 sfAspects.mTransfer = android::ColorAspects::TransferUnspecified;
615 }
616 int32_t primaries, transfer, matrixCoeffs;
617 bool range;
618 ColorUtils::convertCodecColorAspectsToIsoAspects(sfAspects,
619 &primaries,
620 &transfer,
621 &matrixCoeffs,
622 &range);
623 mEncParams.s_out_strm_prms.i4_vui_enable = 1;
624 mEncParams.s_vui_sei_prms.u1_colour_description_present_flag = 1;
625 mEncParams.s_vui_sei_prms.u1_colour_primaries = primaries;
626 mEncParams.s_vui_sei_prms.u1_transfer_characteristics = transfer;
627 mEncParams.s_vui_sei_prms.u1_matrix_coefficients = matrixCoeffs;
628 mEncParams.s_vui_sei_prms.u1_video_full_range_flag = range;
629 // update configuration
630 mEncParams.s_src_prms.i4_width = mSize->width;
631 mEncParams.s_src_prms.i4_height = mSize->height;
632 mEncParams.s_src_prms.i4_frm_rate_denom = 1000;
633 mEncParams.s_src_prms.i4_frm_rate_num =
634 mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
635 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
636 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
637 mBitrate->value;
638 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] =
639 mBitrate->value << 1;
640 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_codec_level = mHevcEncLevel;
641 mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = mIDRInterval;
642 mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIInterval;
643 mIvVideoColorFormat = IV_YUV_420P;
644 mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
645 mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
646 mEncParams.s_lap_prms.i4_rc_look_ahead_pics = DEFAULT_RC_LOOKAHEAD;
647 if (mBframes == 0) {
648 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 0;
649 } else if (mBframes <= 2) {
650 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 1;
651 } else if (mBframes <= 6) {
652 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 2;
653 } else {
654 mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
655 }
656
657 switch (mBitrateMode->value) {
658 case C2Config::BITRATE_IGNORE:
659 mEncParams.s_config_prms.i4_rate_control_mode = 3;
660 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
661 getQpFromQuality(mQuality->value);
662 break;
663 case C2Config::BITRATE_CONST:
664 mEncParams.s_config_prms.i4_rate_control_mode = 5;
665 break;
666 case C2Config::BITRATE_VARIABLE:
667 [[fallthrough]];
668 default:
669 mEncParams.s_config_prms.i4_rate_control_mode = 2;
670 break;
671 break;
672 }
673
674 if (mComplexity->value == 10) {
675 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P0;
676 } else if (mComplexity->value >= 8) {
677 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P2;
678 } else if (mComplexity->value >= 7) {
679 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P3;
680 } else if (mComplexity->value >= 5) {
681 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P4;
682 } else {
683 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
684 }
685
686 return C2_OK;
687 }
688
releaseEncoder()689 c2_status_t C2SoftHevcEnc::releaseEncoder() {
690 mSpsPpsHeaderReceived = false;
691 mSignalledEos = false;
692 mSignalledError = false;
693 mStarted = false;
694
695 if (mCodecCtx) {
696 IHEVCE_PLUGIN_STATUS_T err = ihevce_close(mCodecCtx);
697 if (IHEVCE_EOK != err) return C2_CORRUPTED;
698 mCodecCtx = nullptr;
699 }
700 return C2_OK;
701 }
702
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)703 c2_status_t C2SoftHevcEnc::drain(uint32_t drainMode,
704 const std::shared_ptr<C2BlockPool>& pool) {
705 return drainInternal(drainMode, pool, nullptr);
706 }
707
initEncoder()708 c2_status_t C2SoftHevcEnc::initEncoder() {
709 CHECK(!mCodecCtx);
710
711 {
712 IntfImpl::Lock lock = mIntf->lock();
713 mSize = mIntf->getSize_l();
714 mBitrateMode = mIntf->getBitrateMode_l();
715 mBitrate = mIntf->getBitrate_l();
716 mFrameRate = mIntf->getFrameRate_l();
717 mHevcEncProfile = mIntf->getProfile_l();
718 mHevcEncLevel = mIntf->getLevel_l();
719 mIDRInterval = mIntf->getSyncFramePeriod_l();
720 mIInterval = mIntf->getSyncFramePeriod_l();
721 mComplexity = mIntf->getComplexity_l();
722 mQuality = mIntf->getQuality_l();
723 mGop = mIntf->getGop_l();
724 mRequestSync = mIntf->getRequestSync_l();
725 mColorAspects = mIntf->getCodedColorAspects_l();
726 }
727
728 c2_status_t status = initEncParams();
729
730 if (C2_OK != status) {
731 ALOGE("Failed to initialize encoder params : 0x%x", status);
732 mSignalledError = true;
733 return status;
734 }
735
736 IHEVCE_PLUGIN_STATUS_T err = IHEVCE_EOK;
737 err = ihevce_init(&mEncParams, &mCodecCtx);
738 if (IHEVCE_EOK != err) {
739 ALOGE("HEVC encoder init failed : 0x%x", err);
740 return C2_CORRUPTED;
741 }
742
743 mStarted = true;
744 return C2_OK;
745 }
746
setEncodeArgs(ihevce_inp_buf_t * ps_encode_ip,const C2GraphicView * const input,uint64_t workIndex)747 c2_status_t C2SoftHevcEnc::setEncodeArgs(ihevce_inp_buf_t* ps_encode_ip,
748 const C2GraphicView* const input,
749 uint64_t workIndex) {
750 ihevce_static_cfg_params_t* params = &mEncParams;
751 memset(ps_encode_ip, 0, sizeof(*ps_encode_ip));
752
753 if (!input) {
754 return C2_OK;
755 }
756
757 if (input->width() < mSize->width ||
758 input->height() < mSize->height) {
759 /* Expect width height to be configured */
760 ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", input->width(),
761 mSize->width, input->height(), mSize->height);
762 return C2_BAD_VALUE;
763 }
764
765 const C2PlanarLayout& layout = input->layout();
766 uint8_t* yPlane =
767 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
768 uint8_t* uPlane =
769 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
770 uint8_t* vPlane =
771 const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_V]);
772 int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
773 int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
774 int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
775
776 const uint32_t width = mSize->width;
777 const uint32_t height = mSize->height;
778
779 // width and height must be even
780 if (width & 1u || height & 1u) {
781 ALOGW("height(%u) and width(%u) must both be even", height, width);
782 return C2_BAD_VALUE;
783 }
784
785 size_t yPlaneSize = width * height;
786
787 switch (layout.type) {
788 case C2PlanarLayout::TYPE_RGB:
789 [[fallthrough]];
790 case C2PlanarLayout::TYPE_RGBA: {
791 MemoryBlock conversionBuffer =
792 mConversionBuffers.fetch(yPlaneSize * 3 / 2);
793 mConversionBuffersInUse.emplace(conversionBuffer.data(),
794 conversionBuffer);
795 yPlane = conversionBuffer.data();
796 uPlane = yPlane + yPlaneSize;
797 vPlane = uPlane + yPlaneSize / 4;
798 yStride = width;
799 uStride = vStride = yStride / 2;
800 ConvertRGBToPlanarYUV(yPlane, yStride, height,
801 conversionBuffer.size(), *input);
802 break;
803 }
804 case C2PlanarLayout::TYPE_YUV: {
805 if (!IsYUV420(*input)) {
806 ALOGE("input is not YUV420");
807 return C2_BAD_VALUE;
808 }
809
810 if (layout.planes[layout.PLANE_Y].colInc == 1 &&
811 layout.planes[layout.PLANE_U].colInc == 1 &&
812 layout.planes[layout.PLANE_V].colInc == 1 &&
813 uStride == vStride && yStride == 2 * vStride) {
814 // I420 compatible - already set up above
815 break;
816 }
817
818 // copy to I420
819 yStride = width;
820 uStride = vStride = yStride / 2;
821 MemoryBlock conversionBuffer =
822 mConversionBuffers.fetch(yPlaneSize * 3 / 2);
823 mConversionBuffersInUse.emplace(conversionBuffer.data(),
824 conversionBuffer);
825 MediaImage2 img =
826 CreateYUV420PlanarMediaImage2(width, height, yStride, height);
827 status_t err = ImageCopy(conversionBuffer.data(), &img, *input);
828 if (err != OK) {
829 ALOGE("Buffer conversion failed: %d", err);
830 return C2_BAD_VALUE;
831 }
832 yPlane = conversionBuffer.data();
833 uPlane = yPlane + yPlaneSize;
834 vPlane = uPlane + yPlaneSize / 4;
835 break;
836 }
837
838 case C2PlanarLayout::TYPE_YUVA:
839 ALOGE("YUVA plane type is not supported");
840 return C2_BAD_VALUE;
841
842 default:
843 ALOGE("Unrecognized plane type: %d", layout.type);
844 return C2_BAD_VALUE;
845 }
846
847 switch (mIvVideoColorFormat) {
848 case IV_YUV_420P: {
849 // input buffer is supposed to be const but Ittiam API wants bare
850 // pointer.
851 ps_encode_ip->apv_inp_planes[0] = yPlane;
852 ps_encode_ip->apv_inp_planes[1] = uPlane;
853 ps_encode_ip->apv_inp_planes[2] = vPlane;
854
855 ps_encode_ip->ai4_inp_strd[0] = yStride;
856 ps_encode_ip->ai4_inp_strd[1] = uStride;
857 ps_encode_ip->ai4_inp_strd[2] = vStride;
858
859 ps_encode_ip->ai4_inp_size[0] = yStride * height;
860 ps_encode_ip->ai4_inp_size[1] = uStride * height >> 1;
861 ps_encode_ip->ai4_inp_size[2] = vStride * height >> 1;
862 break;
863 }
864
865 case IV_YUV_422ILE: {
866 // TODO
867 break;
868 }
869
870 case IV_YUV_420SP_UV:
871 case IV_YUV_420SP_VU:
872 default: {
873 ps_encode_ip->apv_inp_planes[0] = yPlane;
874 ps_encode_ip->apv_inp_planes[1] = uPlane;
875 ps_encode_ip->apv_inp_planes[2] = nullptr;
876
877 ps_encode_ip->ai4_inp_strd[0] = yStride;
878 ps_encode_ip->ai4_inp_strd[1] = uStride;
879 ps_encode_ip->ai4_inp_strd[2] = 0;
880
881 ps_encode_ip->ai4_inp_size[0] = yStride * height;
882 ps_encode_ip->ai4_inp_size[1] = uStride * height >> 1;
883 ps_encode_ip->ai4_inp_size[2] = 0;
884 break;
885 }
886 }
887
888 ps_encode_ip->i4_curr_bitrate =
889 params->s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0];
890 ps_encode_ip->i4_curr_peak_bitrate =
891 params->s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0];
892 ps_encode_ip->i4_curr_rate_factor = params->s_config_prms.i4_rate_factor;
893 ps_encode_ip->u8_pts = workIndex;
894 return C2_OK;
895 }
896
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool,ihevce_out_buf_t * ps_encode_op)897 void C2SoftHevcEnc::finishWork(uint64_t index,
898 const std::unique_ptr<C2Work>& work,
899 const std::shared_ptr<C2BlockPool>& pool,
900 ihevce_out_buf_t* ps_encode_op) {
901 std::shared_ptr<C2LinearBlock> block;
902 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
903 c2_status_t status =
904 pool->fetchLinearBlock(ps_encode_op->i4_bytes_generated, usage, &block);
905 if (C2_OK != status) {
906 ALOGE("fetchLinearBlock for Output failed with status 0x%x", status);
907 mSignalledError = true;
908 work->result = status;
909 work->workletsProcessed = 1u;
910 return;
911 }
912 C2WriteView wView = block->map().get();
913 if (C2_OK != wView.error()) {
914 ALOGE("write view map failed with status 0x%x", wView.error());
915 mSignalledError = true;
916 work->result = wView.error();
917 work->workletsProcessed = 1u;
918 return;
919 }
920 memcpy(wView.data(), ps_encode_op->pu1_output_buf,
921 ps_encode_op->i4_bytes_generated);
922
923 std::shared_ptr<C2Buffer> buffer =
924 createLinearBuffer(block, 0, ps_encode_op->i4_bytes_generated);
925
926 DUMP_TO_FILE(mOutFile, ps_encode_op->pu1_output_buf,
927 ps_encode_op->i4_bytes_generated);
928
929 if (ps_encode_op->i4_is_key_frame) {
930 ALOGV("IDR frame produced");
931 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
932 0u /* stream id */, C2Config::SYNC_FRAME));
933 }
934
935 auto fillWork = [buffer](const std::unique_ptr<C2Work>& work) {
936 work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
937 work->worklets.front()->output.buffers.clear();
938 work->worklets.front()->output.buffers.push_back(buffer);
939 work->worklets.front()->output.ordinal = work->input.ordinal;
940 work->workletsProcessed = 1u;
941 };
942 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
943 fillWork(work);
944 if (mSignalledEos) {
945 work->worklets.front()->output.flags =
946 C2FrameData::FLAG_END_OF_STREAM;
947 }
948 } else {
949 finish(index, fillWork);
950 }
951 }
952
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)953 c2_status_t C2SoftHevcEnc::drainInternal(
954 uint32_t drainMode,
955 const std::shared_ptr<C2BlockPool> &pool,
956 const std::unique_ptr<C2Work> &work) {
957
958 if (drainMode == NO_DRAIN) {
959 ALOGW("drain with NO_DRAIN: no-op");
960 return C2_OK;
961 }
962 if (drainMode == DRAIN_CHAIN) {
963 ALOGW("DRAIN_CHAIN not supported");
964 return C2_OMITTED;
965 }
966
967 while (true) {
968 ihevce_out_buf_t s_encode_op{};
969 memset(&s_encode_op, 0, sizeof(s_encode_op));
970
971 ihevce_encode(mCodecCtx, nullptr, &s_encode_op);
972 if (s_encode_op.i4_bytes_generated) {
973 finishWork(s_encode_op.u8_pts, work, pool, &s_encode_op);
974 } else {
975 if (work->workletsProcessed != 1u) fillEmptyWork(work);
976 break;
977 }
978 }
979 return C2_OK;
980 }
981
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)982 void C2SoftHevcEnc::process(const std::unique_ptr<C2Work>& work,
983 const std::shared_ptr<C2BlockPool>& pool) {
984 // Initialize output work
985 work->result = C2_OK;
986 work->workletsProcessed = 0u;
987 work->worklets.front()->output.flags = work->input.flags;
988
989 if (mSignalledError || mSignalledEos) {
990 work->result = C2_BAD_VALUE;
991 ALOGD("Signalled Error / Signalled Eos");
992 return;
993 }
994 c2_status_t status = C2_OK;
995
996 // Initialize encoder if not already initialized
997 if (!mStarted) {
998 status = initEncoder();
999 if (C2_OK != status) {
1000 ALOGE("Failed to initialize encoder : 0x%x", status);
1001 mSignalledError = true;
1002 work->result = status;
1003 work->workletsProcessed = 1u;
1004 return;
1005 }
1006 }
1007
1008 std::shared_ptr<const C2GraphicView> view;
1009 std::shared_ptr<C2Buffer> inputBuffer = nullptr;
1010 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
1011 if (eos) mSignalledEos = true;
1012
1013 if (!work->input.buffers.empty()) {
1014 inputBuffer = work->input.buffers[0];
1015 view = std::make_shared<const C2GraphicView>(
1016 inputBuffer->data().graphicBlocks().front().map().get());
1017 if (view->error() != C2_OK) {
1018 ALOGE("graphic view map err = %d", view->error());
1019 mSignalledError = true;
1020 work->result = C2_CORRUPTED;
1021 work->workletsProcessed = 1u;
1022 return;
1023 }
1024 }
1025 IHEVCE_PLUGIN_STATUS_T err = IHEVCE_EOK;
1026
1027 if (!mSpsPpsHeaderReceived) {
1028 ihevce_out_buf_t s_header_op{};
1029 err = ihevce_encode_header(mCodecCtx, &s_header_op);
1030 if (err == IHEVCE_EOK && s_header_op.i4_bytes_generated) {
1031 std::unique_ptr<C2StreamInitDataInfo::output> csd =
1032 C2StreamInitDataInfo::output::AllocUnique(
1033 s_header_op.i4_bytes_generated, 0u);
1034 if (!csd) {
1035 ALOGE("CSD allocation failed");
1036 mSignalledError = true;
1037 work->result = C2_NO_MEMORY;
1038 work->workletsProcessed = 1u;
1039 return;
1040 }
1041 memcpy(csd->m.value, s_header_op.pu1_output_buf,
1042 s_header_op.i4_bytes_generated);
1043 DUMP_TO_FILE(mOutFile, csd->m.value, csd->flexCount());
1044 work->worklets.front()->output.configUpdate.push_back(
1045 std::move(csd));
1046 mSpsPpsHeaderReceived = true;
1047 }
1048 if (!inputBuffer) {
1049 work->workletsProcessed = 1u;
1050 return;
1051 }
1052 }
1053
1054 // handle dynamic bitrate change
1055 {
1056 IntfImpl::Lock lock = mIntf->lock();
1057 std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
1058 lock.unlock();
1059
1060 if (bitrate != mBitrate) {
1061 mBitrate = bitrate;
1062 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
1063 mBitrate->value;
1064 mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] =
1065 mBitrate->value << 1;
1066 }
1067 }
1068
1069 ihevce_inp_buf_t s_encode_ip{};
1070 ihevce_out_buf_t s_encode_op{};
1071 uint64_t workIndex = work->input.ordinal.frameIndex.peekull();
1072
1073 status = setEncodeArgs(&s_encode_ip, view.get(), workIndex);
1074 if (C2_OK != status) {
1075 ALOGE("setEncodeArgs failed : 0x%x", status);
1076 mSignalledError = true;
1077 work->result = status;
1078 work->workletsProcessed = 1u;
1079 return;
1080 }
1081 // handle request key frame
1082 {
1083 IntfImpl::Lock lock = mIntf->lock();
1084 std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync;
1085 requestSync = mIntf->getRequestSync_l();
1086 lock.unlock();
1087 if (requestSync != mRequestSync) {
1088 // we can handle IDR immediately
1089 if (requestSync->value) {
1090 // unset request
1091 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
1092 std::vector<std::unique_ptr<C2SettingResult>> failures;
1093 mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
1094 ALOGV("Got sync request");
1095 //Force this as an IDR frame
1096 s_encode_ip.i4_force_idr_flag = 1;
1097 }
1098 mRequestSync = requestSync;
1099 }
1100 }
1101
1102 uint64_t timeDelay = 0;
1103 uint64_t timeTaken = 0;
1104 memset(&s_encode_op, 0, sizeof(s_encode_op));
1105 GETTIME(&mTimeStart, nullptr);
1106 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
1107
1108 if (inputBuffer) {
1109 err = ihevce_encode(mCodecCtx, &s_encode_ip, &s_encode_op);
1110 if (IHEVCE_EOK != err) {
1111 ALOGE("Encode Frame failed : 0x%x", err);
1112 mSignalledError = true;
1113 work->result = C2_CORRUPTED;
1114 work->workletsProcessed = 1u;
1115 return;
1116 }
1117 } else if (!eos) {
1118 fillEmptyWork(work);
1119 }
1120
1121 GETTIME(&mTimeEnd, nullptr);
1122 /* Compute time taken for decode() */
1123 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
1124
1125 ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", (int)timeTaken,
1126 (int)timeDelay, s_encode_op.i4_bytes_generated);
1127
1128 if (s_encode_op.i4_bytes_generated) {
1129 finishWork(s_encode_op.u8_pts, work, pool, &s_encode_op);
1130 }
1131
1132 if (eos) {
1133 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1134 }
1135 }
1136
1137 class C2SoftHevcEncFactory : public C2ComponentFactory {
1138 public:
C2SoftHevcEncFactory()1139 C2SoftHevcEncFactory()
1140 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1141 GetCodec2PlatformComponentStore()->getParamReflector())) {}
1142
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1143 c2_status_t createComponent(
1144 c2_node_id_t id,
1145 std::shared_ptr<C2Component>* const component,
1146 std::function<void(C2Component*)> deleter) override {
1147 *component = std::shared_ptr<C2Component>(
1148 new C2SoftHevcEnc(
1149 COMPONENT_NAME, id,
1150 std::make_shared<C2SoftHevcEnc::IntfImpl>(mHelper)),
1151 deleter);
1152 return C2_OK;
1153 }
1154
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1155 c2_status_t createInterface(
1156 c2_node_id_t id,
1157 std::shared_ptr<C2ComponentInterface>* const interface,
1158 std::function<void(C2ComponentInterface*)> deleter) override {
1159 *interface = std::shared_ptr<C2ComponentInterface>(
1160 new SimpleInterface<C2SoftHevcEnc::IntfImpl>(
1161 COMPONENT_NAME, id,
1162 std::make_shared<C2SoftHevcEnc::IntfImpl>(mHelper)),
1163 deleter);
1164 return C2_OK;
1165 }
1166
1167 ~C2SoftHevcEncFactory() override = default;
1168
1169 private:
1170 std::shared_ptr<C2ReflectorHelper> mHelper;
1171 };
1172
1173 } // namespace android
1174
1175 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()1176 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1177 ALOGV("in %s", __func__);
1178 return new ::android::C2SoftHevcEncFactory();
1179 }
1180
1181 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)1182 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1183 ALOGV("in %s", __func__);
1184 delete factory;
1185 }
1186