aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Staessens <dstaessens@google.com>2021-06-07 14:54:53 +0900
committerChih-Yu Huang <akahuang@google.com>2021-10-20 12:07:10 +0900
commitdf5be4b969430c7d933b1bd9d01be3d4836a589d (patch)
tree4df62d16231d132c6134855074f6cc4f80898c6b
parentbc5b861c8ef10aef8c3b7c48b350314d8d000b44 (diff)
downloadv4l2_codec2-df5be4b969430c7d933b1bd9d01be3d4836a589d.tar.gz
v4l2_codec2 encoder: Add support for configuring the bitrate mode.
This CL adds support for the C2_PARAMKEY_BITRATE_MODE parameter to the v4l2 encoder. This parameter allows configuring the bitrate mode used to encode a video. The supported bitrate modes are: - C2Config::BITRATE_VARIABLE - C2Config::BITRATE_CONST Note: Currently the C2 framework does not support configuring the peak bitrate, which is used when the bitrate mode is set to VBR. Instead we set the peak bitrate to a multiple of the target bitrate. Note: Submit after support for V4L2_CID_MPEG_VIDEO_BITRATE_PEAK and V4L2_CID_MPEG_VIDEO_BITRATE_MODE has been added to the virto encoder in crrev.com/c/2944506. BUG: 190336806 BUG: 181514834 Test: arc.VideoEncodeAccel.h264_192p_i420_vm Change-Id: I95d8f9921c1ba475ea8c65760d3c18e5e2818d5e
-rw-r--r--common/V4L2Device.cpp21
-rw-r--r--common/include/v4l2_codec2/common/V4L2Device.h2
-rw-r--r--components/V4L2EncodeComponent.cpp39
-rw-r--r--components/V4L2EncodeInterface.cpp9
-rw-r--r--components/V4L2Encoder.cpp43
-rw-r--r--components/include/v4l2_codec2/components/V4L2EncodeComponent.h2
-rw-r--r--components/include/v4l2_codec2/components/V4L2EncodeInterface.h9
-rw-r--r--components/include/v4l2_codec2/components/V4L2Encoder.h14
-rw-r--r--components/include/v4l2_codec2/components/VideoEncoder.h6
9 files changed, 121 insertions, 24 deletions
diff --git a/common/V4L2Device.cpp b/common/V4L2Device.cpp
index d4fa7f6..1efb4e3 100644
--- a/common/V4L2Device.cpp
+++ b/common/V4L2Device.cpp
@@ -1439,6 +1439,27 @@ int32_t V4L2Device::h264LevelIdcToV4L2H264Level(uint8_t levelIdc) {
}
// static
+v4l2_mpeg_video_bitrate_mode V4L2Device::C2BitrateModeToV4L2BitrateMode(
+ C2Config::bitrate_mode_t bitrateMode) {
+ switch (bitrateMode) {
+ case C2Config::bitrate_mode_t::BITRATE_CONST_SKIP_ALLOWED:
+ ALOGW("BITRATE_CONST_SKIP_ALLOWED not supported, defaulting to BITRATE_CONST");
+ FALLTHROUGH;
+ case C2Config::bitrate_mode_t::BITRATE_CONST:
+ return V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ case C2Config::bitrate_mode_t::BITRATE_VARIABLE_SKIP_ALLOWED:
+ ALOGW("BITRATE_VARIABLE_SKIP_ALLOWED not supported, defaulting to BITRATE_VARIABLE");
+ FALLTHROUGH;
+ case C2Config::bitrate_mode_t::BITRATE_VARIABLE:
+ return V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+ default:
+ ALOGW("Unsupported bitrate mode %u, defaulting to BITRATE_VARIABLE",
+ static_cast<uint32_t>(bitrateMode));
+ return V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+ }
+}
+
+// static
ui::Size V4L2Device::allocatedSizeFromV4L2Format(const struct v4l2_format& format) {
ui::Size codedSize;
ui::Size visibleSize;
diff --git a/common/include/v4l2_codec2/common/V4L2Device.h b/common/include/v4l2_codec2/common/V4L2Device.h
index b4c909c..77d7ddb 100644
--- a/common/include/v4l2_codec2/common/V4L2Device.h
+++ b/common/include/v4l2_codec2/common/V4L2Device.h
@@ -349,6 +349,8 @@ public:
// Convert required H264 profile and level to V4L2 enums.
static int32_t c2ProfileToV4L2H264Profile(C2Config::profile_t profile);
static int32_t h264LevelIdcToV4L2H264Level(uint8_t levelIdc);
+ static v4l2_mpeg_video_bitrate_mode C2BitrateModeToV4L2BitrateMode(
+ C2Config::bitrate_mode_t bitrateMode);
// Converts v4l2_memory to a string.
static const char* v4L2MemoryToString(const v4l2_memory memory);
diff --git a/components/V4L2EncodeComponent.cpp b/components/V4L2EncodeComponent.cpp
index 36bc44a..f88a38a 100644
--- a/components/V4L2EncodeComponent.cpp
+++ b/components/V4L2EncodeComponent.cpp
@@ -40,6 +40,9 @@ namespace {
const VideoPixelFormat kInputPixelFormat = VideoPixelFormat::NV12;
+// The peak bitrate in function of the target bitrate, used when the bitrate mode is VBR.
+constexpr uint32_t kPeakBitrateMultiplier = 2u;
+
// Get the video frame layout from the specified |inputBlock|.
// TODO(dstaessens): Clean up code extracting layout from a C2GraphicBlock.
std::optional<std::vector<VideoFramePlane>> getVideoFrameLayout(const C2ConstGraphicBlock& block,
@@ -646,9 +649,15 @@ bool V4L2EncodeComponent::initializeEncoder() {
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();
+ mBitrate = mInterface->getBitrate();
+
mEncoder = V4L2Encoder::create(
outputProfile, h264Level, mInterface->getInputVisibleSize(), *stride,
- mInterface->getKeyFramePeriod(),
+ mInterface->getKeyFramePeriod(), mBitrateMode, mBitrate,
+ mBitrate * kPeakBitrateMultiplier,
::base::BindRepeating(&V4L2EncodeComponent::fetchOutputBlock, mWeakThis),
::base::BindRepeating(&V4L2EncodeComponent::onInputBufferDone, mWeakThis),
::base::BindRepeating(&V4L2EncodeComponent::onOutputBufferDone, mWeakThis),
@@ -678,19 +687,10 @@ bool V4L2EncodeComponent::updateEncodingParameters() {
ALOGV("%s()", __func__);
ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
- // Query the interface for the encoding parameters requested by the codec 2.0 framework.
- C2StreamBitrateInfo::output bitrateInfo;
- C2StreamFrameRateInfo::output framerateInfo;
- c2_status_t status =
- mInterface->query({&bitrateInfo, &framerateInfo}, {}, C2_DONT_BLOCK, nullptr);
- if (status != C2_OK) {
- ALOGE("Failed to query interface for encoding parameters (error code: %d)", status);
- reportError(status);
- return false;
- }
-
- // Ask device to change bitrate if it's different from the currently configured bitrate.
- uint32_t bitrate = bitrateInfo.value;
+ // Ask device to change bitrate if it's different from the currently configured bitrate. The C2
+ // framework doesn't offer a parameter to configure the peak bitrate, so we'll use a multiple of
+ // the target bitrate here. The peak bitrate is only used if the bitrate mode is set to VBR.
+ uint32_t bitrate = mInterface->getBitrate();
if (mBitrate != bitrate) {
ALOG_ASSERT(bitrate > 0u);
ALOGV("Setting bitrate to %u", bitrate);
@@ -699,10 +699,17 @@ bool V4L2EncodeComponent::updateEncodingParameters() {
return false;
}
mBitrate = bitrate;
+
+ if (mBitrateMode == C2Config::BITRATE_VARIABLE) {
+ ALOGV("Setting peak bitrate to %u", bitrate * kPeakBitrateMultiplier);
+ // TODO(b/190336806): Our stack doesn't support dynamic peak bitrate changes yet, ignore
+ // errors for now.
+ mEncoder->setPeakBitrate(bitrate * kPeakBitrateMultiplier);
+ }
}
// Ask device to change framerate if it's different from the currently configured framerate.
- uint32_t framerate = static_cast<uint32_t>(std::round(framerateInfo.value));
+ uint32_t framerate = static_cast<uint32_t>(std::round(mInterface->getFramerate()));
if (mFramerate != framerate) {
ALOG_ASSERT(framerate > 0u);
ALOGV("Setting framerate to %u", framerate);
@@ -717,7 +724,7 @@ bool V4L2EncodeComponent::updateEncodingParameters() {
// Check whether an explicit key frame was requested, if so reset the key frame counter to
// immediately request a key frame.
C2StreamRequestSyncFrameTuning::output requestKeyFrame;
- status = mInterface->query({&requestKeyFrame}, {}, C2_DONT_BLOCK, nullptr);
+ c2_status_t status = mInterface->query({&requestKeyFrame}, {}, C2_DONT_BLOCK, nullptr);
if (status != C2_OK) {
ALOGE("Failed to query interface for key frame request (error code: %d)", status);
reportError(status);
diff --git a/components/V4L2EncodeInterface.cpp b/components/V4L2EncodeInterface.cpp
index 7f0fb39..2bdf11b 100644
--- a/components/V4L2EncodeInterface.cpp
+++ b/components/V4L2EncodeInterface.cpp
@@ -310,6 +310,15 @@ void V4L2EncodeInterface::Initialize(const C2String& name) {
.withSetter(Setter<decltype(*mBitrate)>::StrictValueWithNoDeps)
.build());
+ addParameter(
+ DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
+ .withDefault(new C2StreamBitrateModeTuning::output(0u, C2Config::BITRATE_CONST))
+ .withFields(
+ {C2F(mBitrateMode, value)
+ .oneOf({C2Config::BITRATE_CONST, C2Config::BITRATE_VARIABLE})})
+ .withSetter(Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
+ .build());
+
std::string outputMime;
if (getCodecFromComponentName(name) == VideoCodec::H264) {
outputMime = MEDIA_MIMETYPE_VIDEO_AVC;
diff --git a/components/V4L2Encoder.cpp b/components/V4L2Encoder.cpp
index 67d54c8..2dfbe8d 100644
--- a/components/V4L2Encoder.cpp
+++ b/components/V4L2Encoder.cpp
@@ -54,6 +54,7 @@ size_t GetMaxOutputBufferSize(const ui::Size& size) {
std::unique_ptr<VideoEncoder> V4L2Encoder::create(
C2Config::profile_t outputProfile, std::optional<uint8_t> level,
const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod,
+ C2Config::bitrate_mode_t bitrateMode, uint32_t bitrate, std::optional<uint32_t> peakBitrate,
FetchOutputBufferCB fetchOutputBufferCb, InputBufferDoneCB inputBufferDoneCb,
OutputBufferDoneCB outputBufferDoneCb, DrainDoneCB drainDoneCb, ErrorCB errorCb,
scoped_refptr<::base::SequencedTaskRunner> taskRunner) {
@@ -62,7 +63,8 @@ std::unique_ptr<VideoEncoder> V4L2Encoder::create(
std::unique_ptr<V4L2Encoder> encoder = ::base::WrapUnique<V4L2Encoder>(new V4L2Encoder(
std::move(taskRunner), std::move(fetchOutputBufferCb), std::move(inputBufferDoneCb),
std::move(outputBufferDoneCb), std::move(drainDoneCb), std::move(errorCb)));
- if (!encoder->initialize(outputProfile, level, visibleSize, stride, keyFramePeriod)) {
+ if (!encoder->initialize(outputProfile, level, visibleSize, stride, keyFramePeriod, bitrateMode,
+ bitrate, peakBitrate)) {
return nullptr;
}
return encoder;
@@ -161,6 +163,19 @@ bool V4L2Encoder::setBitrate(uint32_t bitrate) {
return true;
}
+bool V4L2Encoder::setPeakBitrate(uint32_t peakBitrate) {
+ ALOGV("%s()", __func__);
+ ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+
+ if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
+ {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, peakBitrate)})) {
+ // TODO(b/190336806): Our stack doesn't support dynamic peak bitrate changes yet, ignore
+ // errors for now.
+ ALOGW("Setting peak bitrate to %u failed", peakBitrate);
+ }
+ return true;
+}
+
bool V4L2Encoder::setFramerate(uint32_t framerate) {
ALOGV("%s()", __func__);
ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
@@ -189,8 +204,9 @@ VideoPixelFormat V4L2Encoder::inputFormat() const {
}
bool V4L2Encoder::initialize(C2Config::profile_t outputProfile, std::optional<uint8_t> level,
- const ui::Size& visibleSize, uint32_t stride,
- uint32_t keyFramePeriod) {
+ const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod,
+ C2Config::bitrate_mode_t bitrateMode, uint32_t bitrate,
+ std::optional<uint32_t> peakBitrate) {
ALOGV("%s()", __func__);
ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
ALOG_ASSERT(keyFramePeriod > 0);
@@ -238,6 +254,12 @@ bool V4L2Encoder::initialize(C2Config::profile_t outputProfile, std::optional<ui
return false;
}
+ // Configure the requested bitrate mode and bitrate on the device.
+ if (!configureBitrateMode(bitrateMode) || !setBitrate(bitrate)) return false;
+
+ // If the bitrate mode is VBR we also need to configure the peak bitrate on the device.
+ if ((bitrateMode == C2Config::BITRATE_VARIABLE) && !setPeakBitrate(*peakBitrate)) return false;
+
// First try to configure the specified output format, as changing the output format can affect
// the configured input format.
if (!configureOutputFormat(outputProfile)) return false;
@@ -637,6 +659,21 @@ bool V4L2Encoder::configureH264(C2Config::profile_t outputProfile,
return true;
}
+bool V4L2Encoder::configureBitrateMode(C2Config::bitrate_mode_t bitrateMode) {
+ ALOGV("%s()", __func__);
+ ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+
+ v4l2_mpeg_video_bitrate_mode v4l2BitrateMode =
+ V4L2Device::C2BitrateModeToV4L2BitrateMode(bitrateMode);
+ if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
+ {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE_MODE, v4l2BitrateMode)})) {
+ // TODO(b/190336806): Our stack doesn't support bitrate mode changes yet. We default to CBR
+ // which is currently the only supported mode so we can safely ignore this for now.
+ ALOGW("Setting bitrate mode to %u failed", v4l2BitrateMode);
+ }
+ return true;
+}
+
bool V4L2Encoder::startDevicePoll() {
ALOGV("%s()", __func__);
ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
diff --git a/components/include/v4l2_codec2/components/V4L2EncodeComponent.h b/components/include/v4l2_codec2/components/V4L2EncodeComponent.h
index 61d43f9..21fe551 100644
--- a/components/include/v4l2_codec2/components/V4L2EncodeComponent.h
+++ b/components/include/v4l2_codec2/components/V4L2EncodeComponent.h
@@ -155,6 +155,8 @@ private:
// The bitrate currently configured on the v4l2 device.
uint32_t mBitrate = 0;
+ // The bitrate mode currently configured on the v4l2 device.
+ C2Config::bitrate_mode_t mBitrateMode = C2Config::BITRATE_CONST;
// The framerate currently configured on the v4l2 device.
uint32_t mFramerate = 0;
// The timestamp of the last frame encoded, used to dynamically adjust the framerate.
diff --git a/components/include/v4l2_codec2/components/V4L2EncodeInterface.h b/components/include/v4l2_codec2/components/V4L2EncodeInterface.h
index 2a2c54c..fefebf0 100644
--- a/components/include/v4l2_codec2/components/V4L2EncodeInterface.h
+++ b/components/include/v4l2_codec2/components/V4L2EncodeInterface.h
@@ -39,8 +39,15 @@ public:
return ui::Size(mInputVisibleSize->width, mInputVisibleSize->height);
}
C2BlockPool::local_id_t getBlockPoolId() const { return mOutputBlockPoolIds->m.values[0]; }
+
// Get sync key-frame period in frames.
uint32_t getKeyFramePeriod() const;
+ // Get the requested bitrate mode.
+ C2Config::bitrate_mode_t getBitrateMode() const { return mBitrateMode->value; }
+ // Get the requested bitrate.
+ uint32_t getBitrate() const { return mBitrate->value; }
+ // Get the requested framerate.
+ float getFramerate() const { return mFrameRate->value; }
// Request changing the framerate to the specified value.
void setFramerate(uint32_t framerate) { mFrameRate->value = framerate; }
@@ -98,6 +105,8 @@ protected:
// The requested bitrate of the encoded output stream, in bits per second.
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+ // The requested bitrate mode.
+ std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
// The requested framerate, in frames per second.
std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
// The switch-type parameter that will be set to true while client requests keyframe. It
diff --git a/components/include/v4l2_codec2/components/V4L2Encoder.h b/components/include/v4l2_codec2/components/V4L2Encoder.h
index 5abee8f..9954232 100644
--- a/components/include/v4l2_codec2/components/V4L2Encoder.h
+++ b/components/include/v4l2_codec2/components/V4L2Encoder.h
@@ -33,9 +33,10 @@ public:
static std::unique_ptr<VideoEncoder> create(
C2Config::profile_t profile, std::optional<uint8_t> level, const ui::Size& visibleSize,
- uint32_t stride, uint32_t keyFramePeriod, FetchOutputBufferCB fetchOutputBufferCb,
- InputBufferDoneCB inputBufferDoneCb, OutputBufferDoneCB outputBufferDoneCb,
- DrainDoneCB drainDoneCb, ErrorCB errorCb,
+ uint32_t stride, uint32_t keyFramePeriod, C2Config::bitrate_mode_t bitrateMode,
+ uint32_t bitrate, std::optional<uint32_t> peakBitrate,
+ FetchOutputBufferCB fetchOutputBufferCb, InputBufferDoneCB inputBufferDoneCb,
+ OutputBufferDoneCB outputBufferDoneCb, DrainDoneCB drainDoneCb, ErrorCB errorCb,
scoped_refptr<::base::SequencedTaskRunner> taskRunner);
~V4L2Encoder() override;
@@ -44,6 +45,7 @@ public:
void flush() override;
bool setBitrate(uint32_t bitrate) override;
+ bool setPeakBitrate(uint32_t peakBitrate) override;
bool setFramerate(uint32_t framerate) override;
void requestKeyframe() override;
@@ -80,7 +82,9 @@ private:
// Initialize the V4L2 encoder for specified parameters.
bool initialize(C2Config::profile_t outputProfile, std::optional<uint8_t> level,
- const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod);
+ const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod,
+ C2Config::bitrate_mode_t bitrateMode, uint32_t bitrate,
+ std::optional<uint32_t> peakBitrate);
// Handle the next encode request on the queue.
void handleEncodeRequest();
@@ -101,6 +105,8 @@ private:
// Configure required and optional H.264 controls on the V4L2 device.
bool configureH264(C2Config::profile_t outputProfile,
std::optional<const uint8_t> outputH264Level);
+ // Configure the specified bitrate mode on the V4L2 device.
+ bool configureBitrateMode(C2Config::bitrate_mode_t bitrateMode);
// Attempt to start the V4L2 device poller.
bool startDevicePoll();
diff --git a/components/include/v4l2_codec2/components/VideoEncoder.h b/components/include/v4l2_codec2/components/VideoEncoder.h
index 46bcad1..5f23541 100644
--- a/components/include/v4l2_codec2/components/VideoEncoder.h
+++ b/components/include/v4l2_codec2/components/VideoEncoder.h
@@ -64,8 +64,12 @@ public:
// Flush the encoder, pending drain operations will be aborted.
virtual void flush() = 0;
- // Set the bitrate to the specified value, will affect all non-processed frames.
+ // Set the target bitrate to the specified value, will affect all non-processed frames.
virtual bool setBitrate(uint32_t bitrate) = 0;
+ // Set the peak bitrate to the specified value. The peak bitrate must be larger or equal to the
+ // target bitrate and is ignored if the bitrate mode is constant.
+ virtual bool setPeakBitrate(uint32_t peakBitrate) = 0;
+
// Set the framerate to the specified value, will affect all non-processed frames.
virtual bool setFramerate(uint32_t framerate) = 0;
// Request the next frame encoded to be a key frame, will affect the next non-processed frame.