• 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 
34 #if 0
35 static size_t getCpuCoreCount() {
36     long cpuCoreCount = 1;
37 #if defined(_SC_NPROCESSORS_ONLN)
38     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
39 #else
40     // _SC_NPROC_ONLN must be defined...
41     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
42 #endif
43     CHECK(cpuCoreCount >= 1);
44     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
45     return (size_t)cpuCoreCount;
46 }
47 #endif
48 
C2SoftVpxEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)49 C2SoftVpxEnc::C2SoftVpxEnc(const char* name, c2_node_id_t id,
50                            const std::shared_ptr<IntfImpl>& intfImpl)
51     : SimpleC2Component(
52           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
53       mIntf(intfImpl),
54       mCodecContext(nullptr),
55       mCodecConfiguration(nullptr),
56       mCodecInterface(nullptr),
57       mStrideAlign(2),
58       mColorFormat(VPX_IMG_FMT_I420),
59       mBitrateControlMode(VPX_VBR),
60       mErrorResilience(false),
61       mMinQuantizer(0),
62       mMaxQuantizer(0),
63       mTemporalLayers(0),
64       mTemporalPatternType(VPXTemporalLayerPatternNone),
65       mTemporalPatternLength(0),
66       mTemporalPatternIdx(0),
67       mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
68       mSignalledOutputEos(false),
69       mSignalledError(false) {
70     memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
71     mTemporalLayerBitrateRatio[0] = 100;
72 }
73 
~C2SoftVpxEnc()74 C2SoftVpxEnc::~C2SoftVpxEnc() {
75     onRelease();
76 }
77 
onInit()78 c2_status_t C2SoftVpxEnc::onInit() {
79     status_t err = initEncoder();
80     return err == OK ? C2_OK : C2_CORRUPTED;
81 }
82 
onRelease()83 void C2SoftVpxEnc::onRelease() {
84     if (mCodecContext) {
85         vpx_codec_destroy(mCodecContext);
86         delete mCodecContext;
87         mCodecContext = nullptr;
88     }
89 
90     if (mCodecConfiguration) {
91         delete mCodecConfiguration;
92         mCodecConfiguration = nullptr;
93     }
94 
95     // this one is not allocated by us
96     mCodecInterface = nullptr;
97 }
98 
onStop()99 c2_status_t C2SoftVpxEnc::onStop() {
100     onRelease();
101     mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
102     mSignalledOutputEos = false;
103     mSignalledError = false;
104     return C2_OK;
105 }
106 
onReset()107 void C2SoftVpxEnc::onReset() {
108     (void)onStop();
109 }
110 
onFlush_sm()111 c2_status_t C2SoftVpxEnc::onFlush_sm() {
112     return onStop();
113 }
114 
initEncoder()115 status_t C2SoftVpxEnc::initEncoder() {
116     vpx_codec_err_t codec_return;
117     status_t result = UNKNOWN_ERROR;
118     {
119         IntfImpl::Lock lock = mIntf->lock();
120         mSize = mIntf->getSize_l();
121         mBitrate = mIntf->getBitrate_l();
122         mBitrateMode = mIntf->getBitrateMode_l();
123         mFrameRate = mIntf->getFrameRate_l();
124         mIntraRefresh = mIntf->getIntraRefresh_l();
125         mRequestSync = mIntf->getRequestSync_l();
126         mTemporalLayers = mIntf->getTemporalLayers_l()->m.layerCount;
127     }
128 
129     switch (mBitrateMode->value) {
130         case C2Config::BITRATE_VARIABLE:
131             mBitrateControlMode = VPX_VBR;
132             break;
133         case C2Config::BITRATE_CONST:
134         default:
135             mBitrateControlMode = VPX_CBR;
136             break;
137         break;
138     }
139 
140     setCodecSpecificInterface();
141     if (!mCodecInterface) goto CleanUp;
142 
143     ALOGD("VPx: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
144           (uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
145           mMinQuantizer, mMaxQuantizer);
146 
147     mCodecConfiguration = new vpx_codec_enc_cfg_t;
148     if (!mCodecConfiguration) goto CleanUp;
149     codec_return = vpx_codec_enc_config_default(mCodecInterface,
150                                                 mCodecConfiguration,
151                                                 0);
152     if (codec_return != VPX_CODEC_OK) {
153         ALOGE("Error populating default configuration for vpx encoder.");
154         goto CleanUp;
155     }
156 
157     mCodecConfiguration->g_w = mSize->width;
158     mCodecConfiguration->g_h = mSize->height;
159     //mCodecConfiguration->g_threads = getCpuCoreCount();
160     mCodecConfiguration->g_threads = 0;
161     mCodecConfiguration->g_error_resilient = mErrorResilience;
162 
163     // timebase unit is microsecond
164     // g_timebase is in seconds (i.e. 1/1000000 seconds)
165     mCodecConfiguration->g_timebase.num = 1;
166     mCodecConfiguration->g_timebase.den = 1000000;
167     // rc_target_bitrate is in kbps, mBitrate in bps
168     mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
169     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
170     // Disable frame drop - not allowed in MediaCodec now.
171     mCodecConfiguration->rc_dropframe_thresh = 0;
172     // Disable lagged encoding.
173     mCodecConfiguration->g_lag_in_frames = 0;
174     if (mBitrateControlMode == VPX_CBR) {
175         // Disable spatial resizing.
176         mCodecConfiguration->rc_resize_allowed = 0;
177         // Single-pass mode.
178         mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
179         // Maximum amount of bits that can be subtracted from the target
180         // bitrate - expressed as percentage of the target bitrate.
181         mCodecConfiguration->rc_undershoot_pct = 100;
182         // Maximum amount of bits that can be added to the target
183         // bitrate - expressed as percentage of the target bitrate.
184         mCodecConfiguration->rc_overshoot_pct = 15;
185         // Initial value of the buffer level in ms.
186         mCodecConfiguration->rc_buf_initial_sz = 500;
187         // Amount of data that the encoder should try to maintain in ms.
188         mCodecConfiguration->rc_buf_optimal_sz = 600;
189         // The amount of data that may be buffered by the decoding
190         // application in ms.
191         mCodecConfiguration->rc_buf_sz = 1000;
192         // Enable error resilience - needed for packet loss.
193         mCodecConfiguration->g_error_resilient = 1;
194         // Maximum key frame interval - for CBR boost to 3000
195         mCodecConfiguration->kf_max_dist = 3000;
196         // Encoder determines optimal key frame placement automatically.
197         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
198     }
199 
200     // Frames temporal pattern - for now WebRTC like pattern is only supported.
201     switch (mTemporalLayers) {
202         case 0:
203             mTemporalPatternLength = 0;
204             break;
205         case 1:
206             mCodecConfiguration->ts_number_layers = 1;
207             mCodecConfiguration->ts_rate_decimator[0] = 1;
208             mCodecConfiguration->ts_periodicity = 1;
209             mCodecConfiguration->ts_layer_id[0] = 0;
210             mTemporalPattern[0] = kTemporalUpdateLastRefAll;
211             mTemporalPatternLength = 1;
212             break;
213         case 2:
214             mCodecConfiguration->ts_number_layers = 2;
215             mCodecConfiguration->ts_rate_decimator[0] = 2;
216             mCodecConfiguration->ts_rate_decimator[1] = 1;
217             mCodecConfiguration->ts_periodicity = 2;
218             mCodecConfiguration->ts_layer_id[0] = 0;
219             mCodecConfiguration->ts_layer_id[1] = 1;
220             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
221             mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
222             mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
223             mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
224             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
225             mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
226             mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
227             mTemporalPattern[7] = kTemporalUpdateNone;
228             mTemporalPatternLength = 8;
229             break;
230         case 3:
231             mCodecConfiguration->ts_number_layers = 3;
232             mCodecConfiguration->ts_rate_decimator[0] = 4;
233             mCodecConfiguration->ts_rate_decimator[1] = 2;
234             mCodecConfiguration->ts_rate_decimator[2] = 1;
235             mCodecConfiguration->ts_periodicity = 4;
236             mCodecConfiguration->ts_layer_id[0] = 0;
237             mCodecConfiguration->ts_layer_id[1] = 2;
238             mCodecConfiguration->ts_layer_id[2] = 1;
239             mCodecConfiguration->ts_layer_id[3] = 2;
240             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
241             mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
242             mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
243             mTemporalPattern[3] = kTemporalUpdateNone;
244             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
245             mTemporalPattern[5] = kTemporalUpdateNone;
246             mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
247             mTemporalPattern[7] = kTemporalUpdateNone;
248             mTemporalPatternLength = 8;
249             break;
250         default:
251             ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
252             goto CleanUp;
253     }
254     // Set bitrate values for each layer
255     for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
256         mCodecConfiguration->ts_target_bitrate[i] =
257             mCodecConfiguration->rc_target_bitrate *
258             mTemporalLayerBitrateRatio[i] / 100;
259     }
260     if (mIntf->getSyncFramePeriod() >= 0) {
261         mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
262         mCodecConfiguration->kf_min_dist = mIntf->getSyncFramePeriod();
263         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
264     }
265     if (mMinQuantizer > 0) {
266         mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
267     }
268     if (mMaxQuantizer > 0) {
269         mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
270     }
271     setCodecSpecificConfiguration();
272     mCodecContext = new vpx_codec_ctx_t;
273     if (!mCodecContext) goto CleanUp;
274     codec_return = vpx_codec_enc_init(mCodecContext,
275                                       mCodecInterface,
276                                       mCodecConfiguration,
277                                       0);  // flags
278     if (codec_return != VPX_CODEC_OK) {
279         ALOGE("Error initializing vpx encoder");
280         goto CleanUp;
281     }
282 
283     // Extra CBR settings
284     if (mBitrateControlMode == VPX_CBR) {
285         codec_return = vpx_codec_control(mCodecContext,
286                                          VP8E_SET_STATIC_THRESHOLD,
287                                          1);
288         if (codec_return == VPX_CODEC_OK) {
289             uint32_t rc_max_intra_target =
290                 (uint32_t)(mCodecConfiguration->rc_buf_optimal_sz * mFrameRate->value / 20 + 0.5);
291             // Don't go below 3 times per frame bandwidth.
292             if (rc_max_intra_target < 300) {
293                 rc_max_intra_target = 300;
294             }
295             codec_return = vpx_codec_control(mCodecContext,
296                                              VP8E_SET_MAX_INTRA_BITRATE_PCT,
297                                              rc_max_intra_target);
298         }
299         if (codec_return == VPX_CODEC_OK) {
300             codec_return = vpx_codec_control(mCodecContext,
301                                              VP8E_SET_CPUUSED,
302                                              -8);
303         }
304         if (codec_return != VPX_CODEC_OK) {
305             ALOGE("Error setting cbr parameters for vpx encoder.");
306             goto CleanUp;
307         }
308     }
309 
310     codec_return = setCodecSpecificControls();
311     if (codec_return != VPX_CODEC_OK) goto CleanUp;
312 
313     {
314         uint32_t width = mSize->width;
315         uint32_t height = mSize->height;
316         if (((uint64_t)width * height) >
317             ((uint64_t)INT32_MAX / 3)) {
318             ALOGE("b/25812794, Buffer size is too big, width=%u, height=%u.", width, height);
319         } else {
320             uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
321             uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
322             mConversionBuffer = MemoryBlock::Allocate(stride * vstride * 3 / 2);
323             if (!mConversionBuffer.size()) {
324                 ALOGE("Allocating conversion buffer failed.");
325             } else {
326                 mNumInputFrames = -1;
327                 return OK;
328             }
329         }
330     }
331 
332 CleanUp:
333     onRelease();
334     return result;
335 }
336 
getEncodeFlags()337 vpx_enc_frame_flags_t C2SoftVpxEnc::getEncodeFlags() {
338     vpx_enc_frame_flags_t flags = 0;
339     if (mTemporalPatternLength > 0) {
340       int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
341       mTemporalPatternIdx++;
342       switch (mTemporalPattern[patternIdx]) {
343           case kTemporalUpdateLast:
344               flags |= VP8_EFLAG_NO_UPD_GF;
345               flags |= VP8_EFLAG_NO_UPD_ARF;
346               flags |= VP8_EFLAG_NO_REF_GF;
347               flags |= VP8_EFLAG_NO_REF_ARF;
348               break;
349           case kTemporalUpdateGoldenWithoutDependency:
350               flags |= VP8_EFLAG_NO_REF_GF;
351               [[fallthrough]];
352           case kTemporalUpdateGolden:
353               flags |= VP8_EFLAG_NO_REF_ARF;
354               flags |= VP8_EFLAG_NO_UPD_ARF;
355               flags |= VP8_EFLAG_NO_UPD_LAST;
356               break;
357           case kTemporalUpdateAltrefWithoutDependency:
358               flags |= VP8_EFLAG_NO_REF_ARF;
359               flags |= VP8_EFLAG_NO_REF_GF;
360               [[fallthrough]];
361           case kTemporalUpdateAltref:
362               flags |= VP8_EFLAG_NO_UPD_GF;
363               flags |= VP8_EFLAG_NO_UPD_LAST;
364               break;
365           case kTemporalUpdateNoneNoRefAltref:
366               flags |= VP8_EFLAG_NO_REF_ARF;
367               [[fallthrough]];
368           case kTemporalUpdateNone:
369               flags |= VP8_EFLAG_NO_UPD_GF;
370               flags |= VP8_EFLAG_NO_UPD_ARF;
371               flags |= VP8_EFLAG_NO_UPD_LAST;
372               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
373               break;
374           case kTemporalUpdateNoneNoRefGoldenRefAltRef:
375               flags |= VP8_EFLAG_NO_REF_GF;
376               flags |= VP8_EFLAG_NO_UPD_GF;
377               flags |= VP8_EFLAG_NO_UPD_ARF;
378               flags |= VP8_EFLAG_NO_UPD_LAST;
379               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
380               break;
381           case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
382               flags |= VP8_EFLAG_NO_REF_GF;
383               flags |= VP8_EFLAG_NO_UPD_ARF;
384               flags |= VP8_EFLAG_NO_UPD_LAST;
385               break;
386           case kTemporalUpdateLastRefAltRef:
387               flags |= VP8_EFLAG_NO_UPD_GF;
388               flags |= VP8_EFLAG_NO_UPD_ARF;
389               flags |= VP8_EFLAG_NO_REF_GF;
390               break;
391           case kTemporalUpdateGoldenRefAltRef:
392               flags |= VP8_EFLAG_NO_UPD_ARF;
393               flags |= VP8_EFLAG_NO_UPD_LAST;
394               break;
395           case kTemporalUpdateLastAndGoldenRefAltRef:
396               flags |= VP8_EFLAG_NO_UPD_ARF;
397               flags |= VP8_EFLAG_NO_REF_GF;
398               break;
399           case kTemporalUpdateLastRefAll:
400               flags |= VP8_EFLAG_NO_UPD_ARF;
401               flags |= VP8_EFLAG_NO_UPD_GF;
402               break;
403       }
404     }
405     return flags;
406 }
407 
408 // TODO: add support for YUV input color formats
409 // TODO: add support for SVC, ARF. SVC and ARF returns multiple frames
410 // (hierarchical / noshow) in one call. These frames should be combined in to
411 // a single buffer and sent back to the client
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)412 void C2SoftVpxEnc::process(
413         const std::unique_ptr<C2Work> &work,
414         const std::shared_ptr<C2BlockPool> &pool) {
415     // Initialize output work
416     work->result = C2_OK;
417     work->workletsProcessed = 1u;
418     work->worklets.front()->output.flags = work->input.flags;
419 
420     if (mSignalledError || mSignalledOutputEos) {
421         work->result = C2_BAD_VALUE;
422         return;
423     }
424     // Initialize encoder if not already
425     if (!mCodecContext && OK != initEncoder()) {
426         ALOGE("Failed to initialize encoder");
427         mSignalledError = true;
428         work->result = C2_CORRUPTED;
429         return;
430     }
431 
432     std::shared_ptr<const C2GraphicView> rView;
433     std::shared_ptr<C2Buffer> inputBuffer;
434     if (!work->input.buffers.empty()) {
435         inputBuffer = work->input.buffers[0];
436         rView = std::make_shared<const C2GraphicView>(
437                     inputBuffer->data().graphicBlocks().front().map().get());
438         if (rView->error() != C2_OK) {
439             ALOGE("graphic view map err = %d", rView->error());
440             work->result = C2_CORRUPTED;
441             return;
442         }
443     } else {
444         ALOGV("Empty input Buffer");
445         uint32_t flags = 0;
446         if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
447             flags |= C2FrameData::FLAG_END_OF_STREAM;
448         }
449         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
450         work->worklets.front()->output.buffers.clear();
451         work->worklets.front()->output.ordinal = work->input.ordinal;
452         work->workletsProcessed = 1u;
453         return;
454     }
455 
456     const C2ConstGraphicBlock inBuffer =
457         inputBuffer->data().graphicBlocks().front();
458     if (inBuffer.width() != mSize->width ||
459         inBuffer.height() != mSize->height) {
460         ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
461               inBuffer.width(), mSize->width, inBuffer.height(),
462               mSize->height);
463         mSignalledError = true;
464         work->result = C2_BAD_VALUE;
465         return;
466     }
467     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
468     vpx_image_t raw_frame;
469     const C2PlanarLayout &layout = rView->layout();
470     uint32_t width = rView->width();
471     uint32_t height = rView->height();
472     if (width > 0x8000 || height > 0x8000) {
473         ALOGE("Image too big: %u x %u", width, height);
474         work->result = C2_BAD_VALUE;
475         return;
476     }
477     uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
478     uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
479     switch (layout.type) {
480         case C2PlanarLayout::TYPE_RGB:
481         case C2PlanarLayout::TYPE_RGBA: {
482             ConvertRGBToPlanarYUV(mConversionBuffer.data(), stride, vstride,
483                                   mConversionBuffer.size(), *rView.get());
484             vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
485                          mStrideAlign, mConversionBuffer.data());
486             break;
487         }
488         case C2PlanarLayout::TYPE_YUV: {
489             if (!IsYUV420(*rView)) {
490                 ALOGE("input is not YUV420");
491                 work->result = C2_BAD_VALUE;
492                 return;
493             }
494 
495             if (layout.planes[layout.PLANE_Y].colInc == 1
496                     && layout.planes[layout.PLANE_U].colInc == 1
497                     && layout.planes[layout.PLANE_V].colInc == 1) {
498                 // I420 compatible - though with custom offset and stride
499                 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
500                              mStrideAlign, (uint8_t*)rView->data()[0]);
501                 raw_frame.planes[1] = (uint8_t*)rView->data()[1];
502                 raw_frame.planes[2] = (uint8_t*)rView->data()[2];
503                 raw_frame.stride[0] = layout.planes[layout.PLANE_Y].rowInc;
504                 raw_frame.stride[1] = layout.planes[layout.PLANE_U].rowInc;
505                 raw_frame.stride[2] = layout.planes[layout.PLANE_V].rowInc;
506             } else {
507                 // copy to I420
508                 MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, stride, vstride);
509                 if (mConversionBuffer.size() >= stride * vstride * 3 / 2) {
510                     status_t err = ImageCopy(mConversionBuffer.data(), &img, *rView);
511                     if (err != OK) {
512                         ALOGE("Buffer conversion failed: %d", err);
513                         work->result = C2_BAD_VALUE;
514                         return;
515                     }
516                     vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
517                                  mStrideAlign, (uint8_t*)rView->data()[0]);
518                     vpx_img_set_rect(&raw_frame, 0, 0, width, height);
519                 } else {
520                     ALOGE("Conversion buffer is too small: %u x %u for %zu",
521                             stride, vstride, mConversionBuffer.size());
522                     work->result = C2_BAD_VALUE;
523                     return;
524                 }
525             }
526             break;
527         }
528         default:
529             ALOGE("Unrecognized plane type: %d", layout.type);
530             work->result = C2_BAD_VALUE;
531             return;
532     }
533 
534     vpx_enc_frame_flags_t flags = getEncodeFlags();
535     // handle dynamic config parameters
536     {
537         IntfImpl::Lock lock = mIntf->lock();
538         std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh = mIntf->getIntraRefresh_l();
539         std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
540         std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
541         lock.unlock();
542 
543         if (intraRefresh != mIntraRefresh) {
544             mIntraRefresh = intraRefresh;
545             ALOGV("Got mIntraRefresh request");
546         }
547 
548         if (requestSync != mRequestSync) {
549             // we can handle IDR immediately
550             if (requestSync->value) {
551                 // unset request
552                 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
553                 std::vector<std::unique_ptr<C2SettingResult>> failures;
554                 mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
555                 ALOGV("Got sync request");
556                 flags |= VPX_EFLAG_FORCE_KF;
557             }
558             mRequestSync = requestSync;
559         }
560 
561         if (bitrate != mBitrate) {
562             mBitrate = bitrate;
563             mCodecConfiguration->rc_target_bitrate =
564                 (mBitrate->value + 500) / 1000;
565             vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
566                                                            mCodecConfiguration);
567             if (res != VPX_CODEC_OK) {
568                 ALOGE("vpx encoder failed to update bitrate: %s",
569                       vpx_codec_err_to_string(res));
570                 mSignalledError = true;
571                 work->result = C2_CORRUPTED;
572                 return;
573             }
574         }
575     }
576 
577     uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
578     uint32_t frameDuration;
579     if (inputTimeStamp > mLastTimestamp) {
580         frameDuration = (uint32_t)(inputTimeStamp - mLastTimestamp);
581     } else {
582         // Use default of 30 fps in case of 0 frame rate.
583         float frameRate = mFrameRate->value;
584         if (frameRate < 0.001) {
585             frameRate = 30;
586         }
587         frameDuration = (uint32_t)(1000000 / frameRate + 0.5);
588     }
589     mLastTimestamp = inputTimeStamp;
590 
591     vpx_codec_err_t codec_return = vpx_codec_encode(mCodecContext, &raw_frame,
592                                                     inputTimeStamp,
593                                                     frameDuration, flags,
594                                                     VPX_DL_REALTIME);
595     if (codec_return != VPX_CODEC_OK) {
596         ALOGE("vpx encoder failed to encode frame");
597         mSignalledError = true;
598         work->result = C2_CORRUPTED;
599         return;
600     }
601 
602     bool populated = false;
603     vpx_codec_iter_t encoded_packet_iterator = nullptr;
604     const vpx_codec_cx_pkt_t* encoded_packet;
605     while ((encoded_packet = vpx_codec_get_cx_data(
606                     mCodecContext, &encoded_packet_iterator))) {
607         if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
608             std::shared_ptr<C2LinearBlock> block;
609             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
610             c2_status_t err = pool->fetchLinearBlock(encoded_packet->data.frame.sz, usage, &block);
611             if (err != C2_OK) {
612                 ALOGE("fetchLinearBlock for Output failed with status %d", err);
613                 work->result = C2_NO_MEMORY;
614                 return;
615             }
616             C2WriteView wView = block->map().get();
617             if (wView.error()) {
618                 ALOGE("write view map failed %d", wView.error());
619                 work->result = C2_CORRUPTED;
620                 return;
621             }
622 
623             memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
624             ++mNumInputFrames;
625 
626             ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
627             uint32_t flags = 0;
628             if (eos) {
629                 flags |= C2FrameData::FLAG_END_OF_STREAM;
630             }
631             work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
632             work->worklets.front()->output.buffers.clear();
633             std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block);
634             if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) {
635                 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
636                         0u /* stream id */, C2PictureTypeKeyFrame));
637             }
638             work->worklets.front()->output.buffers.push_back(buffer);
639             work->worklets.front()->output.ordinal = work->input.ordinal;
640             work->worklets.front()->output.ordinal.timestamp = encoded_packet->data.frame.pts;
641             work->workletsProcessed = 1u;
642             populated = true;
643             if (eos) {
644                 mSignalledOutputEos = true;
645                 ALOGV("signalled EOS");
646             }
647         }
648     }
649     if (!populated) {
650         work->workletsProcessed = 0u;
651     }
652 }
653 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)654 c2_status_t C2SoftVpxEnc::drain(
655         uint32_t drainMode,
656         const std::shared_ptr<C2BlockPool> &pool) {
657     (void)pool;
658     if (drainMode == NO_DRAIN) {
659         ALOGW("drain with NO_DRAIN: no-op");
660         return C2_OK;
661     }
662     if (drainMode == DRAIN_CHAIN) {
663         ALOGW("DRAIN_CHAIN not supported");
664         return C2_OMITTED;
665     }
666 
667     return C2_OK;
668 }
669 
670 }  // namespace android
671