• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 "C2SoftVpxEnc"
19 #include <log/log.h>
20 #include <utils/misc.h>
21 
22 #include <media/hardware/VideoAPI.h>
23 
24 #include <Codec2BufferUtils.h>
25 #include <C2Debug.h>
26 #include "C2SoftVpxEnc.h"
27 
28 #ifndef INT32_MAX
29 #define INT32_MAX   2147483647
30 #endif
31 
32 namespace android {
33 
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)34 C2SoftVpxEnc::IntfImpl::IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
35     : SimpleInterface<void>::BaseParams(
36             helper,
37             COMPONENT_NAME,
38             C2Component::KIND_ENCODER,
39             C2Component::DOMAIN_VIDEO,
40             MEDIA_MIMETYPE_VIDEO) {
41     noPrivateBuffers(); // TODO: account for our buffers here
42     noInputReferences();
43     noOutputReferences();
44     noInputLatency();
45     noTimeStretch();
46     setDerivedInstance(this);
47 
48     addParameter(
49             DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
50             .withConstValue(new C2ComponentAttributesSetting(
51                 C2Component::ATTRIB_IS_TEMPORAL))
52             .build());
53 
54     addParameter(
55             DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
56             .withConstValue(new C2StreamUsageTuning::input(
57                     0u, (uint64_t)C2MemoryUsage::CPU_READ))
58             .build());
59 
60     addParameter(
61         DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
62             .withDefault(new C2StreamPictureSizeInfo::input(0u, 64, 64))
63             .withFields({
64                 C2F(mSize, width).inRange(2, 2048, 2),
65                 C2F(mSize, height).inRange(2, 2048, 2),
66             })
67             .withSetter(SizeSetter)
68             .build());
69 
70     addParameter(
71         DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
72             .withDefault(new C2StreamBitrateModeTuning::output(
73                     0u, C2Config::BITRATE_VARIABLE))
74             .withFields({
75                 C2F(mBitrateMode, value).oneOf({
76                     C2Config::BITRATE_CONST, C2Config::BITRATE_VARIABLE })
77             })
78             .withSetter(
79                 Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
80             .build());
81 
82     addParameter(
83         DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
84             .withDefault(new C2StreamFrameRateInfo::output(0u, 1.))
85             // TODO: More restriction?
86             .withFields({C2F(mFrameRate, value).greaterThan(0.)})
87             .withSetter(
88                 Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
89             .build());
90 
91     addParameter(
92         DefineParam(mLayering, C2_PARAMKEY_TEMPORAL_LAYERING)
93             .withDefault(C2StreamTemporalLayeringTuning::output::AllocShared(0u, 0, 0, 0))
94             .withFields({
95                 C2F(mLayering, m.layerCount).inRange(0, 4),
96                 C2F(mLayering, m.bLayerCount).inRange(0, 0),
97                 C2F(mLayering, m.bitrateRatios).inRange(0., 1.)
98             })
99             .withSetter(LayeringSetter)
100             .build());
101 
102     addParameter(
103             DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
104             .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
105             .withFields({C2F(mSyncFramePeriod, value).any()})
106             .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
107             .build());
108 
109     addParameter(
110         DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
111             .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
112             .withFields({C2F(mBitrate, value).inRange(4096, 40000000)})
113             .withSetter(BitrateSetter)
114             .build());
115 
116     addParameter(
117             DefineParam(mIntraRefresh, C2_PARAMKEY_INTRA_REFRESH)
118             .withConstValue(new C2StreamIntraRefreshTuning::output(
119                             0u, C2Config::INTRA_REFRESH_DISABLED, 0.))
120             .build());
121 #ifdef VP9
122     addParameter(
123             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
124             .withDefault(new C2StreamProfileLevelInfo::output(
125                     0u, PROFILE_VP9_0, LEVEL_VP9_4_1))
126             .withFields({
127                 C2F(mProfileLevel, profile).equalTo(
128                     PROFILE_VP9_0
129                 ),
130                 C2F(mProfileLevel, level).oneOf({
131                         C2Config::LEVEL_VP9_1,
132                         C2Config::LEVEL_VP9_1_1,
133                         C2Config::LEVEL_VP9_2,
134                         C2Config::LEVEL_VP9_2_1,
135                         C2Config::LEVEL_VP9_3,
136                         C2Config::LEVEL_VP9_3_1,
137                         C2Config::LEVEL_VP9_4,
138                         C2Config::LEVEL_VP9_4_1,
139                 }),
140             })
141             .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
142             .build());
143 #else
144     addParameter(
145             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
146             .withDefault(new C2StreamProfileLevelInfo::output(
147                     0u, PROFILE_VP8_0, LEVEL_UNUSED))
148             .withFields({
149                 C2F(mProfileLevel, profile).equalTo(
150                     PROFILE_VP8_0
151                 ),
152                 C2F(mProfileLevel, level).equalTo(
153                     LEVEL_UNUSED),
154             })
155             .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
156             .build());
157 #endif
158     addParameter(
159             DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
160             .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
161             .withFields({C2F(mRequestSync, value).oneOf({ C2_FALSE, C2_TRUE }) })
162             .withSetter(Setter<decltype(*mRequestSync)>::NonStrictValueWithNoDeps)
163             .build());
164 
165     addParameter(
166             DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
167             .withDefault(new C2StreamColorAspectsInfo::input(
168                     0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
169                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
170             .withFields({
171                 C2F(mColorAspects, range).inRange(
172                             C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
173                 C2F(mColorAspects, primaries).inRange(
174                             C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
175                 C2F(mColorAspects, transfer).inRange(
176                             C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
177                 C2F(mColorAspects, matrix).inRange(
178                             C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
179             })
180             .withSetter(ColorAspectsSetter)
181             .build());
182 
183     addParameter(
184             DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
185             .withDefault(new C2StreamColorAspectsInfo::output(
186                     0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
187                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
188             .withFields({
189                 C2F(mCodedColorAspects, range).inRange(
190                             C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
191                 C2F(mCodedColorAspects, primaries).inRange(
192                             C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
193                 C2F(mCodedColorAspects, transfer).inRange(
194                             C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
195                 C2F(mCodedColorAspects, matrix).inRange(
196                             C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
197             })
198             .withSetter(CodedColorAspectsSetter, mColorAspects)
199             .build());
200 }
201 
BitrateSetter(bool mayBlock,C2P<C2StreamBitrateInfo::output> & me)202 C2R C2SoftVpxEnc::IntfImpl::BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
203     (void)mayBlock;
204     C2R res = C2R::Ok();
205     if (me.v.value < 4096) {
206         me.set().value = 4096;
207     }
208     return res;
209 }
210 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::input> & oldMe,C2P<C2StreamPictureSizeInfo::input> & me)211 C2R C2SoftVpxEnc::IntfImpl::SizeSetter(bool mayBlock,
212                                        const C2P<C2StreamPictureSizeInfo::input>& oldMe,
213                                        C2P<C2StreamPictureSizeInfo::input>& me) {
214     (void)mayBlock;
215     C2R res = C2R::Ok();
216     if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
217         res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
218         me.set().width = oldMe.v.width;
219     }
220     if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
221         res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
222         me.set().height = oldMe.v.height;
223     }
224     return res;
225 }
226 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::output> & me,const C2P<C2StreamPictureSizeInfo::input> & size,const C2P<C2StreamFrameRateInfo::output> & frameRate,const C2P<C2StreamBitrateInfo::output> & bitrate)227 C2R C2SoftVpxEnc::IntfImpl::ProfileLevelSetter(bool mayBlock,
228                                                C2P<C2StreamProfileLevelInfo::output>& me,
229                                                const C2P<C2StreamPictureSizeInfo::input>& size,
230                                                const C2P<C2StreamFrameRateInfo::output>& frameRate,
231                                                const C2P<C2StreamBitrateInfo::output>& bitrate) {
232     (void)mayBlock;
233 #ifdef VP9
234     if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
235         me.set().profile = PROFILE_VP9_0;
236     }
237     struct LevelLimits {
238         C2Config::level_t level;
239         float samplesPerSec;
240         uint64_t samples;
241         uint32_t bitrate;
242         size_t dimension;
243     };
244     constexpr LevelLimits kLimits[] = {
245             {LEVEL_VP9_1, 829440, 36864, 200000, 512},
246             {LEVEL_VP9_1_1, 2764800, 73728, 800000, 768},
247             {LEVEL_VP9_2, 4608000, 122880, 1800000, 960},
248             {LEVEL_VP9_2_1, 9216000, 245760, 3600000, 1344},
249             {LEVEL_VP9_3, 20736000, 552960, 7200000, 2048},
250             {LEVEL_VP9_3_1, 36864000, 983040, 12000000, 2752},
251             {LEVEL_VP9_4, 83558400, 2228224, 18000000, 4160},
252             {LEVEL_VP9_4_1, 160432128, 2228224, 30000000, 4160},
253     };
254 
255     uint64_t samples = size.v.width * size.v.height;
256     float samplesPerSec = float(samples) * frameRate.v.value;
257     size_t dimension = std::max(size.v.width, size.v.height);
258 
259     // Check if the supplied level meets the samples / bitrate requirements.
260     // If not, update the level with the lowest level meeting the requirements.
261     bool found = false;
262 
263     // By default needsUpdate = false in case the supplied level does meet
264     // the requirements.
265     bool needsUpdate = false;
266     if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
267         needsUpdate = true;
268     }
269     for (const LevelLimits& limit : kLimits) {
270         if (samples <= limit.samples && samplesPerSec <= limit.samplesPerSec &&
271             bitrate.v.value <= limit.bitrate && dimension <= limit.dimension) {
272             // This is the lowest level that meets the requirements, and if
273             // we haven't seen the supplied level yet, that means we don't
274             // need the update.
275             if (needsUpdate) {
276                 ALOGD("Given level %x does not cover current configuration: "
277                         "adjusting to %x",
278                         me.v.level, limit.level);
279                 me.set().level = limit.level;
280             }
281             found = true;
282             break;
283         }
284         if (me.v.level == limit.level) {
285             // We break out of the loop when the lowest feasible level is
286             // found. The fact that we're here means that our level doesn't
287             // meet the requirement and needs to be updated.
288             needsUpdate = true;
289         }
290     }
291     if (!found) {
292         // We set to the highest supported level.
293         me.set().level = LEVEL_VP9_4_1;
294     }
295 #else
296     (void)size;
297     (void)frameRate;
298     (void)bitrate;
299     if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
300         me.set().profile = PROFILE_VP8_0;
301     }
302     if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
303         me.set().level = LEVEL_UNUSED;
304     }
305 #endif
306     return C2R::Ok();
307 }
308 
LayeringSetter(bool mayBlock,C2P<C2StreamTemporalLayeringTuning::output> & me)309 C2R C2SoftVpxEnc::IntfImpl::LayeringSetter(bool mayBlock,
310                                            C2P<C2StreamTemporalLayeringTuning::output>& me) {
311     (void)mayBlock;
312     C2R res = C2R::Ok();
313     if (me.v.m.layerCount > 4) {
314         me.set().m.layerCount = 4;
315     }
316     me.set().m.bLayerCount = 0;
317     // ensure ratios are monotonic and clamped between 0 and 1
318     for (size_t ix = 0; ix < me.v.flexCount(); ++ix) {
319         me.set().m.bitrateRatios[ix] = c2_clamp(
320             ix > 0 ? me.v.m.bitrateRatios[ix - 1] : 0, me.v.m.bitrateRatios[ix], 1.);
321     }
322     ALOGI("setting temporal layering %u + %u", me.v.m.layerCount, me.v.m.bLayerCount);
323     return res;
324 }
325 
getSyncFramePeriod() const326 uint32_t C2SoftVpxEnc::IntfImpl::getSyncFramePeriod() const {
327     if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
328         return 0;
329     }
330     double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
331     return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
332 }
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)333 C2R C2SoftVpxEnc::IntfImpl::ColorAspectsSetter(bool mayBlock,
334                                                C2P<C2StreamColorAspectsInfo::input>& me) {
335     (void)mayBlock;
336     if (me.v.range > C2Color::RANGE_OTHER) {
337             me.set().range = C2Color::RANGE_OTHER;
338     }
339     if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
340             me.set().primaries = C2Color::PRIMARIES_OTHER;
341     }
342     if (me.v.transfer > C2Color::TRANSFER_OTHER) {
343             me.set().transfer = C2Color::TRANSFER_OTHER;
344     }
345     if (me.v.matrix > C2Color::MATRIX_OTHER) {
346             me.set().matrix = C2Color::MATRIX_OTHER;
347     }
348     return C2R::Ok();
349 }
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsInfo::input> & coded)350 C2R C2SoftVpxEnc::IntfImpl::CodedColorAspectsSetter(
351         bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
352         const C2P<C2StreamColorAspectsInfo::input>& coded) {
353     (void)mayBlock;
354     me.set().range = coded.v.range;
355     me.set().primaries = coded.v.primaries;
356     me.set().transfer = coded.v.transfer;
357     me.set().matrix = coded.v.matrix;
358     return C2R::Ok();
359 }
360 
361 #if 0
362 static size_t getCpuCoreCount() {
363     long cpuCoreCount = 1;
364 #if defined(_SC_NPROCESSORS_ONLN)
365     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
366 #else
367     // _SC_NPROC_ONLN must be defined...
368     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
369 #endif
370     CHECK(cpuCoreCount >= 1);
371     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
372     return (size_t)cpuCoreCount;
373 }
374 #endif
375 
C2SoftVpxEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)376 C2SoftVpxEnc::C2SoftVpxEnc(const char* name, c2_node_id_t id,
377                            const std::shared_ptr<IntfImpl>& intfImpl)
378     : SimpleC2Component(
379           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
380       mIntf(intfImpl),
381       mCodecContext(nullptr),
382       mCodecConfiguration(nullptr),
383       mCodecInterface(nullptr),
384       mStrideAlign(2),
385       mColorFormat(VPX_IMG_FMT_I420),
386       mBitrateControlMode(VPX_VBR),
387       mErrorResilience(false),
388       mMinQuantizer(0),
389       mMaxQuantizer(0),
390       mTemporalLayers(0),
391       mTemporalPatternType(VPXTemporalLayerPatternNone),
392       mTemporalPatternLength(0),
393       mTemporalPatternIdx(0),
394       mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
395       mSignalledOutputEos(false),
396       mSignalledError(false) {
397     for (int i = 0; i < MAXTEMPORALLAYERS; i++) {
398         mTemporalLayerBitrateRatio[i] = 1.0f;
399     }
400 }
401 
~C2SoftVpxEnc()402 C2SoftVpxEnc::~C2SoftVpxEnc() {
403     onRelease();
404 }
405 
onInit()406 c2_status_t C2SoftVpxEnc::onInit() {
407     status_t err = initEncoder();
408     return err == OK ? C2_OK : C2_CORRUPTED;
409 }
410 
onRelease()411 void C2SoftVpxEnc::onRelease() {
412     if (mCodecContext) {
413         vpx_codec_destroy(mCodecContext);
414         delete mCodecContext;
415         mCodecContext = nullptr;
416     }
417 
418     if (mCodecConfiguration) {
419         delete mCodecConfiguration;
420         mCodecConfiguration = nullptr;
421     }
422 
423     // this one is not allocated by us
424     mCodecInterface = nullptr;
425 }
426 
onStop()427 c2_status_t C2SoftVpxEnc::onStop() {
428     onRelease();
429     mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
430     mSignalledOutputEos = false;
431     mSignalledError = false;
432     return C2_OK;
433 }
434 
onReset()435 void C2SoftVpxEnc::onReset() {
436     (void)onStop();
437 }
438 
onFlush_sm()439 c2_status_t C2SoftVpxEnc::onFlush_sm() {
440     return onStop();
441 }
442 
initEncoder()443 status_t C2SoftVpxEnc::initEncoder() {
444     vpx_codec_err_t codec_return;
445     status_t result = UNKNOWN_ERROR;
446     {
447         IntfImpl::Lock lock = mIntf->lock();
448         mSize = mIntf->getSize_l();
449         mBitrate = mIntf->getBitrate_l();
450         mBitrateMode = mIntf->getBitrateMode_l();
451         mFrameRate = mIntf->getFrameRate_l();
452         mIntraRefresh = mIntf->getIntraRefresh_l();
453         mRequestSync = mIntf->getRequestSync_l();
454         mLayering = mIntf->getTemporalLayers_l();
455         mTemporalLayers = mLayering->m.layerCount;
456     }
457 
458     switch (mBitrateMode->value) {
459         case C2Config::BITRATE_CONST:
460             mBitrateControlMode = VPX_CBR;
461             break;
462         case C2Config::BITRATE_VARIABLE:
463         [[fallthrough]];
464         default:
465             mBitrateControlMode = VPX_VBR;
466             break;
467     }
468 
469     setCodecSpecificInterface();
470     if (!mCodecInterface) goto CleanUp;
471 
472     ALOGD("VPx: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
473           (uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
474           mMinQuantizer, mMaxQuantizer);
475 
476     mCodecConfiguration = new vpx_codec_enc_cfg_t;
477     if (!mCodecConfiguration) goto CleanUp;
478     codec_return = vpx_codec_enc_config_default(mCodecInterface,
479                                                 mCodecConfiguration,
480                                                 0);
481     if (codec_return != VPX_CODEC_OK) {
482         ALOGE("Error populating default configuration for vpx encoder.");
483         goto CleanUp;
484     }
485 
486     mCodecConfiguration->g_w = mSize->width;
487     mCodecConfiguration->g_h = mSize->height;
488     //mCodecConfiguration->g_threads = getCpuCoreCount();
489     mCodecConfiguration->g_threads = 0;
490     mCodecConfiguration->g_error_resilient = mErrorResilience;
491 
492     // timebase unit is microsecond
493     // g_timebase is in seconds (i.e. 1/1000000 seconds)
494     mCodecConfiguration->g_timebase.num = 1;
495     mCodecConfiguration->g_timebase.den = 1000000;
496     // rc_target_bitrate is in kbps, mBitrate in bps
497     mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
498     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
499     // Disable frame drop - not allowed in MediaCodec now.
500     mCodecConfiguration->rc_dropframe_thresh = 0;
501     // Disable lagged encoding.
502     mCodecConfiguration->g_lag_in_frames = 0;
503     if (mBitrateControlMode == VPX_CBR) {
504         // Disable spatial resizing.
505         mCodecConfiguration->rc_resize_allowed = 0;
506         // Single-pass mode.
507         mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
508         // Maximum amount of bits that can be subtracted from the target
509         // bitrate - expressed as percentage of the target bitrate.
510         mCodecConfiguration->rc_undershoot_pct = 100;
511         // Maximum amount of bits that can be added to the target
512         // bitrate - expressed as percentage of the target bitrate.
513         mCodecConfiguration->rc_overshoot_pct = 15;
514         // Initial value of the buffer level in ms.
515         mCodecConfiguration->rc_buf_initial_sz = 500;
516         // Amount of data that the encoder should try to maintain in ms.
517         mCodecConfiguration->rc_buf_optimal_sz = 600;
518         // The amount of data that may be buffered by the decoding
519         // application in ms.
520         mCodecConfiguration->rc_buf_sz = 1000;
521         // Enable error resilience - needed for packet loss.
522         mCodecConfiguration->g_error_resilient = 1;
523         // Maximum key frame interval - for CBR boost to 3000
524         mCodecConfiguration->kf_max_dist = 3000;
525         // Encoder determines optimal key frame placement automatically.
526         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
527     }
528 
529     // Frames temporal pattern - for now WebRTC like pattern is only supported.
530     switch (mTemporalLayers) {
531         case 0:
532             mTemporalPatternLength = 0;
533             break;
534         case 1:
535             mCodecConfiguration->ts_number_layers = 1;
536             mCodecConfiguration->ts_rate_decimator[0] = 1;
537             mCodecConfiguration->ts_periodicity = 1;
538             mCodecConfiguration->ts_layer_id[0] = 0;
539             mTemporalPattern[0] = kTemporalUpdateLastRefAll;
540             mTemporalPatternLength = 1;
541             break;
542         case 2:
543             mCodecConfiguration->ts_number_layers = 2;
544             mCodecConfiguration->ts_rate_decimator[0] = 2;
545             mCodecConfiguration->ts_rate_decimator[1] = 1;
546             mCodecConfiguration->ts_periodicity = 2;
547             mCodecConfiguration->ts_layer_id[0] = 0;
548             mCodecConfiguration->ts_layer_id[1] = 1;
549             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
550             mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
551             mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
552             mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
553             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
554             mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
555             mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
556             mTemporalPattern[7] = kTemporalUpdateNone;
557             mTemporalLayerBitrateRatio[0] = mLayering->m.bitrateRatios[0];
558             mTemporalPatternLength = 8;
559             break;
560         case 3:
561             mCodecConfiguration->ts_number_layers = 3;
562             mCodecConfiguration->ts_rate_decimator[0] = 4;
563             mCodecConfiguration->ts_rate_decimator[1] = 2;
564             mCodecConfiguration->ts_rate_decimator[2] = 1;
565             mCodecConfiguration->ts_periodicity = 4;
566             mCodecConfiguration->ts_layer_id[0] = 0;
567             mCodecConfiguration->ts_layer_id[1] = 2;
568             mCodecConfiguration->ts_layer_id[2] = 1;
569             mCodecConfiguration->ts_layer_id[3] = 2;
570             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
571             mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
572             mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
573             mTemporalPattern[3] = kTemporalUpdateNone;
574             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
575             mTemporalPattern[5] = kTemporalUpdateNone;
576             mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
577             mTemporalPattern[7] = kTemporalUpdateNone;
578             mTemporalLayerBitrateRatio[0] = mLayering->m.bitrateRatios[0];
579             mTemporalLayerBitrateRatio[1] = mLayering->m.bitrateRatios[1];
580             mTemporalPatternLength = 8;
581             break;
582         default:
583             ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
584             goto CleanUp;
585     }
586     // Set bitrate values for each layer
587     for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
588         mCodecConfiguration->ts_target_bitrate[i] =
589             mCodecConfiguration->rc_target_bitrate *
590             mTemporalLayerBitrateRatio[i];
591     }
592     if (mIntf->getSyncFramePeriod() >= 0) {
593         mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
594         mCodecConfiguration->kf_min_dist = mIntf->getSyncFramePeriod();
595         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
596     }
597     if (mMinQuantizer > 0) {
598         mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
599     }
600     if (mMaxQuantizer > 0) {
601         mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
602     }
603     setCodecSpecificConfiguration();
604     mCodecContext = new vpx_codec_ctx_t;
605     if (!mCodecContext) goto CleanUp;
606     codec_return = vpx_codec_enc_init(mCodecContext,
607                                       mCodecInterface,
608                                       mCodecConfiguration,
609                                       0);  // flags
610     if (codec_return != VPX_CODEC_OK) {
611         ALOGE("Error initializing vpx encoder");
612         goto CleanUp;
613     }
614 
615     // Extra CBR settings
616     if (mBitrateControlMode == VPX_CBR) {
617         codec_return = vpx_codec_control(mCodecContext,
618                                          VP8E_SET_STATIC_THRESHOLD,
619                                          1);
620         if (codec_return == VPX_CODEC_OK) {
621             uint32_t rc_max_intra_target =
622                 (uint32_t)(mCodecConfiguration->rc_buf_optimal_sz * mFrameRate->value / 20 + 0.5);
623             // Don't go below 3 times per frame bandwidth.
624             if (rc_max_intra_target < 300) {
625                 rc_max_intra_target = 300;
626             }
627             codec_return = vpx_codec_control(mCodecContext,
628                                              VP8E_SET_MAX_INTRA_BITRATE_PCT,
629                                              rc_max_intra_target);
630         }
631         if (codec_return == VPX_CODEC_OK) {
632             codec_return = vpx_codec_control(mCodecContext,
633                                              VP8E_SET_CPUUSED,
634                                              -8);
635         }
636         if (codec_return != VPX_CODEC_OK) {
637             ALOGE("Error setting cbr parameters for vpx encoder.");
638             goto CleanUp;
639         }
640     }
641 
642     codec_return = setCodecSpecificControls();
643     if (codec_return != VPX_CODEC_OK) goto CleanUp;
644 
645     {
646         uint32_t width = mSize->width;
647         uint32_t height = mSize->height;
648         if (((uint64_t)width * height) >
649             ((uint64_t)INT32_MAX / 3)) {
650             ALOGE("b/25812794, Buffer size is too big, width=%u, height=%u.", width, height);
651         } else {
652             uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
653             uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
654             mConversionBuffer = MemoryBlock::Allocate(stride * vstride * 3 / 2);
655             if (!mConversionBuffer.size()) {
656                 ALOGE("Allocating conversion buffer failed.");
657             } else {
658                 mNumInputFrames = -1;
659                 return OK;
660             }
661         }
662     }
663 
664 CleanUp:
665     onRelease();
666     return result;
667 }
668 
getEncodeFlags()669 vpx_enc_frame_flags_t C2SoftVpxEnc::getEncodeFlags() {
670     vpx_enc_frame_flags_t flags = 0;
671     if (mTemporalPatternLength > 0) {
672       int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
673       mTemporalPatternIdx++;
674       switch (mTemporalPattern[patternIdx]) {
675           case kTemporalUpdateLast:
676               flags |= VP8_EFLAG_NO_UPD_GF;
677               flags |= VP8_EFLAG_NO_UPD_ARF;
678               flags |= VP8_EFLAG_NO_REF_GF;
679               flags |= VP8_EFLAG_NO_REF_ARF;
680               break;
681           case kTemporalUpdateGoldenWithoutDependency:
682               flags |= VP8_EFLAG_NO_REF_GF;
683               [[fallthrough]];
684           case kTemporalUpdateGolden:
685               flags |= VP8_EFLAG_NO_REF_ARF;
686               flags |= VP8_EFLAG_NO_UPD_ARF;
687               flags |= VP8_EFLAG_NO_UPD_LAST;
688               break;
689           case kTemporalUpdateAltrefWithoutDependency:
690               flags |= VP8_EFLAG_NO_REF_ARF;
691               flags |= VP8_EFLAG_NO_REF_GF;
692               [[fallthrough]];
693           case kTemporalUpdateAltref:
694               flags |= VP8_EFLAG_NO_UPD_GF;
695               flags |= VP8_EFLAG_NO_UPD_LAST;
696               break;
697           case kTemporalUpdateNoneNoRefAltref:
698               flags |= VP8_EFLAG_NO_REF_ARF;
699               [[fallthrough]];
700           case kTemporalUpdateNone:
701               flags |= VP8_EFLAG_NO_UPD_GF;
702               flags |= VP8_EFLAG_NO_UPD_ARF;
703               flags |= VP8_EFLAG_NO_UPD_LAST;
704               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
705               break;
706           case kTemporalUpdateNoneNoRefGoldenRefAltRef:
707               flags |= VP8_EFLAG_NO_REF_GF;
708               flags |= VP8_EFLAG_NO_UPD_GF;
709               flags |= VP8_EFLAG_NO_UPD_ARF;
710               flags |= VP8_EFLAG_NO_UPD_LAST;
711               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
712               break;
713           case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
714               flags |= VP8_EFLAG_NO_REF_GF;
715               flags |= VP8_EFLAG_NO_UPD_ARF;
716               flags |= VP8_EFLAG_NO_UPD_LAST;
717               break;
718           case kTemporalUpdateLastRefAltRef:
719               flags |= VP8_EFLAG_NO_UPD_GF;
720               flags |= VP8_EFLAG_NO_UPD_ARF;
721               flags |= VP8_EFLAG_NO_REF_GF;
722               break;
723           case kTemporalUpdateGoldenRefAltRef:
724               flags |= VP8_EFLAG_NO_UPD_ARF;
725               flags |= VP8_EFLAG_NO_UPD_LAST;
726               break;
727           case kTemporalUpdateLastAndGoldenRefAltRef:
728               flags |= VP8_EFLAG_NO_UPD_ARF;
729               flags |= VP8_EFLAG_NO_REF_GF;
730               break;
731           case kTemporalUpdateLastRefAll:
732               flags |= VP8_EFLAG_NO_UPD_ARF;
733               flags |= VP8_EFLAG_NO_UPD_GF;
734               break;
735       }
736     }
737     return flags;
738 }
739 
740 // TODO: add support for YUV input color formats
741 // TODO: add support for SVC, ARF. SVC and ARF returns multiple frames
742 // (hierarchical / noshow) in one call. These frames should be combined in to
743 // a single buffer and sent back to the client
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)744 void C2SoftVpxEnc::process(
745         const std::unique_ptr<C2Work> &work,
746         const std::shared_ptr<C2BlockPool> &pool) {
747     // Initialize output work
748     work->result = C2_OK;
749     work->workletsProcessed = 1u;
750     work->worklets.front()->output.flags = work->input.flags;
751 
752     if (mSignalledError || mSignalledOutputEos) {
753         work->result = C2_BAD_VALUE;
754         return;
755     }
756     // Initialize encoder if not already
757     if (!mCodecContext && OK != initEncoder()) {
758         ALOGE("Failed to initialize encoder");
759         mSignalledError = true;
760         work->result = C2_CORRUPTED;
761         return;
762     }
763 
764     std::shared_ptr<C2GraphicView> rView;
765     std::shared_ptr<C2Buffer> inputBuffer;
766     if (!work->input.buffers.empty()) {
767         inputBuffer = work->input.buffers[0];
768         rView = std::make_shared<C2GraphicView>(
769                     inputBuffer->data().graphicBlocks().front().map().get());
770         if (rView->error() != C2_OK) {
771             ALOGE("graphic view map err = %d", rView->error());
772             work->result = C2_CORRUPTED;
773             return;
774         }
775         //(b/232396154)
776         //workaround for incorrect crop size in view when using surface mode
777         rView->setCrop_be(C2Rect(mSize->width, mSize->height));
778     } else {
779         ALOGV("Empty input Buffer");
780         uint32_t flags = 0;
781         if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
782             flags |= C2FrameData::FLAG_END_OF_STREAM;
783         }
784         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
785         work->worklets.front()->output.buffers.clear();
786         work->worklets.front()->output.ordinal = work->input.ordinal;
787         work->workletsProcessed = 1u;
788         return;
789     }
790 
791     const C2ConstGraphicBlock inBuffer =
792         inputBuffer->data().graphicBlocks().front();
793     if (inBuffer.width() < mSize->width ||
794         inBuffer.height() < mSize->height) {
795         ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
796               inBuffer.width(), mSize->width, inBuffer.height(),
797               mSize->height);
798         mSignalledError = true;
799         work->result = C2_BAD_VALUE;
800         return;
801     }
802     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
803     vpx_image_t raw_frame;
804     const C2PlanarLayout &layout = rView->layout();
805     uint32_t width = mSize->width;
806     uint32_t height = mSize->height;
807     if (width > 0x8000 || height > 0x8000) {
808         ALOGE("Image too big: %u x %u", width, height);
809         work->result = C2_BAD_VALUE;
810         return;
811     }
812     uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
813     uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
814     switch (layout.type) {
815         case C2PlanarLayout::TYPE_RGB:
816         case C2PlanarLayout::TYPE_RGBA: {
817             std::shared_ptr<C2StreamColorAspectsInfo::output> colorAspects;
818             {
819                 IntfImpl::Lock lock = mIntf->lock();
820                 colorAspects = mIntf->getCodedColorAspects_l();
821             }
822             ConvertRGBToPlanarYUV(mConversionBuffer.data(), stride, vstride,
823                                   mConversionBuffer.size(), *rView.get(),
824                                   colorAspects->matrix, colorAspects->range);
825             vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
826                          mStrideAlign, mConversionBuffer.data());
827             break;
828         }
829         case C2PlanarLayout::TYPE_YUV: {
830             if (!IsYUV420(*rView)) {
831                 ALOGE("input is not YUV420");
832                 work->result = C2_BAD_VALUE;
833                 return;
834             }
835 
836             if (layout.planes[layout.PLANE_Y].colInc == 1
837                     && layout.planes[layout.PLANE_U].colInc == 1
838                     && layout.planes[layout.PLANE_V].colInc == 1) {
839                 // I420 compatible - though with custom offset and stride
840                 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
841                              mStrideAlign, (uint8_t*)rView->data()[0]);
842                 raw_frame.planes[1] = (uint8_t*)rView->data()[1];
843                 raw_frame.planes[2] = (uint8_t*)rView->data()[2];
844                 raw_frame.stride[0] = layout.planes[layout.PLANE_Y].rowInc;
845                 raw_frame.stride[1] = layout.planes[layout.PLANE_U].rowInc;
846                 raw_frame.stride[2] = layout.planes[layout.PLANE_V].rowInc;
847             } else {
848                 // copy to I420
849                 MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, stride, vstride);
850                 if (mConversionBuffer.size() >= stride * vstride * 3 / 2) {
851                     status_t err = ImageCopy(mConversionBuffer.data(), &img, *rView);
852                     if (err != OK) {
853                         ALOGE("Buffer conversion failed: %d", err);
854                         work->result = C2_BAD_VALUE;
855                         return;
856                     }
857                     vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
858                                  mStrideAlign, mConversionBuffer.data());
859                     vpx_img_set_rect(&raw_frame, 0, 0, width, height);
860                 } else {
861                     ALOGE("Conversion buffer is too small: %u x %u for %zu",
862                             stride, vstride, mConversionBuffer.size());
863                     work->result = C2_BAD_VALUE;
864                     return;
865                 }
866             }
867             break;
868         }
869         default:
870             ALOGE("Unrecognized plane type: %d", layout.type);
871             work->result = C2_BAD_VALUE;
872             return;
873     }
874 
875     vpx_enc_frame_flags_t flags = getEncodeFlags();
876     // handle dynamic config parameters
877     {
878         IntfImpl::Lock lock = mIntf->lock();
879         std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh = mIntf->getIntraRefresh_l();
880         std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
881         std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
882         lock.unlock();
883 
884         if (intraRefresh != mIntraRefresh) {
885             mIntraRefresh = intraRefresh;
886             ALOGV("Got mIntraRefresh request");
887         }
888 
889         if (requestSync != mRequestSync) {
890             // we can handle IDR immediately
891             if (requestSync->value) {
892                 // unset request
893                 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
894                 std::vector<std::unique_ptr<C2SettingResult>> failures;
895                 mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
896                 ALOGV("Got sync request");
897                 flags |= VPX_EFLAG_FORCE_KF;
898             }
899             mRequestSync = requestSync;
900         }
901 
902         if (bitrate != mBitrate) {
903             mBitrate = bitrate;
904             mCodecConfiguration->rc_target_bitrate =
905                 (mBitrate->value + 500) / 1000;
906             vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
907                                                            mCodecConfiguration);
908             if (res != VPX_CODEC_OK) {
909                 ALOGE("vpx encoder failed to update bitrate: %s",
910                       vpx_codec_err_to_string(res));
911                 mSignalledError = true;
912                 work->result = C2_CORRUPTED;
913                 return;
914             }
915         }
916     }
917 
918     uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
919     uint32_t frameDuration;
920     if (inputTimeStamp > mLastTimestamp) {
921         frameDuration = (uint32_t)(inputTimeStamp - mLastTimestamp);
922     } else {
923         // Use default of 30 fps in case of 0 frame rate.
924         float frameRate = mFrameRate->value;
925         if (frameRate < 0.001) {
926             frameRate = 30;
927         }
928         frameDuration = (uint32_t)(1000000 / frameRate + 0.5);
929     }
930     mLastTimestamp = inputTimeStamp;
931 
932     vpx_codec_err_t codec_return = vpx_codec_encode(mCodecContext, &raw_frame,
933                                                     inputTimeStamp,
934                                                     frameDuration, flags,
935                                                     VPX_DL_REALTIME);
936     if (codec_return != VPX_CODEC_OK) {
937         ALOGE("vpx encoder failed to encode frame");
938         mSignalledError = true;
939         work->result = C2_CORRUPTED;
940         return;
941     }
942 
943     bool populated = false;
944     vpx_codec_iter_t encoded_packet_iterator = nullptr;
945     const vpx_codec_cx_pkt_t* encoded_packet;
946     while ((encoded_packet = vpx_codec_get_cx_data(
947                     mCodecContext, &encoded_packet_iterator))) {
948         if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
949             std::shared_ptr<C2LinearBlock> block;
950             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
951             c2_status_t err = pool->fetchLinearBlock(encoded_packet->data.frame.sz, usage, &block);
952             if (err != C2_OK) {
953                 ALOGE("fetchLinearBlock for Output failed with status %d", err);
954                 work->result = C2_NO_MEMORY;
955                 return;
956             }
957             C2WriteView wView = block->map().get();
958             if (wView.error()) {
959                 ALOGE("write view map failed %d", wView.error());
960                 work->result = C2_CORRUPTED;
961                 return;
962             }
963 
964             memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
965             ++mNumInputFrames;
966 
967             ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
968             uint32_t flags = 0;
969             if (eos) {
970                 flags |= C2FrameData::FLAG_END_OF_STREAM;
971             }
972             work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
973             work->worklets.front()->output.buffers.clear();
974             std::shared_ptr<C2Buffer> buffer =
975                 createLinearBuffer(block, 0, encoded_packet->data.frame.sz);
976             if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) {
977                 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
978                         0u /* stream id */, C2Config::SYNC_FRAME));
979             }
980             work->worklets.front()->output.buffers.push_back(buffer);
981             work->worklets.front()->output.ordinal = work->input.ordinal;
982             work->worklets.front()->output.ordinal.timestamp = encoded_packet->data.frame.pts;
983             work->workletsProcessed = 1u;
984             populated = true;
985             if (eos) {
986                 mSignalledOutputEos = true;
987                 ALOGV("signalled EOS");
988             }
989         }
990     }
991     if (!populated) {
992         work->workletsProcessed = 0u;
993     }
994 }
995 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)996 c2_status_t C2SoftVpxEnc::drain(
997         uint32_t drainMode,
998         const std::shared_ptr<C2BlockPool> &pool) {
999     (void)pool;
1000     if (drainMode == NO_DRAIN) {
1001         ALOGW("drain with NO_DRAIN: no-op");
1002         return C2_OK;
1003     }
1004     if (drainMode == DRAIN_CHAIN) {
1005         ALOGW("DRAIN_CHAIN not supported");
1006         return C2_OMITTED;
1007     }
1008 
1009     return C2_OK;
1010 }
1011 
1012 }  // namespace android
1013