Commit 029544da authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Commit Bot

media/gpu/v4l2: workaround VIDIOC_G_FMT bug in libtegrav4l2.so.

libtegrav4l2.so's implementation of V4L2_G_FMT has a bug which will make
it return 0 planes for single-plane multiplanar formats. We obviously
cannot have a multiplanar format with 0 planes, so add a workaround at
the fake-ioctl level. Implement it as a case-switch for future-proofing
against other workarounds we will likely have to add.

Also add a few recommendations in v4l2_device.cc against the temptation
to spare some memory by using an appropriately-sized array of
v4l2_planes: it turns out libv4l2 also likes to write above the number
of passed planes, and using anything shorter than VIDEO_MAX_PLANES will
result in memory corruption DCHECKS being raised.

BUG=893661
TEST=Checked that VDA unittest was passing on both hana and nyan_big.

Change-Id: I7ea638f19f5bf0bdfaa0a47885577eb9dec4c225
Reviewed-on: https://chromium-review.googlesource.com/c/1275727
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Reviewed-by: default avatarKuang-che Wu <kcwu@chromium.org>
Reviewed-by: default avatarHirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#599135}
parent df554d02
......@@ -61,7 +61,25 @@ TegraV4L2Device::~TegraV4L2Device() {
}
int TegraV4L2Device::Ioctl(int flags, void* arg) {
return HANDLE_EINTR(TegraV4L2_Ioctl(device_fd_, flags, arg));
int ret = HANDLE_EINTR(TegraV4L2_Ioctl(device_fd_, flags, arg));
if (ret)
return ret;
// Workarounds for Tegra's broken closed-source V4L2 interface.
struct v4l2_format* format;
switch (flags) {
// VIDIOC_G_FMT returns 0 planes for multiplanar formats with 1 plane.
case static_cast<int>(VIDIOC_G_FMT):
format = static_cast<struct v4l2_format*>(arg);
if (V4L2_TYPE_IS_MULTIPLANAR(format->type) &&
format->fmt.pix_mp.num_planes == 0)
format->fmt.pix_mp.num_planes = 1;
break;
default:
break;
}
return 0;
}
bool TegraV4L2Device::Poll(bool poll_device, bool* event_pending) {
......
......@@ -58,6 +58,9 @@ class V4L2Buffer {
// V4L2 data as queried by QUERYBUF.
struct v4l2_buffer v4l2_buffer_ = {};
// WARNING: do not change this to a vector or something smaller than
// VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
// the number of allocated planes, resulting in memory corruption.
struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES] = {{}};
DISALLOW_COPY_AND_ASSIGN(V4L2Buffer);
......@@ -162,6 +165,9 @@ class V4L2BufferQueueProxy {
// Data from the buffer, that users can query and/or write.
struct v4l2_buffer v4l2_buffer_;
// WARNING: do not change this to a vector or something smaller than
// VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
// the number of allocated planes, resulting in memory corruption.
struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
private:
......@@ -670,6 +676,9 @@ std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::DequeueBuffer() {
}
struct v4l2_buffer v4l2_buffer = {};
// WARNING: do not change this to a vector or something smaller than
// VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
// the number of allocated planes, resulting in memory corruption.
struct v4l2_plane planes[VIDEO_MAX_PLANES] = {{}};
v4l2_buffer.type = type_;
v4l2_buffer.memory = memory_;
......
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