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