// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //#define LOG_NDEBUG 0 #define LOG_TAG "V4L2EncodeComponent" #include #include #include #include #include #include #include namespace android { // static std::atomic V4L2EncodeComponent::sConcurrentInstances = 0; // static std::shared_ptr V4L2EncodeComponent::create( C2String name, c2_node_id_t id, std::shared_ptr intfImpl, C2ComponentFactory::ComponentDeleter deleter) { ALOGV("%s(%s)", __func__, name.c_str()); static const int32_t kMaxConcurrentInstances = property_get_int32("ro.vendor.v4l2_codec2.encode_concurrent_instances", -1); static std::mutex mutex; std::lock_guard lock(mutex); if (kMaxConcurrentInstances >= 0 && sConcurrentInstances.load() >= kMaxConcurrentInstances) { ALOGW("Cannot create additional encoder, maximum number of instances reached: %d", kMaxConcurrentInstances); return nullptr; } return std::shared_ptr(new V4L2EncodeComponent(name, id, std::move(intfImpl)), deleter); } V4L2EncodeComponent::V4L2EncodeComponent(C2String name, c2_node_id_t id, std::shared_ptr interface) : EncodeComponent(name, id, interface) { ALOGV("%s():", __func__); sConcurrentInstances.fetch_add(1, std::memory_order_relaxed); } V4L2EncodeComponent::~V4L2EncodeComponent() { ALOGV("%s():", __func__); sConcurrentInstances.fetch_sub(1, std::memory_order_relaxed); } bool V4L2EncodeComponent::initializeEncoder() { ALOGV("%s()", __func__); ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence()); ALOG_ASSERT(!mInputFormatConverter); ALOG_ASSERT(!mEncoder); mLastFrameTime = std::nullopt; // Get the requested profile and level. C2Config::profile_t outputProfile = mInterface->getOutputProfile(); // CSD only needs to be extracted when using an H.264 profile. mExtractCSD = isH264Profile(outputProfile); std::optional h264Level; if (isH264Profile(outputProfile)) { h264Level = c2LevelToV4L2Level(mInterface->getOutputLevel()); } // Get the stride used by the C2 framework, as this might be different from the stride used by // the V4L2 encoder. std::optional stride = getVideoFrameStride(VideoEncoder::kInputPixelFormat, mInterface->getInputVisibleSize()); if (!stride) { ALOGE("Failed to get video frame stride"); reportError(C2_CORRUPTED); return false; } // Get the requested bitrate mode and bitrate. The C2 framework doesn't offer a parameter to // configure the peak bitrate, so we use a multiple of the target bitrate. mBitrateMode = mInterface->getBitrateMode(); if (property_get_bool("persist.vendor.v4l2_codec2.disable_vbr", false)) { // NOTE: This is a workaround for b/235771157. ALOGW("VBR is disabled on this device"); mBitrateMode = C2Config::BITRATE_CONST; } mBitrate = mInterface->getBitrate(); mEncoder = V4L2Encoder::create( outputProfile, h264Level, mInterface->getInputVisibleSize(), *stride, mInterface->getKeyFramePeriod(), mBitrateMode, mBitrate, mBitrate * VideoEncoder::kPeakBitrateMultiplier, ::base::BindRepeating(&V4L2EncodeComponent::fetchOutputBlock, mWeakThis), ::base::BindRepeating(&V4L2EncodeComponent::onInputBufferDone, mWeakThis), ::base::BindRepeating(&V4L2EncodeComponent::onOutputBufferDone, mWeakThis), ::base::BindRepeating(&V4L2EncodeComponent::onDrainDone, mWeakThis), ::base::BindRepeating(&V4L2EncodeComponent::reportError, mWeakThis, C2_CORRUPTED), mEncoderTaskRunner); if (!mEncoder) { ALOGE("Failed to create V4L2Encoder (profile: %s)", profileToString(outputProfile)); return false; } return true; } } // namespace android