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 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 74 C2SoftVpxEnc::~C2SoftVpxEnc() { 75 onRelease(); 76 } 77 78 c2_status_t C2SoftVpxEnc::onInit() { 79 status_t err = initEncoder(); 80 return err == OK ? C2_OK : C2_CORRUPTED; 81 } 82 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 99 c2_status_t C2SoftVpxEnc::onStop() { 100 onRelease(); 101 mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL; 102 mSignalledOutputEos = false; 103 mSignalledError = false; 104 return C2_OK; 105 } 106 107 void C2SoftVpxEnc::onReset() { 108 (void)onStop(); 109 } 110 111 c2_status_t C2SoftVpxEnc::onFlush_sm() { 112 return onStop(); 113 } 114 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_CONST: 131 mBitrateControlMode = VPX_CBR; 132 break; 133 case C2Config::BITRATE_VARIABLE: 134 [[fallthrough]]; 135 default: 136 mBitrateControlMode = VPX_VBR; 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 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 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 */, C2Config::SYNC_FRAME)); 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 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