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