Commit 24156892 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/v4l2VEA: Scale a given VideoFrame if needed

V4L2VEA has been able to work in Zero-Copy mode when a given
VideoFrame's dimension is the same as a resolution configured in
Initialize(). This is sufficient to enable Zero-Copy capture in
ARC++ case.

To enable Zero-Copy capture in chrome case, it is necessary to
scale VideoFrame for Simulcast case. This CL enables V4L2VEA
to scale VideoFrame by using ImageProcessor interface.

See https://tinyurl.com/frame-dimension-in-VEA
for how V4L2VEA works.

Bug: chromium:1033799, chromium:982201
Test: Hangout Meet on scarlet (with crrev.com/c/1923767 and crrev.com/c/2007802)
Test: VEA test on kukui
Change-Id: I07d5abfca0f5dd7c4adcfc10191316c5ba3021de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2010466
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarAlexandre Courbot <acourbot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740587}
parent 11125245
...@@ -296,13 +296,16 @@ void V4L2VideoEncodeAccelerator::InitializeTask(const Config& config, ...@@ -296,13 +296,16 @@ void V4L2VideoEncodeAccelerator::InitializeTask(const Config& config,
config.initial_bitrate, config.initial_framerate.value_or( config.initial_bitrate, config.initial_framerate.value_or(
VideoEncodeAccelerator::kDefaultFramerate)); VideoEncodeAccelerator::kDefaultFramerate));
const gfx::Size input_size = image_processor_.get() // input_frame_size_ is the size of input_config of |image_processor_|.
? image_processor_->input_config().size // On native_input_mode_, since the passed size in RequireBitstreamBuffers()
: input_frame_size_; // is ignored by the client, we don't update the expected frame size.
if (!native_input_mode_ && image_processor_.get())
input_frame_size_ = image_processor_->input_config().size;
child_task_runner_->PostTask( child_task_runner_->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(&Client::RequireBitstreamBuffers, client_,
base::BindOnce(&Client::RequireBitstreamBuffers, client_, kInputBufferCount, input_frame_size_,
kInputBufferCount, input_size, output_buffer_byte_size_)); output_buffer_byte_size_));
// Finish initialization. // Finish initialization.
*result = true; *result = true;
...@@ -685,69 +688,50 @@ bool V4L2VideoEncodeAccelerator::ReconfigureFormatIfNeeded( ...@@ -685,69 +688,50 @@ bool V4L2VideoEncodeAccelerator::ReconfigureFormatIfNeeded(
const VideoFrame& frame) { const VideoFrame& frame) {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
// We should apply the frame size change to ImageProcessor if there is. if (!native_input_mode_) {
if (image_processor_) { // frame.coded_size() must be the size specified in
// Stride is the same. There is no need of executing S_FMT again. // RequireBitstreamBuffers() in non native-input mode.
if (image_processor_->input_config().size == frame.coded_size()) { return frame.coded_size() == input_frame_size_;
return true; }
}
VLOGF(2) << "Call S_FMT with a new size=" << frame.coded_size().ToString() if (!input_buffer_map_.empty()) {
<< ", the previous size =" if (frame.coded_size() != input_frame_size_) {
<< device_input_layout_->coded_size().ToString();
if (!input_buffer_map_.empty()) {
VLOGF(1) << "Input frame size is changed during encoding"; VLOGF(1) << "Input frame size is changed during encoding";
NOTIFY_ERROR(kInvalidArgumentError);
return false;
}
if (!CreateImageProcessor(frame.layout(), *device_input_layout_,
frame.visible_rect(),
encoder_input_visible_rect_)) {
NOTIFY_ERROR(kPlatformFailureError);
return false;
}
if (image_processor_->input_config().size.width() !=
frame.coded_size().width()) {
NOTIFY_ERROR(kPlatformFailureError);
return false; return false;
} }
return true; return true;
} }
// Here we should compare |device_input_layout_->coded_size()|. However, VEA // Height and width that V4L2VEA needs to configure.
// requests a client |input_frame_size_|, which might be a larger size than const gfx::Size buffer_size(frame.stride(0), frame.coded_size().height());
// |device_input_layout_->coded_size()|. The size is larger if there is an if (frame.coded_size() == input_frame_size_) {
// extra data in planes, that happens on MediaTek. // A buffer given by client is allocated with the same dimension using
// This comparison will work because VEAClient within Chrome gives the buffer // minigbm. However, it is possible that stride and height are different
// whose frame size as |input_frame_size_|. VEAClient for ARC++ might give a // from ones adjusted by a driver.
// different frame size but |input_frame_size_| is always the same as if (!image_processor_) {
// |device_input_layout_->coded_size()|. if (device_input_layout_->coded_size().width() == buffer_size.width() &&
if (frame.coded_size() != input_frame_size_) { device_input_layout_->coded_size().height() == buffer_size.height()) {
VLOGF(2) << "Call S_FMT with a new size=" << frame.coded_size().ToString() return true;
<< ", the previous size =" }
<< device_input_layout_->coded_size().ToString() return NegotiateInputFormat(device_input_layout_->format(), buffer_size);
<< " (the size requested to client="
<< input_frame_size_.ToString();
if (!input_buffer_map_.empty()) {
VLOGF(1) << "Input frame size is changed during encoding";
NOTIFY_ERROR(kInvalidArgumentError);
return false;
}
if (!NegotiateInputFormat(device_input_layout_->format(),
frame.coded_size())) {
NOTIFY_ERROR(kPlatformFailureError);
return false;
} }
if (device_input_layout_->coded_size().width() !=
frame.coded_size().width()) { if (image_processor_->input_config().size.height() ==
NOTIFY_ERROR(kPlatformFailureError); buffer_size.height() &&
return false; image_processor_->input_config().planes[0].stride ==
buffer_size.width()) {
return true;
} }
} }
return true; // The |frame| dimension is different from the resolution configured to
// V4L2VEA. This is the case that V4L2VEA needs to create ImageProcessor for
// scaling. Update |input_frame_size_| to check if succeeding frames'
// dimensions are not different from one of the first frame.
input_frame_size_ = frame.coded_size();
return CreateImageProcessor(frame.layout(), *device_input_layout_,
frame.visible_rect(),
encoder_input_visible_rect_);
} }
void V4L2VideoEncodeAccelerator::InputImageProcessorTask() { void V4L2VideoEncodeAccelerator::InputImageProcessorTask() {
...@@ -1375,9 +1359,8 @@ bool V4L2VideoEncodeAccelerator::NegotiateInputFormat( ...@@ -1375,9 +1359,8 @@ bool V4L2VideoEncodeAccelerator::NegotiateInputFormat(
return false; return false;
} }
if (native_input_mode_) { if (native_input_mode_) {
input_frame_size_ = input_frame_size_ = VideoFrame::DetermineAlignedSize(
gfx::Size(device_input_layout_->planes()[0].stride, input_format, encoder_input_visible_rect_.size());
device_input_layout_->coded_size().height());
} else { } else {
input_frame_size_ = V4L2Device::AllocatedSizeFromV4L2Format(*format); input_frame_size_ = V4L2Device::AllocatedSizeFromV4L2Format(*format);
} }
......
...@@ -201,8 +201,8 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator ...@@ -201,8 +201,8 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator
bool SetFormats(VideoPixelFormat input_format, bool SetFormats(VideoPixelFormat input_format,
VideoCodecProfile output_profile); VideoCodecProfile output_profile);
// Reconfigure format of input buffers and image processor if frame size // Reconfigure format of input buffers and image processor if the buffer
// given by client is different from one set in input buffers. // represented by |frame| is different from one set in input buffers.
bool ReconfigureFormatIfNeeded(const VideoFrame& frame); bool ReconfigureFormatIfNeeded(const VideoFrame& frame);
// Try to set up the device to the input format we were Initialized() with, // Try to set up the device to the input format we were Initialized() with,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment