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