1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //#define LOG_NDEBUG 0
6 #define LOG_TAG "V4L2EncodeInterface"
7 
8 #include <v4l2_codec2/components/V4L2EncodeInterface.h>
9 
10 #include <inttypes.h>
11 #include <algorithm>
12 
13 #include <C2PlatformSupport.h>
14 #include <SimpleC2Interface.h>
15 #include <android/hardware/graphics/common/1.0/types.h>
16 #include <media/stagefright/MediaDefs.h>
17 #include <utils/Log.h>
18 
19 #include <v4l2_codec2/common/V4L2ComponentCommon.h>
20 #include <v4l2_codec2/common/V4L2Device.h>
21 #include <v4l2_codec2/common/VideoTypes.h>
22 
23 using android::hardware::graphics::common::V1_0::BufferUsage;
24 
25 namespace android {
26 
27 namespace {
28 
29 // Use basic linear block pool/allocator as default.
30 constexpr C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_LINEAR;
31 // Default input and output allocators.
32 constexpr C2Allocator::id_t kDefaultInputAllocator = C2PlatformAllocatorStore::GRALLOC;
33 constexpr C2Allocator::id_t kDefaultOutputAllocator = C2PlatformAllocatorStore::BLOB;
34 
35 // The default output framerate in frames per second.
36 // TODO: increase to 60 fps in the future.
37 constexpr float kDefaultFrameRate = 30.0;
38 // The default output bitrate in bits per second. Use the max bitrate of AVC Level1.0 as default.
39 constexpr uint32_t kDefaultBitrate = 64000;
40 
41 // The maximal output bitrate in bits per second. It's the max bitrate of AVC Level4.1.
42 // TODO: increase this in the future for supporting higher level/resolution encoding.
43 constexpr uint32_t kMaxBitrate = 50000000;
44 
getCodecFromComponentName(const std::string & name)45 std::optional<VideoCodec> getCodecFromComponentName(const std::string& name) {
46     if (name == V4L2ComponentName::kH264Encoder) return VideoCodec::H264;
47     if (name == V4L2ComponentName::kVP8Encoder) return VideoCodec::VP8;
48     if (name == V4L2ComponentName::kVP9Encoder) return VideoCodec::VP9;
49 
50     ALOGE("Unknown name: %s", name.c_str());
51     return std::nullopt;
52 }
53 
54 // Check whether the specified profile is a valid profile for the specified codec.
IsValidProfileForCodec(VideoCodec codec,C2Config::profile_t profile)55 bool IsValidProfileForCodec(VideoCodec codec, C2Config::profile_t profile) {
56     switch (codec) {
57     case VideoCodec::H264:
58         return ((profile >= C2Config::PROFILE_AVC_BASELINE) &&
59                 (profile <= C2Config::PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH));
60     case VideoCodec::VP8:
61         return ((profile >= C2Config::PROFILE_VP8_0) && (profile <= C2Config::PROFILE_VP8_3));
62     case VideoCodec::VP9:
63         return ((profile >= C2Config::PROFILE_VP9_0) && (profile <= C2Config::PROFILE_VP9_3));
64     default:
65         return false;
66     }
67 }
68 
69 }  // namespace
70 
71 // static
H264ProfileLevelSetter(bool,C2P<C2StreamProfileLevelInfo::output> & info,const C2P<C2StreamPictureSizeInfo::input> & videoSize,const C2P<C2StreamFrameRateInfo::output> & frameRate,const C2P<C2StreamBitrateInfo::output> & bitrate)72 C2R V4L2EncodeInterface::H264ProfileLevelSetter(
73         bool /*mayBlock*/, C2P<C2StreamProfileLevelInfo::output>& info,
74         const C2P<C2StreamPictureSizeInfo::input>& videoSize,
75         const C2P<C2StreamFrameRateInfo::output>& frameRate,
76         const C2P<C2StreamBitrateInfo::output>& bitrate) {
77     static C2Config::level_t lowestConfigLevel = C2Config::LEVEL_UNUSED;
78 
79     // Adopt default minimal profile instead if the requested profile is not supported, or lower
80     // than the default minimal one.
81     constexpr C2Config::profile_t minProfile = C2Config::PROFILE_AVC_BASELINE;
82     if (!info.F(info.v.profile).supportsAtAll(info.v.profile) || info.v.profile < minProfile) {
83         if (info.F(info.v.profile).supportsAtAll(minProfile)) {
84             ALOGV("Set profile to default (%u) instead.", minProfile);
85             info.set().profile = minProfile;
86         } else {
87             ALOGE("Unable to set either requested profile (%u) or default profile (%u).",
88                   info.v.profile, minProfile);
89             return C2R(C2SettingResultBuilder::BadValue(info.F(info.v.profile)));
90         }
91     }
92 
93     // Table A-1 in spec
94     struct LevelLimits {
95         C2Config::level_t level;
96         float maxMBPS;   // max macroblock processing rate in macroblocks per second
97         uint64_t maxFS;  // max frame size in macroblocks
98         uint32_t maxBR;  // max video bitrate in bits per second
99     };
100     constexpr LevelLimits kLimits[] = {
101             {C2Config::LEVEL_AVC_1, 1485, 99, 64000},
102             {C2Config::LEVEL_AVC_1B, 1485, 99, 128000},
103             {C2Config::LEVEL_AVC_1_1, 3000, 396, 192000},
104             {C2Config::LEVEL_AVC_1_2, 6000, 396, 384000},
105             {C2Config::LEVEL_AVC_1_3, 11880, 396, 768000},
106             {C2Config::LEVEL_AVC_2, 11880, 396, 2000000},
107             {C2Config::LEVEL_AVC_2_1, 19800, 792, 4000000},
108             {C2Config::LEVEL_AVC_2_2, 20250, 1620, 4000000},
109             {C2Config::LEVEL_AVC_3, 40500, 1620, 10000000},
110             {C2Config::LEVEL_AVC_3_1, 108000, 3600, 14000000},
111             {C2Config::LEVEL_AVC_3_2, 216000, 5120, 20000000},
112             {C2Config::LEVEL_AVC_4, 245760, 8192, 20000000},
113             {C2Config::LEVEL_AVC_4_1, 245760, 8192, 50000000},
114             {C2Config::LEVEL_AVC_4_2, 522240, 8704, 50000000},
115             {C2Config::LEVEL_AVC_5, 589824, 22080, 135000000},
116             {C2Config::LEVEL_AVC_5_1, 983040, 36864, 240000000},
117             {C2Config::LEVEL_AVC_5_2, 2073600, 36864, 240000000},
118     };
119 
120     uint64_t targetFS =
121             static_cast<uint64_t>((videoSize.v.width + 15) / 16) * ((videoSize.v.height + 15) / 16);
122     float targetMBPS = static_cast<float>(targetFS) * frameRate.v.value;
123 
124     // Try the recorded lowest configed level. This level should become adaptable after input size,
125     // frame rate, and bitrate are all set.
126     if (lowestConfigLevel != C2Config::LEVEL_UNUSED && lowestConfigLevel < info.v.level) {
127         info.set().level = lowestConfigLevel;
128     }
129 
130     // Check if the supplied level meets the requirements. If not, update the level with the lowest
131     // level meeting the requirements.
132 
133     bool found = false;
134     bool needsUpdate = !info.F(info.v.level).supportsAtAll(info.v.level);
135     for (const LevelLimits& limit : kLimits) {
136         if (!info.F(info.v.level).supportsAtAll(limit.level)) {
137             continue;
138         }
139 
140         // Table A-2 in spec
141         // The maximum bit rate for High Profile is 1.25 times that of the Base/Extended/Main
142         // Profiles, 3 times for Hi10P, and 4 times for Hi422P/Hi444PP.
143         uint32_t maxBR = limit.maxBR;
144         if (info.v.profile >= C2Config::PROFILE_AVC_HIGH_422) {
145             maxBR *= 4;
146         } else if (info.v.profile >= C2Config::PROFILE_AVC_HIGH_10) {
147             maxBR *= 3;
148         } else if (info.v.profile >= C2Config::PROFILE_AVC_HIGH) {
149             maxBR = maxBR * 5.0 / 4.0;
150         }
151 
152         if (targetFS <= limit.maxFS && targetMBPS <= limit.maxMBPS && bitrate.v.value <= maxBR) {
153             // This is the lowest level that meets the requirements, and if
154             // we haven't seen the supplied level yet, that means we don't
155             // need the update.
156             if (needsUpdate) {
157                 // Since current config update is sequential, there is an issue when we want to set
158                 // lower level for small input size, frame rate, and bitrate, if we set level first,
159                 // it will be adjusted to a higher one because the default input size or others are
160                 // above the limit. Use lowestConfigLevel to record the level we have tried to
161                 // config (but failed).
162                 // TODO(johnylin): remove this solution after b/140407694 has proper fix.
163                 lowestConfigLevel = info.v.level;
164 
165                 ALOGD("Given level %u does not cover current configuration: "
166                       "adjusting to %u",
167                       info.v.level, limit.level);
168                 info.set().level = limit.level;
169             }
170             found = true;
171             break;
172         }
173         if (info.v.level <= limit.level) {
174             // We break out of the loop when the lowest feasible level is found. The fact that we're
175             // here means that our level doesn't meet the requirement and needs to be updated.
176             needsUpdate = true;
177         }
178     }
179     if (!found) {
180         ALOGE("Unable to find proper level with current config, requested level (%u).",
181               info.v.level);
182         return C2R(C2SettingResultBuilder::BadValue(info.F(info.v.level)));
183     }
184 
185     return C2R::Ok();
186 }
187 
VP9ProfileLevelSetter(bool,C2P<C2StreamProfileLevelInfo::output> & info,const C2P<C2StreamPictureSizeInfo::input> &,const C2P<C2StreamFrameRateInfo::output> &,const C2P<C2StreamBitrateInfo::output> &)188 C2R V4L2EncodeInterface::VP9ProfileLevelSetter(
189         bool /*mayBlock*/, C2P<C2StreamProfileLevelInfo::output>& info,
190         const C2P<C2StreamPictureSizeInfo::input>& /*videoSize*/,
191         const C2P<C2StreamFrameRateInfo::output>& /*frameRate*/,
192         const C2P<C2StreamBitrateInfo::output>& /*bitrate*/) {
193     // Adopt default minimal profile instead if the requested profile is not supported, or lower
194     // than the default minimal one.
195     constexpr C2Config::profile_t defaultMinProfile = C2Config::PROFILE_VP9_0;
196     if (!info.F(info.v.profile).supportsAtAll(info.v.profile) ||
197         info.v.profile < defaultMinProfile) {
198         if (info.F(info.v.profile).supportsAtAll(defaultMinProfile)) {
199             ALOGV("Set profile to default (%u) instead.", defaultMinProfile);
200             info.set().profile = defaultMinProfile;
201         } else {
202             ALOGE("Unable to set either requested profile (%u) or default profile (%u).",
203                   info.v.profile, defaultMinProfile);
204             return C2R(C2SettingResultBuilder::BadValue(info.F(info.v.profile)));
205         }
206     }
207 
208     return C2R::Ok();
209 }
210 
211 // static
SizeSetter(bool mayBlock,C2P<C2StreamPictureSizeInfo::input> & videoSize)212 C2R V4L2EncodeInterface::SizeSetter(bool mayBlock, C2P<C2StreamPictureSizeInfo::input>& videoSize) {
213     (void)mayBlock;
214     // TODO: maybe apply block limit?
215     return videoSize.F(videoSize.v.width)
216             .validatePossible(videoSize.v.width)
217             .plus(videoSize.F(videoSize.v.height).validatePossible(videoSize.v.height));
218 }
219 
220 // static
IntraRefreshPeriodSetter(bool mayBlock,C2P<C2StreamIntraRefreshTuning::output> & period)221 C2R V4L2EncodeInterface::IntraRefreshPeriodSetter(bool mayBlock,
222                                                   C2P<C2StreamIntraRefreshTuning::output>& period) {
223     (void)mayBlock;
224     if (period.v.period < 1) {
225         period.set().mode = C2Config::INTRA_REFRESH_DISABLED;
226         period.set().period = 0;
227     } else {
228         // Only support arbitrary mode (cyclic in our case).
229         period.set().mode = C2Config::INTRA_REFRESH_ARBITRARY;
230     }
231     return C2R::Ok();
232 }
233 
V4L2EncodeInterface(const C2String & name,std::shared_ptr<C2ReflectorHelper> helper)234 V4L2EncodeInterface::V4L2EncodeInterface(const C2String& name,
235                                          std::shared_ptr<C2ReflectorHelper> helper)
236       : C2InterfaceHelper(std::move(helper)) {
237     ALOGV("%s(%s)", __func__, name.c_str());
238 
239     setDerivedInstance(this);
240 
241     Initialize(name);
242 }
243 
Initialize(const C2String & name)244 void V4L2EncodeInterface::Initialize(const C2String& name) {
245     scoped_refptr<V4L2Device> device = V4L2Device::create();
246     if (!device) {
247         ALOGE("Failed to create V4L2 device");
248         mInitStatus = C2_CORRUPTED;
249         return;
250     }
251 
252     auto codec = getCodecFromComponentName(name);
253     if (!codec) {
254         ALOGE("Invalid component name");
255         mInitStatus = C2_BAD_VALUE;
256         return;
257     }
258 
259     V4L2Device::SupportedEncodeProfiles supported_profiles = device->getSupportedEncodeProfiles();
260 
261     // Compile the list of supported profiles.
262     // Note: unsigned int is used here, since std::vector<C2Config::profile_t> cannot convert to
263     // std::vector<unsigned int> required by the c2 framework below.
264     std::vector<unsigned int> profiles;
265     ui::Size maxSize;
266     for (const auto& supportedProfile : supported_profiles) {
267         if (!IsValidProfileForCodec(codec.value(), supportedProfile.profile)) {
268             continue;  // Ignore unrecognizable or unsupported profiles.
269         }
270         ALOGV("Queried c2_profile = 0x%x : max_size = %d x %d", supportedProfile.profile,
271               supportedProfile.max_resolution.width, supportedProfile.max_resolution.height);
272         profiles.push_back(static_cast<unsigned int>(supportedProfile.profile));
273         maxSize.setWidth(std::max(maxSize.width, supportedProfile.max_resolution.width));
274         maxSize.setHeight(std::max(maxSize.height, supportedProfile.max_resolution.height));
275     }
276 
277     if (profiles.empty()) {
278         ALOGE("No supported profiles");
279         mInitStatus = C2_BAD_VALUE;
280         return;
281     }
282 
283     // Special note: the order of addParameter matters if your setters are dependent on other
284     //               parameters. Please make sure the dependent parameters are added prior to the
285     //               one needs the setter dependency.
286 
287     addParameter(DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
288                          .withConstValue(new C2ComponentKindSetting(C2Component::KIND_ENCODER))
289                          .build());
290 
291     addParameter(DefineParam(mInputVisibleSize, C2_PARAMKEY_PICTURE_SIZE)
292                          .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
293                          .withFields({
294                                  C2F(mInputVisibleSize, width).inRange(2, maxSize.width, 2),
295                                  C2F(mInputVisibleSize, height).inRange(2, maxSize.height, 2),
296                          })
297                          .withSetter(SizeSetter)
298                          .build());
299 
300     addParameter(DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
301                          .withDefault(new C2StreamFrameRateInfo::output(0u, kDefaultFrameRate))
302                          // TODO: More restriction?
303                          .withFields({C2F(mFrameRate, value).greaterThan(0.)})
304                          .withSetter(Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
305                          .build());
306 
307     addParameter(DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
308                          .withDefault(new C2StreamBitrateInfo::output(0u, kDefaultBitrate))
309                          .withFields({C2F(mBitrate, value).inRange(0, kMaxBitrate)})
310                          .withSetter(Setter<decltype(*mBitrate)>::StrictValueWithNoDeps)
311                          .build());
312 
313     std::string outputMime;
314     if (getCodecFromComponentName(name) == VideoCodec::H264) {
315         outputMime = MEDIA_MIMETYPE_VIDEO_AVC;
316         C2Config::profile_t minProfile = static_cast<C2Config::profile_t>(
317                 *std::min_element(profiles.begin(), profiles.end()));
318         addParameter(
319                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
320                         .withDefault(new C2StreamProfileLevelInfo::output(0u, minProfile,
321                                                                           C2Config::LEVEL_AVC_4_1))
322                         .withFields(
323                                 {C2F(mProfileLevel, profile).oneOf(profiles),
324                                  C2F(mProfileLevel, level)
325                                          // TODO: query supported levels from adaptor.
326                                          .oneOf({C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B,
327                                                  C2Config::LEVEL_AVC_1_1, C2Config::LEVEL_AVC_1_2,
328                                                  C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2,
329                                                  C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2,
330                                                  C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1,
331                                                  C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4,
332                                                  C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_5,
333                                                  C2Config::LEVEL_AVC_5_1})})
334                         .withSetter(H264ProfileLevelSetter, mInputVisibleSize, mFrameRate, mBitrate)
335                         .build());
336     } else if (getCodecFromComponentName(name) == VideoCodec::VP8) {
337         outputMime = MEDIA_MIMETYPE_VIDEO_VP8;
338         // VP8 doesn't have conventional profiles, we'll use profile0 if the VP8 codec is requested.
339         addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
340                              .withConstValue(new C2StreamProfileLevelInfo::output(
341                                      0u, C2Config::PROFILE_VP8_0, C2Config::LEVEL_UNUSED))
342                              .build());
343     } else if (getCodecFromComponentName(name) == VideoCodec::VP9) {
344         outputMime = MEDIA_MIMETYPE_VIDEO_VP9;
345         C2Config::profile_t minProfile = static_cast<C2Config::profile_t>(
346                 *std::min_element(profiles.begin(), profiles.end()));
347         addParameter(
348                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
349                         .withDefault(new C2StreamProfileLevelInfo::output(0u, minProfile,
350                                                                           C2Config::LEVEL_VP9_1))
351                         .withFields(
352                                 {C2F(mProfileLevel, profile).oneOf(profiles),
353                                  C2F(mProfileLevel, level)
354                                          // TODO(dstaessens) query supported levels from adaptor.
355                                          .oneOf({C2Config::LEVEL_VP9_1, C2Config::LEVEL_VP9_1_1,
356                                                  C2Config::LEVEL_VP9_2, C2Config::LEVEL_VP9_2_1,
357                                                  C2Config::LEVEL_VP9_3, C2Config::LEVEL_VP9_3_1,
358                                                  C2Config::LEVEL_VP9_4, C2Config::LEVEL_VP9_4_1,
359                                                  C2Config::LEVEL_VP9_5, C2Config::LEVEL_VP9_5_1,
360                                                  C2Config::LEVEL_VP9_5_2, C2Config::LEVEL_VP9_6,
361                                                  C2Config::LEVEL_VP9_6_1,
362                                                  C2Config::LEVEL_VP9_6_2})})
363                         .withSetter(VP9ProfileLevelSetter, mInputVisibleSize, mFrameRate, mBitrate)
364                         .build());
365     } else {
366         ALOGE("Unsupported component name: %s", name.c_str());
367         mInitStatus = C2_BAD_VALUE;
368         return;
369     }
370 
371     addParameter(
372             DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE)
373                     .withConstValue(new C2StreamBufferTypeSetting::input(0u, C2BufferData::GRAPHIC))
374                     .build());
375 
376     // TODO(b/167640667) Add VIDEO_ENCODER flag once input convertor is not enabled by default.
377     // When using the format convertor (which is currently always enabled) it's not useful to add
378     // the VIDEO_ENCODER buffer flag for input buffers here. Currently zero-copy is not supported
379     // yet, so when using this flag an additional buffer will be allocated on host side and a copy
380     // will be performed between the guest and host buffer to keep them in sync. This is wasteful as
381     // the buffer is only used on guest side by the format convertor which converts and copies the
382     // buffer into another buffer.
383     //addParameter(DefineParam(mInputMemoryUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
384     //                     .withConstValue(new C2StreamUsageTuning::input(
385     //                             0u, static_cast<uint64_t>(BufferUsage::VIDEO_ENCODER)))
386     //                     .build());
387 
388     addParameter(
389             DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE)
390                     .withConstValue(new C2StreamBufferTypeSetting::output(0u, C2BufferData::LINEAR))
391                     .build());
392 
393     addParameter(DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
394                          .withConstValue(AllocSharedString<C2PortMediaTypeSetting::input>(
395                                  MEDIA_MIMETYPE_VIDEO_RAW))
396                          .build());
397 
398     addParameter(DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
399                          .withConstValue(AllocSharedString<C2PortMediaTypeSetting::output>(
400                                  outputMime.c_str()))
401                          .build());
402 
403     addParameter(DefineParam(mIntraRefreshPeriod, C2_PARAMKEY_INTRA_REFRESH)
404                          .withDefault(new C2StreamIntraRefreshTuning::output(
405                                  0u, C2Config::INTRA_REFRESH_DISABLED, 0.))
406                          .withFields({C2F(mIntraRefreshPeriod, mode)
407                                               .oneOf({C2Config::INTRA_REFRESH_DISABLED,
408                                                       C2Config::INTRA_REFRESH_ARBITRARY}),
409                                       C2F(mIntraRefreshPeriod, period).any()})
410                          .withSetter(IntraRefreshPeriodSetter)
411                          .build());
412 
413     addParameter(DefineParam(mRequestKeyFrame, C2_PARAMKEY_REQUEST_SYNC_FRAME)
414                          .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
415                          .withFields({C2F(mRequestKeyFrame, value).oneOf({C2_FALSE, C2_TRUE})})
416                          .withSetter(Setter<decltype(*mRequestKeyFrame)>::NonStrictValueWithNoDeps)
417                          .build());
418 
419     addParameter(DefineParam(mKeyFramePeriodUs, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
420                          .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
421                          .withFields({C2F(mKeyFramePeriodUs, value).any()})
422                          .withSetter(Setter<decltype(*mKeyFramePeriodUs)>::StrictValueWithNoDeps)
423                          .build());
424 
425     C2Allocator::id_t inputAllocators[] = {kDefaultInputAllocator};
426 
427     C2Allocator::id_t outputAllocators[] = {kDefaultOutputAllocator};
428 
429     addParameter(
430             DefineParam(mInputAllocatorIds, C2_PARAMKEY_INPUT_ALLOCATORS)
431                     .withConstValue(C2PortAllocatorsTuning::input::AllocShared(inputAllocators))
432                     .build());
433 
434     addParameter(
435             DefineParam(mOutputAllocatorIds, C2_PARAMKEY_OUTPUT_ALLOCATORS)
436                     .withConstValue(C2PortAllocatorsTuning::output::AllocShared(outputAllocators))
437                     .build());
438 
439     C2BlockPool::local_id_t outputBlockPools[] = {kDefaultOutputBlockPool};
440 
441     addParameter(
442             DefineParam(mOutputBlockPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS)
443                     .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputBlockPools))
444                     .withFields({C2F(mOutputBlockPoolIds, m.values[0]).any(),
445                                  C2F(mOutputBlockPoolIds, m.values).inRange(0, 1)})
446                     .withSetter(Setter<C2PortBlockPoolsTuning::output>::NonStrictValuesWithNoDeps)
447                     .build());
448 
449     mInitStatus = C2_OK;
450 }
451 
getKeyFramePeriod() const452 uint32_t V4L2EncodeInterface::getKeyFramePeriod() const {
453     if (mKeyFramePeriodUs->value < 0 || mKeyFramePeriodUs->value == INT64_MAX) {
454         return 0;
455     }
456     double period = mKeyFramePeriodUs->value / 1e6 * mFrameRate->value;
457     return static_cast<uint32_t>(std::max(std::min(std::round(period), double(UINT32_MAX)), 1.));
458 }
459 
460 }  // namespace android
461