summaryrefslogtreecommitdiff
path: root/chromium/media/renderers/shared_image_video_frame_test_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/renderers/shared_image_video_frame_test_utils.cc')
-rw-r--r--chromium/media/renderers/shared_image_video_frame_test_utils.cc254
1 files changed, 254 insertions, 0 deletions
diff --git a/chromium/media/renderers/shared_image_video_frame_test_utils.cc b/chromium/media/renderers/shared_image_video_frame_test_utils.cc
new file mode 100644
index 00000000000..9b36170d6c1
--- /dev/null
+++ b/chromium/media/renderers/shared_image_video_frame_test_utils.cc
@@ -0,0 +1,254 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/renderers/shared_image_video_frame_test_utils.h"
+
+#include "base/logging.h"
+#include "components/viz/common/gpu/context_provider.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface_stub.h"
+#include "gpu/command_buffer/client/shared_image_interface.h"
+#include "gpu/command_buffer/common/capabilities.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+
+namespace media {
+
+namespace {
+
+static constexpr const uint8_t kYuvColors[8][3] = {
+ {0x00, 0x80, 0x80}, // Black
+ {0x4c, 0x54, 0xff}, // Red
+ {0x95, 0x2b, 0x15}, // Green
+ {0xe1, 0x00, 0x94}, // Yellow
+ {0x1d, 0xff, 0x6b}, // Blue
+ {0x69, 0xd3, 0xec}, // Magenta
+ {0xb3, 0xaa, 0x00}, // Cyan
+ {0xff, 0x80, 0x80}, // White
+};
+
+// Destroys a list of shared images after a sync token is passed. Also runs
+// |callback|.
+void DestroySharedImages(scoped_refptr<viz::ContextProvider> context_provider,
+ std::vector<gpu::Mailbox> mailboxes,
+ base::OnceClosure callback,
+ const gpu::SyncToken& sync_token) {
+ auto* sii = context_provider->SharedImageInterface();
+ for (const auto& mailbox : mailboxes)
+ sii->DestroySharedImage(sync_token, mailbox);
+ std::move(callback).Run();
+}
+
+// Upload pixels to a shared image using GL.
+void UploadPixels(gpu::gles2::GLES2Interface* gl,
+ const gpu::Mailbox& mailbox,
+ const gfx::Size& size,
+ GLenum format,
+ GLenum type,
+ const uint8_t* data) {
+ GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
+ gl->BeginSharedImageAccessDirectCHROMIUM(
+ texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
+ gl->BindTexture(GL_TEXTURE_2D, texture);
+ gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), format,
+ type, data);
+ gl->EndSharedImageAccessDirectCHROMIUM(texture);
+ gl->DeleteTextures(1, &texture);
+}
+
+} // namespace
+
+scoped_refptr<VideoFrame> CreateSharedImageFrame(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ VideoPixelFormat format,
+ std::vector<gpu::Mailbox> mailboxes,
+ const gpu::SyncToken& sync_token,
+ GLenum texture_target,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size,
+ base::TimeDelta timestamp,
+ base::OnceClosure destroyed_callback) {
+ gpu::MailboxHolder mailboxes_for_frame[VideoFrame::kMaxPlanes] = {};
+ size_t i = 0;
+ for (const auto& mailbox : mailboxes) {
+ mailboxes_for_frame[i++] =
+ gpu::MailboxHolder(mailbox, sync_token, texture_target);
+ }
+ auto callback =
+ base::BindOnce(&DestroySharedImages, std::move(context_provider),
+ std::move(mailboxes), std::move(destroyed_callback));
+ return VideoFrame::WrapNativeTextures(format, mailboxes_for_frame,
+ std::move(callback), coded_size,
+ visible_rect, natural_size, timestamp);
+}
+
+scoped_refptr<VideoFrame> CreateSharedImageRGBAFrame(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ base::OnceClosure destroyed_callback) {
+ DCHECK_EQ(coded_size.width() % 4, 0);
+ DCHECK_EQ(coded_size.height() % 2, 0);
+ size_t pixels_size = coded_size.GetArea() * 4;
+ auto pixels = std::make_unique<uint8_t[]>(pixels_size);
+ size_t i = 0;
+ for (size_t block_y = 0; block_y < 2u; ++block_y) {
+ for (int y = 0; y < coded_size.height() / 2; ++y) {
+ for (size_t block_x = 0; block_x < 4u; ++block_x) {
+ for (int x = 0; x < coded_size.width() / 4; ++x) {
+ pixels[i++] = 0xffu * (block_x % 2); // R
+ pixels[i++] = 0xffu * (block_x / 2); // G
+ pixels[i++] = 0xffu * block_y; // B
+ pixels[i++] = 0xffu; // A
+ }
+ }
+ }
+ }
+ DCHECK_EQ(i, pixels_size);
+
+ auto* sii = context_provider->SharedImageInterface();
+ gpu::Mailbox mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::RGBA_8888, coded_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ auto* gl = context_provider->ContextGL();
+ gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
+ UploadPixels(gl, mailbox, coded_size, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels.get());
+ gpu::SyncToken sync_token;
+ gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+
+ return CreateSharedImageFrame(
+ std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_ABGR,
+ {mailbox}, sync_token, GL_TEXTURE_2D, coded_size, visible_rect,
+ visible_rect.size(), base::TimeDelta::FromSeconds(1),
+ std::move(destroyed_callback));
+}
+
+scoped_refptr<VideoFrame> CreateSharedImageI420Frame(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ base::OnceClosure destroyed_callback) {
+ DCHECK_EQ(coded_size.width() % 8, 0);
+ DCHECK_EQ(coded_size.height() % 4, 0);
+ gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2);
+ size_t y_pixels_size = coded_size.GetArea();
+ size_t uv_pixels_size = uv_size.GetArea();
+ auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size);
+ auto u_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
+ auto v_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
+ size_t y_i = 0;
+ size_t uv_i = 0;
+ for (size_t block_y = 0; block_y < 2u; ++block_y) {
+ for (int y = 0; y < coded_size.height() / 2; ++y) {
+ for (size_t block_x = 0; block_x < 4u; ++block_x) {
+ size_t color_index = block_x + block_y * 4;
+ const uint8_t* yuv = kYuvColors[color_index];
+ for (int x = 0; x < coded_size.width() / 4; ++x) {
+ y_pixels[y_i++] = yuv[0];
+ if ((x % 2) && (y % 2)) {
+ u_pixels[uv_i] = yuv[1];
+ v_pixels[uv_i++] = yuv[2];
+ }
+ }
+ }
+ }
+ }
+ DCHECK_EQ(y_i, y_pixels_size);
+ DCHECK_EQ(uv_i, uv_pixels_size);
+
+ auto* sii = context_provider->SharedImageInterface();
+ gpu::Mailbox y_mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::LUMINANCE_8, coded_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ gpu::Mailbox u_mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::LUMINANCE_8, uv_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ gpu::Mailbox v_mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::LUMINANCE_8, uv_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ auto* gl = context_provider->ContextGL();
+ gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
+ UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ y_pixels.get());
+ UploadPixels(gl, u_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ u_pixels.get());
+ UploadPixels(gl, v_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ v_pixels.get());
+ gpu::SyncToken sync_token;
+ gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+
+ return CreateSharedImageFrame(
+ std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_I420,
+ {y_mailbox, u_mailbox, v_mailbox}, sync_token, GL_TEXTURE_2D, coded_size,
+ visible_rect, visible_rect.size(), base::TimeDelta::FromSeconds(1),
+ std::move(destroyed_callback));
+}
+
+scoped_refptr<VideoFrame> CreateSharedImageNV12Frame(
+ scoped_refptr<viz::ContextProvider> context_provider,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ base::OnceClosure destroyed_callback) {
+ DCHECK_EQ(coded_size.width() % 8, 0);
+ DCHECK_EQ(coded_size.height() % 4, 0);
+ if (!context_provider->ContextCapabilities().texture_rg) {
+ LOG(ERROR) << "GL_EXT_texture_rg not supported";
+ return {};
+ }
+ gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2);
+ size_t y_pixels_size = coded_size.GetArea();
+ size_t uv_pixels_size = uv_size.GetArea() * 2;
+ auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size);
+ auto uv_pixels = std::make_unique<uint8_t[]>(uv_pixels_size);
+ size_t y_i = 0;
+ size_t uv_i = 0;
+ for (size_t block_y = 0; block_y < 2u; ++block_y) {
+ for (int y = 0; y < coded_size.height() / 2; ++y) {
+ for (size_t block_x = 0; block_x < 4u; ++block_x) {
+ size_t color_index = block_x + block_y * 4;
+ const uint8_t* yuv = kYuvColors[color_index];
+ for (int x = 0; x < coded_size.width() / 4; ++x) {
+ y_pixels[y_i++] = yuv[0];
+ if ((x % 2) && (y % 2)) {
+ uv_pixels[uv_i++] = yuv[1];
+ uv_pixels[uv_i++] = yuv[2];
+ }
+ }
+ }
+ }
+ }
+ DCHECK_EQ(y_i, y_pixels_size);
+ DCHECK_EQ(uv_i, uv_pixels_size);
+
+ auto* sii = context_provider->SharedImageInterface();
+ gpu::Mailbox y_mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::LUMINANCE_8, coded_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ gpu::Mailbox uv_mailbox = sii->CreateSharedImage(
+ viz::ResourceFormat::RG_88, uv_size, gfx::ColorSpace(),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
+ auto* gl = context_provider->ContextGL();
+ gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
+ UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ y_pixels.get());
+ UploadPixels(gl, uv_mailbox, uv_size, GL_RG, GL_UNSIGNED_BYTE,
+ uv_pixels.get());
+ gpu::SyncToken sync_token;
+ gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+
+ return CreateSharedImageFrame(
+ std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_NV12,
+ {y_mailbox, uv_mailbox}, sync_token, GL_TEXTURE_2D, coded_size,
+ visible_rect, visible_rect.size(), base::TimeDelta::FromSeconds(1),
+ std::move(destroyed_callback));
+}
+
+} // namespace media