Commit ead8f96b authored by kcwu's avatar kcwu Committed by Commit bot

Fix visible size for V4L2 VDA

Note this CL depends on s5p-mfc kernel driver fix https://chromium.googlesource.com/chromiumos/third_party/kernel/+/090b79f, which is available since 6840.0.0
Otherwise exynos chromeos will crash.

BUG=chromium:449920
TEST=apprtc loopback with resolution 640x354 on peach pit; run run video_VideoSanity

Review URL: https://codereview.chromium.org/972063002

Cr-Commit-Position: refs/heads/master@{#319059}
parent 240be555
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/filters/h264_parser.h" #include "media/filters/h264_parser.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gl/scoped_binders.h" #include "ui/gl/scoped_binders.h"
#define NOTIFY_ERROR(x) \ #define NOTIFY_ERROR(x) \
...@@ -339,7 +340,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( ...@@ -339,7 +340,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
// thread is waiting on pictures_assigned_. // thread is waiting on pictures_assigned_.
DCHECK(free_output_buffers_.empty()); DCHECK(free_output_buffers_.empty());
for (size_t i = 0; i < output_buffer_map_.size(); ++i) { for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
DCHECK(buffers[i].size() == frame_buffer_size_); DCHECK(buffers[i].size() == coded_size_);
OutputRecord& output_record = output_buffer_map_[i]; OutputRecord& output_record = output_buffer_map_[i];
DCHECK(!output_record.at_device); DCHECK(!output_record.at_device);
...@@ -352,7 +353,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( ...@@ -352,7 +353,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers(
EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_,
egl_context_, egl_context_,
buffers[i].texture_id(), buffers[i].texture_id(),
frame_buffer_size_, coded_size_,
i, i,
output_format_fourcc_, output_format_fourcc_,
output_planes_count_); output_planes_count_);
...@@ -729,8 +730,9 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial( ...@@ -729,8 +730,9 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(
// Check and see if we have format info yet. // Check and see if we have format info yet.
struct v4l2_format format; struct v4l2_format format;
gfx::Size visible_size;
bool again = false; bool again = false;
if (!GetFormatInfo(&format, &again)) if (!GetFormatInfo(&format, &visible_size, &again))
return false; return false;
if (again) { if (again) {
...@@ -743,7 +745,7 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial( ...@@ -743,7 +745,7 @@ bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(
if (decoder_state_ == kInitialized) { if (decoder_state_ == kInitialized) {
DVLOG(3) << "DecodeBufferInitial(): running initialization"; DVLOG(3) << "DecodeBufferInitial(): running initialization";
// Success! Setup our parameters. // Success! Setup our parameters.
if (!CreateBuffersForFormat(format)) if (!CreateBuffersForFormat(format, visible_size))
return false; return false;
// We expect to process the initial buffer once during stream init to // We expect to process the initial buffer once during stream init to
...@@ -1085,7 +1087,7 @@ void V4L2VideoDecodeAccelerator::Dequeue() { ...@@ -1085,7 +1087,7 @@ void V4L2VideoDecodeAccelerator::Dequeue() {
<< " as picture_id=" << output_record.picture_id; << " as picture_id=" << output_record.picture_id;
const media::Picture& picture = const media::Picture& picture =
media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec, media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec,
gfx::Rect(frame_buffer_size_), false); gfx::Rect(visible_size_), false);
pending_picture_ready_.push( pending_picture_ready_.push(
PictureRecord(output_record.cleared, picture)); PictureRecord(output_record.cleared, picture));
SendPictureReady(); SendPictureReady();
...@@ -1533,14 +1535,15 @@ void V4L2VideoDecodeAccelerator::FinishResolutionChange() { ...@@ -1533,14 +1535,15 @@ void V4L2VideoDecodeAccelerator::FinishResolutionChange() {
struct v4l2_format format; struct v4l2_format format;
bool again; bool again;
bool ret = GetFormatInfo(&format, &again); gfx::Size visible_size;
bool ret = GetFormatInfo(&format, &visible_size, &again);
if (!ret || again) { if (!ret || again) {
LOG(ERROR) << "Couldn't get format information after resolution change"; LOG(ERROR) << "Couldn't get format information after resolution change";
NOTIFY_ERROR(PLATFORM_FAILURE); NOTIFY_ERROR(PLATFORM_FAILURE);
return; return;
} }
if (!CreateBuffersForFormat(format)) { if (!CreateBuffersForFormat(format, visible_size)) {
LOG(ERROR) << "Couldn't reallocate buffers after resolution change"; LOG(ERROR) << "Couldn't reallocate buffers after resolution change";
NOTIFY_ERROR(PLATFORM_FAILURE); NOTIFY_ERROR(PLATFORM_FAILURE);
return; return;
...@@ -1615,7 +1618,8 @@ void V4L2VideoDecodeAccelerator::SetErrorState(Error error) { ...@@ -1615,7 +1618,8 @@ void V4L2VideoDecodeAccelerator::SetErrorState(Error error) {
} }
bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format, bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format,
bool* again) { gfx::Size* visible_size,
bool* again) {
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
*again = false; *again = false;
...@@ -1639,17 +1643,23 @@ bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format, ...@@ -1639,17 +1643,23 @@ bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format,
return false; return false;
} }
gfx::Size coded_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
if (visible_size != nullptr)
*visible_size = GetVisibleSize(coded_size);
return true; return true;
} }
bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat(
const struct v4l2_format& format) { const struct v4l2_format& format,
const gfx::Size& visible_size) {
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
output_planes_count_ = format.fmt.pix_mp.num_planes; output_planes_count_ = format.fmt.pix_mp.num_planes;
frame_buffer_size_.SetSize( coded_size_.SetSize(format.fmt.pix_mp.width, format.fmt.pix_mp.height);
format.fmt.pix_mp.width, format.fmt.pix_mp.height); visible_size_ = visible_size;
DVLOG(3) << "CreateBuffersForFormat(): new resolution: " DVLOG(3) << "CreateBuffersForFormat(): new resolution: "
<< frame_buffer_size_.ToString(); << coded_size_.ToString() << ", visible size: "
<< visible_size_.ToString();
if (!CreateOutputBuffers()) if (!CreateOutputBuffers())
return false; return false;
...@@ -1657,6 +1667,42 @@ bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( ...@@ -1657,6 +1667,42 @@ bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat(
return true; return true;
} }
gfx::Size V4L2VideoDecodeAccelerator::GetVisibleSize(
const gfx::Size& coded_size) {
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
struct v4l2_crop crop_arg;
memset(&crop_arg, 0, sizeof(crop_arg));
crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
if (device_->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
PLOG(ERROR) << "GetVisibleSize(): ioctl() VIDIOC_G_CROP failed";
return coded_size;
}
gfx::Rect rect(crop_arg.c.left, crop_arg.c.top, crop_arg.c.width,
crop_arg.c.height);
DVLOG(3) << "visible rectangle is " << rect.ToString();
if (!gfx::Rect(coded_size).Contains(rect)) {
DLOG(ERROR) << "visible rectangle " << rect.ToString()
<< " is not inside coded size " << coded_size.ToString();
return coded_size;
}
if (rect.IsEmpty()) {
DLOG(ERROR) << "visible size is empty";
return coded_size;
}
// Chrome assume picture frame is coded at (0, 0).
if (!rect.origin().IsOrigin()) {
DLOG(ERROR) << "Unexpected visible rectangle " << rect.ToString()
<< ", top-left is not origin";
return coded_size;
}
return rect.size();
}
bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { bool V4L2VideoDecodeAccelerator::CreateInputBuffers() {
DVLOG(3) << "CreateInputBuffers()"; DVLOG(3) << "CreateInputBuffers()";
// We always run this as we prepare to initialize. // We always run this as we prepare to initialize.
...@@ -1786,13 +1832,12 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { ...@@ -1786,13 +1832,12 @@ bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() {
DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): "
<< "buffer_count=" << output_buffer_map_.size() << "buffer_count=" << output_buffer_map_.size()
<< ", width=" << frame_buffer_size_.width() << ", coded_size=" << coded_size_.ToString();
<< ", height=" << frame_buffer_size_.height();
child_message_loop_proxy_->PostTask(FROM_HERE, child_message_loop_proxy_->PostTask(FROM_HERE,
base::Bind(&Client::ProvidePictureBuffers, base::Bind(&Client::ProvidePictureBuffers,
client_, client_,
output_buffer_map_.size(), output_buffer_map_.size(),
frame_buffer_size_, coded_size_,
device_->GetTextureTarget())); device_->GetTextureTarget()));
// Wait for the client to call AssignPictureBuffers() on the Child thread. // Wait for the client to call AssignPictureBuffers() on the Child thread.
...@@ -1966,14 +2011,14 @@ bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() { ...@@ -1966,14 +2011,14 @@ bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() {
} }
struct v4l2_format format; struct v4l2_format format;
bool again = false; bool again = false;
bool ret = GetFormatInfo(&format, &again); bool ret = GetFormatInfo(&format, nullptr, &again);
if (!ret || again) { if (!ret || again) {
DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed";
return false; return false;
} }
gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), gfx::Size new_coded_size(base::checked_cast<int>(format.fmt.pix_mp.width),
base::checked_cast<int>(format.fmt.pix_mp.height)); base::checked_cast<int>(format.fmt.pix_mp.height));
if (frame_buffer_size_ != new_size) { if (coded_size_ != new_coded_size) {
DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected";
return true; return true;
} }
......
...@@ -242,11 +242,19 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator ...@@ -242,11 +242,19 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
void StartResolutionChangeIfNeeded(); void StartResolutionChangeIfNeeded();
void FinishResolutionChange(); void FinishResolutionChange();
// Try to get output format, detected after parsing the beginning // Try to get output format and visible size, detected after parsing the
// of the stream. Sets |again| to true if more parsing is needed. // beginning of the stream. Sets |again| to true if more parsing is needed.
bool GetFormatInfo(struct v4l2_format* format, bool* again); // |visible_size| could be nullptr and ignored.
// Create output buffers for the given |format|. bool GetFormatInfo(struct v4l2_format* format,
bool CreateBuffersForFormat(const struct v4l2_format& format); gfx::Size* visible_size,
bool* again);
// Create output buffers for the given |format| and |visible_size|.
bool CreateBuffersForFormat(const struct v4l2_format& format,
const gfx::Size& visible_size);
// Try to get |visible_size|. Return visible size, or, if querying it is not
// supported or produces invalid size, return |coded_size| instead.
gfx::Size GetVisibleSize(const gfx::Size& coded_size);
// //
// Device tasks, to be run on device_poll_thread_. // Device tasks, to be run on device_poll_thread_.
...@@ -415,8 +423,11 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator ...@@ -415,8 +423,11 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator
// to avoid races with potential Reset requests. // to avoid races with potential Reset requests.
base::WaitableEvent pictures_assigned_; base::WaitableEvent pictures_assigned_;
// Output picture size. // Output picture coded size.
gfx::Size frame_buffer_size_; gfx::Size coded_size_;
// Output picture visible size.
gfx::Size visible_size_;
// //
// The device polling thread handles notifications of V4L2 device changes. // The device polling thread handles notifications of V4L2 device changes.
......
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