Commit 5f54287a authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/chromeos/LibyuvIP: Support NV12Scale

Bug: 1033799
Test: image_processor_test on kukui
Change-Id: I5857332393313e5f6aa33fbc1ac505279dd9bc54
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2007802
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarAlexandre Courbot <acourbot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735777}
parent 3a66cf46
......@@ -170,14 +170,6 @@ TEST_P(ImageProcessorParamTest, ConvertOneTime_MemToMem) {
test::Image output_image(std::get<1>(GetParam()));
ASSERT_TRUE(input_image.Load());
ASSERT_TRUE(output_image.LoadMetadata());
if (input_image.PixelFormat() == output_image.PixelFormat()) {
// If the input format is the same as the output format, then the conversion
// is scaling. LibyuvImageProcessorBackend doesn't support scaling yet. So
// skip this test case.
// TODO(hiroh): Remove this skip once LibyuvIP supports scaling.
GTEST_SKIP();
}
auto ip_client = CreateImageProcessorClient(
input_image, {VideoFrame::STORAGE_OWNED_MEMORY}, &output_image,
{VideoFrame::STORAGE_OWNED_MEMORY});
......@@ -201,14 +193,6 @@ TEST_P(ImageProcessorParamTest, ConvertOneTime_DmabufToMem) {
test::Image output_image(std::get<1>(GetParam()));
ASSERT_TRUE(input_image.Load());
ASSERT_TRUE(output_image.LoadMetadata());
if (input_image.PixelFormat() == output_image.PixelFormat()) {
// If the input format is the same as the output format, then the conversion
// is scaling. LibyuvImageProcessorBackend doesn't support scaling yet. So
// skip this test case.
// TODO(hiroh): Remove this skip once LibyuvIP supports scaling.
GTEST_SKIP();
}
auto ip_client = CreateImageProcessorClient(
input_image, {VideoFrame::STORAGE_DMABUFS}, &output_image,
{VideoFrame::STORAGE_OWNED_MEMORY});
......
......@@ -12,11 +12,66 @@
#include "third_party/libyuv/include/libyuv/convert.h"
#include "third_party/libyuv/include/libyuv/convert_from.h"
#include "third_party/libyuv/include/libyuv/convert_from_argb.h"
#include "third_party/libyuv/include/libyuv/scale.h"
namespace media {
namespace {
// TODO(https://bugs.chromium.org/p/libyuv/issues/detail?id=838): Remove
// this once libyuv implements NV12Scale and use the libyuv::NV12Scale().
// This is copy-pasted from
// third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h.
void NV12Scale(uint8_t* tmp_buffer,
const uint8_t* src_y,
int src_stride_y,
const uint8_t* src_uv,
int src_stride_uv,
int src_width,
int src_height,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_uv,
int dst_stride_uv,
int dst_width,
int dst_height) {
const int src_chroma_width = (src_width + 1) / 2;
const int src_chroma_height = (src_height + 1) / 2;
if (src_width == dst_width && src_height == dst_height) {
// No scaling.
libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_width,
src_height);
libyuv::CopyPlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv,
src_chroma_width * 2, src_chroma_height);
return;
}
// Scaling.
// Allocate temporary memory for spitting UV planes and scaling them.
const int dst_chroma_width = (dst_width + 1) / 2;
const int dst_chroma_height = (dst_height + 1) / 2;
uint8_t* const src_u = tmp_buffer;
uint8_t* const src_v = src_u + src_chroma_width * src_chroma_height;
uint8_t* const dst_u = src_v + src_chroma_width * src_chroma_height;
uint8_t* const dst_v = dst_u + dst_chroma_width * dst_chroma_height;
// Split source UV plane into separate U and V plane using the temporary data.
libyuv::SplitUVPlane(src_uv, src_stride_uv, src_u, src_chroma_width, src_v,
src_chroma_width, src_chroma_width, src_chroma_height);
// Scale the planes.
libyuv::I420Scale(
src_y, src_stride_y, src_u, src_chroma_width, src_v, src_chroma_width,
src_width, src_height, dst_y, dst_stride_y, dst_u, dst_chroma_width,
dst_v, dst_chroma_width, dst_width, dst_height, libyuv::kFilterBox);
// Merge the UV planes into the destination.
libyuv::MergeUVPlane(dst_u, dst_chroma_width, dst_v, dst_chroma_width, dst_uv,
dst_stride_uv, dst_chroma_width, dst_chroma_height);
}
enum class SupportResult {
Supported,
SupportedWithPivot,
......@@ -29,9 +84,14 @@ SupportResult IsFormatSupported(Fourcc input_fourcc, Fourcc output_fourcc) {
uint32_t output;
bool need_pivot;
} kSupportFormatConversionArray[] = {
{Fourcc::AR24, Fourcc::NV12, false}, {Fourcc::YU12, Fourcc::NV12, false},
{Fourcc::YV12, Fourcc::NV12, false}, {Fourcc::AB24, Fourcc::NV12, true},
// Conversion.
{Fourcc::AR24, Fourcc::NV12, false},
{Fourcc::YU12, Fourcc::NV12, false},
{Fourcc::YV12, Fourcc::NV12, false},
{Fourcc::AB24, Fourcc::NV12, true},
{Fourcc::XB24, Fourcc::NV12, true},
// Scaling.
{Fourcc::NV12, Fourcc::NV12, true},
};
const auto single_input_fourcc = input_fourcc.ToSinglePlanar();
......@@ -133,8 +193,28 @@ std::unique_ptr<ImageProcessorBackend> LibYUVImageProcessorBackend::Create(
return nullptr;
}
scoped_refptr<VideoFrame> intermediate_frame;
if (input_config.fourcc.ToVideoPixelFormat() ==
output_config.fourcc.ToVideoPixelFormat()) {
if (input_config.visible_rect.origin() != gfx::Point(0, 0) ||
output_config.visible_rect.origin() != gfx::Point(0, 0)) {
VLOGF(2) << "Visible rectangle is not (0, 0), "
<< "input_config.visible_rect="
<< input_config.visible_rect.ToString()
<< "output_config.visible_rect="
<< output_config.visible_rect.ToString();
return nullptr;
}
// Down-scaling support only.
// This restriction is to simplify |intermediate_frame_| creation. It is
// used as |tmp_buffer| in NV12Scale().
// TODO(hiroh): Remove this restriction once libyuv:NV12Scale() is arrived.
if (!input_config.visible_rect.Contains(output_config.visible_rect)) {
VLOGF(2) << "Down-scaling support only";
return nullptr;
}
}
scoped_refptr<VideoFrame> intermediate_frame;
if (res == SupportResult::SupportedWithPivot) {
intermediate_frame = VideoFrame::CreateFrame(
PIXEL_FORMAT_I420, input_config.visible_rect.size(),
......@@ -271,6 +351,17 @@ int LibYUVImageProcessorBackend::DoConversion(const VideoFrame* const input,
Y_U_V_DATA(intermediate_frame_));
return LIBYUV_FUNC(I420ToNV12, Y_U_V_DATA(intermediate_frame_),
Y_UV_DATA(output));
case PIXEL_FORMAT_NV12:
// The size of |tmp_buffer| of NV12Scale() should be
// input_visible_rect().GetArea() / 2 +
// output_visible_rect().GetArea() / 2. Although |intermediate_frame_|
// is much larger than the required size, we use the frame to simplify
// the code.
NV12Scale(intermediate_frame_->data(0), Y_UV_DATA(input),
input->visible_rect().width(), input->visible_rect().height(),
Y_UV_DATA(output), output->visible_rect().width(),
output->visible_rect().height());
return 0;
default:
VLOGF(1) << "Unexpected input format: " << input->format();
return -1;
......
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