diff options
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.cc | 254 |
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 |