• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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