High watch CVSS 3.4 chrome Uninitialized Memory 🔧 Commit mapped

Overview

High
Severity
3.4
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUninitialized resource in Media
DescriptionUninitialized resource in Media
ComponentMedia
Sub-componentMedia
Bug ClassUninitialized Memory
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker563351482
Fix commitf424973cf00b (chromium/src) +113/-42
CWECWE-908
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-09-18 (per vendor advisory)
Fix landed2026-09-22 (public git)
Disclosed2026-09-29
Patch gap7 days — fix public in source before the advisory

Background

`MediaFoundationVideoEncodeAccelerator` (MFVEA)
the Windows GPU-process hardware video encoder that turns VideoFrames into encoded bitstreams via Media Foundation.
`CopyInputSampleBufferFromGpu`
the MFVEA path that reads a GPU D3D11 texture back into a CPU IMFMediaBuffer via gpu::CopyD3D11TexToMem, which only supports and copies NV12 bytes.
`VideoFrame::AllocationSize`
a helper that computes a buffer size from a pixel format and dimensions; different formats yield different per-frame byte counts.
NV12
a 4:2:0 semi-planar format whose byte size is width * height * 3 / 2, the layout CopyD3D11TexToMem assumes.

Root Cause Analysis

In the skip-scaling branch of CopyInputSampleBufferFromGpu, the code read a GPU texture back with gpu::CopyD3D11TexToMem (which unconditionally copies NV12 bytes) without ever validating that the VideoFrame’s pixel format or the source texture’s DXGI format was actually NV12. The IMFMediaBuffer was allocated and its advertised length (SetCurrentLength) derived from frame->format() rather than the true NV12 copy size, so when the frame/texture format disagreed with NV12 the buffer could be sized larger than the bytes the copy wrote, leaving a suffix of the buffer uninitialized while its length claimed those bytes were valid. Downstream Media Foundation encoding then consumes that advertised length, disclosing uninitialized heap/driver memory in the encoded output.

The fix adds two early return E_INVALIDARG guards rejecting any frame whose frame->format() != PIXEL_FORMAT_NV12 and any texture whose input_desc.Format != DXGI_FORMAT_NV12, and pins both the allocation and copied_bytes to VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, input_visible_size_) so size and content are consistent. The related GenerateSampleFromVideoFrame readback branch (which shared the fragile size logic) is deleted entirely and collapsed to InitializeSampleFromTexture.

Key insight
The core mistake was letting an NV12-only readback proceed on frames/textures of arbitrary format and advertising a length computed from the frame’s declared format rather than the bytes actually copied; the fix validates NV12 up front and derives the buffer size from the true NV12 allocation size.

Attack Path

  1. Submit a non-NV12 frame for hardware encode A renderer/client drives the Media Foundation encoder with a GPU-backed VideoFrame whose pixel format (or backing texture DXGI format) is not NV12, e.g. ARGB/BGRA as exercised by the regression tests.
  2. Reach the GPU-readback path with scaling skipped Execution enters CopyInputSampleBufferFromGpu on the branch where no scaling is needed, so no format normalization occurs before readback. (inferred)
  3. Mis-sized, partially-written buffer gpu::CopyD3D11TexToMem copies only NV12-shaped bytes while the IMFMediaBuffer is allocated and length-advertised from the frame’s non-NV12 AllocationSize, leaving part of the reported buffer uninitialized.
  4. Uninitialized memory reaches output The encoder consumes the advertised length and the uninitialized region is emitted into the encoded bitstream returned to the client, an information disclosure. (inferred)

Impact Assessment

An attacker who can feed frames to the Windows hardware encoder gains disclosure of uninitialized memory (the advisory classifies it as “Uninitialized resource in Media”) in the GPU process, leaking that data through the encoded output. Preconditions are use of the Media Foundation encode path with a GPU-backed, non-NV12 frame or texture. No memory-corruption or code-execution escalation is claimed by the advisory; the leak severity is as the advisory states.

Changed Functions

FunctionChangeNotes
if
media/base/win/mf_helpers.cc
modified
if
media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
modified

Files Changed

  • media/base/win/mf_helpers.cc
  • media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
  • media/base/win/mf_helpers.h
  • media/gpu/windows/media_foundation_video_encode_accelerator_win.h
  • media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
  • media/gpu/windows/mf_video_processor_accelerator.cc

Audit Directions

  • Format-assumption without validation
    Hunt for readback/copy helpers (e.g. CopyD3D11TexToMem) that hard-code one pixel/DXGI format but are called on frames whose format is attacker-influenced and unchecked.
  • Length derived from a different source than the copy
    Flag any SetCurrentLength/buffer-length assignment computed from a declared format or size that differs from the actual number of bytes written into the buffer.
  • Scaling-skipped fast paths
    Review branches that bypass normalization/scaling in media encoders, since they often skip the format checks the slow path performs.
From f424973cf00b08c815d50cdff42e756a150b5d89 Mon Sep 17 00:00:00 2001
From: Dale Curtis <[email protected]>
Date: Mon, 21 Sep 2026 18:30:35 -0700
Subject: [PATCH] media: Validate frame and texture format in MFVEA GPU readback

In MediaFoundationVideoEncodeAccelerator::CopyInputSampleBufferFromGpu,
GPU textures are read back to CPU memory via gpu::CopyD3D11TexToMem.
This path only supports NV12 textures and copies NV12 bytes.

Previously, neither the frame's pixel format nor the texture's DXGI
format were validated in CopyInputSampleBufferFromGpu when scaling was
skipped. Additionally, the buffer allocation and advertised length were
derived from frame->format() rather than the actual copied NV12 size.

Change-Id: I9e350b03097126a3ce43cf5dfc6030b39b4a4b30
Fixed: 563351482
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8435965
Commit-Queue: Dale Curtis <[email protected]>
Auto-Submit: Dale Curtis <[email protected]>
Reviewed-by: Eugene Zemtsov <[email protected]>
Commit-Queue: Eugene Zemtsov <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1702292}
---
diff --git a/media/base/win/mf_helpers.cc b/media/base/win/mf_helpers.cc
index de95017..929eeac 100644
--- a/media/base/win/mf_helpers.cc
+++ b/media/base/win/mf_helpers.cc
@@ -992,8 +992,6 @@
 HRESULT GenerateSampleFromVideoFrame(
     const VideoFrame* frame,
     DXGIDeviceManager* dxgi_device_manager,
-    bool use_dxgi_buffer,
-    Microsoft::WRL::ComPtr<ID3D11Texture2D>* staging_texture,
     DWORD buffer_alignment,
     IMFSample** sample_out) {
   // A shared image sample for a non-mappable SharedImage cannot be created
@@ -1033,36 +1031,8 @@
     RETURN_ON_HR_FAILURE(
         hr, "Failed to open shared D3D texture from GMB handle", hr);
 
-    if (use_dxgi_buffer) {
-      hr = InitializeSampleFromTexture(frame, input_texture.Get(), sample);
-      RETURN_ON_HR_FAILURE(hr, "Failed to initialize sample from texture", hr);
-    } else {
-      Microsoft::WRL::ComPtr<IMFMediaBuffer> input_buffer;
-      size_t allocation_size =
-          VideoFrame::AllocationSize(frame->format(), frame->coded_size());
-      hr = MFCreateAlignedMemoryBuffer(
-          allocation_size,
-          buffer_alignment == 0 ? buffer_alignment : buffer_alignment - 1,
-          &input_buffer);
-      RETURN_ON_HR_FAILURE(
-          hr, "Failed to create memory buffer for input sample", hr);
-
-      MediaBufferScopedPointer scoped_buffer(input_buffer.Get());
-      bool copy_succeeded =
-          gpu::CopyD3D11TexToMem(input_texture.Get(), scoped_buffer.as_span(),
-                                 d3d_device.Get(), staging_texture);
-      if (!copy_succeeded) {
-        LOG(ERROR) << "Failed to copy sample to memory.";
-        return E_FAIL;
-      }
-
-      size_t copied_bytes = frame->visible_rect().width() *
-                            frame->visible_rect().height() * 3 / 2;
-      hr = input_buffer->SetCurrentLength(copied_bytes);
-      RETURN_ON_HR_FAILURE(hr, "Failed to set current buffer length", hr);
-      hr = sample->AddBuffer(input_buffer.Get());
-      RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", hr);
-    }
+    hr = InitializeSampleFromTexture(frame, input_texture.Get(), sample);
+    RETURN_ON_HR_FAILURE(hr, "Failed to initialize sample from texture", hr);
   } else {
     size_t allocation_size = VideoFrame::AllocationSize(
         frame->format(), frame->visible_rect().size());
diff --git a/media/base/win/mf_helpers.h b/media/base/win/mf_helpers.h
index 73db391f..8572e20 100644
--- a/media/base/win/mf_helpers.h
+++ b/media/base/win/mf_helpers.h
@@ -224,13 +224,11 @@
     Microsoft::WRL::ComPtr<ID3D11Texture2D> input_texture,
     bool need_perform_copy);
 
-// Converts `frame` into an IMFSample, using an underlying D3D texture,
-// reading back from the GPU, or copying the frame contents as necessary.
+// Converts `frame` into an IMFSample, using an underlying D3D texture
+// or copying the frame contents as necessary.
 MEDIA_EXPORT HRESULT GenerateSampleFromVideoFrame(
     const media::VideoFrame* frame,
     DXGIDeviceManager* dxgi_device_manager,
-    bool use_dxgi_buffer,
-    Microsoft::WRL::ComPtr<ID3D11Texture2D>* staging_texture,
     DWORD buffer_alignment,
     IMFSample** sample_out);
 
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index 86f7bd2..d55df07 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -2283,6 +2283,13 @@
   DCHECK(dxgi_device_manager_);
   auto& input_sample = input.input_sample;
 
+  if (frame->format() != PIXEL_FORMAT_NV12) {
+    LOG(ERROR) << "Format mismatch: frame format "
+               << VideoPixelFormatToString(frame->format())
+               << " is not PIXEL_FORMAT_NV12";
+    return E_INVALIDARG;
+  }
+
   auto d3d_device = dxgi_device_manager_->GetDevice();
   if (!d3d_device) {
     LOG(ERROR) << "Failed to get device from MF DXGI device manager";
@@ -2316,6 +2323,13 @@
   // Check if we need to scale the input texture
   D3D11_TEXTURE2D_DESC input_desc = {};
   input_texture->GetDesc(&input_desc);
+
+  if (input_desc.Format != DXGI_FORMAT_NV12) {
+    LOG(ERROR) << "Format mismatch: source format " << input_desc.Format
+               << " is not DXGI_FORMAT_NV12";
+    return E_INVALIDARG;
+  }
+
   gfx::Size texture_size(input_desc.Width, input_desc.Height);
   ComD3D11Texture2D sample_texture;
   if (texture_size != input_visible_size_ ||
@@ -2334,10 +2348,10 @@
   MFT_INPUT_STREAM_INFO input_stream_info;
   hr = encoder_->GetInputStreamInfo(input_stream_id_, &input_stream_info);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get input stream info", hr);
+  const size_t allocation_size =
+      VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, input_visible_size_);
   hr = MFCreateAlignedMemoryBuffer(
-      input_stream_info.cbSize
-          ? input_stream_info.cbSize
-          : VideoFrame::AllocationSize(frame->format(), input_visible_size_),
+      std::max(static_cast<size_t>(input_stream_info.cbSize), allocation_size),
       input_stream_info.cbAlignment == 0 ? input_stream_info.cbAlignment
                                          : input_stream_info.cbAlignment - 1,
       &input_buffer);
@@ -2352,8 +2366,7 @@
     LOG(ERROR) << "Failed to copy sample to memory.";
     return E_FAIL;
   }
-  size_t copied_bytes =
-      VideoFrame::AllocationSize(frame->format(), input_visible_size_);
+  const size_t copied_bytes = allocation_size;
   hr = input_buffer->SetCurrentLength(copied_bytes);
   RETURN_ON_HR_FAILURE(hr, "Failed to set current buffer length", hr);
 
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index e7fcd6d..020755600 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -117,6 +117,10 @@
       const gfx::Size& input_visible_size,
       scoped_refptr<DXGIDeviceManager> dxgi_device_manager);
 
+  void SetDxgiResourceMappingRequiredForTesting(bool required) {
+    dxgi_resource_mapping_required_ = required;
+  }
+
  private:
   // Holds output buffers coming from the client ready to be filled.
   struct BitstreamBufferRef;
diff --git a/media/gpu/windows/mf_video_processor_accelerator.cc b/media/gpu/windows/mf_video_processor_accelerator.cc
index 450bb48..042af81b5 100644
--- a/media/gpu/windows/mf_video_processor_accelerator.cc
+++ b/media/gpu/windows/mf_video_processor_accelerator.cc
@@ -179,7 +179,7 @@
 
   ComMFSample sample;
   HRESULT hr = GenerateSampleFromVideoFrame(
-      frame.get(), dxgi_device_manager_.get(), true, nullptr, 0, &sample);
+      frame.get(), dxgi_device_manager_.get(), 0, &sample);
   RETURN_ON_HR_FAILURE(hr, L"Couldn't generate MF sample from VideoFrame", hr);
 
   // The video processor will internally acquire the keyed mutex for the
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
index f04b2f5..ecff140b 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
@@ -153,6 +153,8 @@
     : public MediaFoundationVideoEncodeAccelerator {
  public:
   using MediaFoundationVideoEncodeAccelerator::InitializeForTesting;
+  using MediaFoundationVideoEncodeAccelerator::
+      SetDxgiResourceMappingRequiredForTesting;
 
   TestMediaFoundationVideoEncodeAccelerator(
       const gpu::GpuPreferences& gpu_preferences,
@@ -451,6 +453,90 @@
   task_environment_.RunUntilIdle();
 }
 
+// Tests that when dxgi_resource_mapping_required_ is true, a frame whose
+// format is not NV12 is rejected rather than disclosing uninitialized memory.
+TEST_F(MediaFoundationVideoEncodeAcceleratorKeyedMutexTimeoutTest,
+       RejectFrameOnDxgiResourceMappingFrameFormatMismatch) {
+  encoder_->SetDxgiResourceMappingRequiredForTesting(true);
+
+  gfx::Size input_visible_size(1280, 720);
+  auto test_sii = base::MakeRefCounted<gpu::TestSharedImageInterface>();
+  gfx::GpuMemoryBufferHandle gmb_handle{gfx::DXGIHandle::CreateFakeForTest()};
+  const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
+                        gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
+
+  auto shared_image = test_sii->CreateSharedImage(
+      {viz::SinglePlaneFormat::kBGRA_8888, input_visible_size,
+       gfx::ColorSpace(), gpu::SharedImageUsageSet(si_usage),
+       "MediaFoundationVideoEncodeAcceleratorTest"},
+      gpu::kNullSurfaceHandle, gfx::BufferUsage::GPU_READ,
+      std::move(gmb_handle));
+
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapMappableSharedImage(
+      std::move(shared_image), test_sii->GenVerifiedSyncToken(),
+      base::NullCallback(), gfx::Rect(input_visible_size), input_visible_size,
+      base::TimeDelta());
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(frame->format(), PIXEL_FORMAT_ARGB);
+
+  VideoEncoder::EncodeOptions options(false);
+  EXPECT_CALL(client_, NotifyErrorStatus(Property(
+                           &EncoderStatus::code,
+                           EncoderStatus::Codes::kEncoderFailedEncode)));
+
+  encoder_->Encode(frame, options);
+}
+
+// Tests that when dxgi_resource_mapping_required_ is true, a frame backed by a
+// texture whose DXGI format is not NV12 is rejected rather than disclosing
+// uninitialized memory.
+TEST_F(MediaFoundationVideoEncodeAcceleratorKeyedMutexTimeoutTest,
+       RejectFrameOnDxgiResourceMappingTextureFormatMismatch) {
+  encoder_->SetDxgiResourceMappingRequiredForTesting(true);
+
+  auto mock_texture =
+      Microsoft::WRL::Make<MockD3D11Texture2D>(mock_d3d11_device_);
+
+  D3D11_TEXTURE2D_DESC desc = {};
+  gfx::Size input_visible_size(1280, 720);
+  desc.Width = input_visible_size.width();
+  desc.Height = input_visible_size.height();
+  desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+  EXPECT_CALL(*mock_texture.Get(), GetDesc(_))
+      .WillRepeatedly([desc](D3D11_TEXTURE2D_DESC* pDesc) { *pDesc = desc; });
+
+  EXPECT_CALL(*mock_d3d11_device_.Get(), OpenSharedResource1(_, _, _))
+      .WillOnce([&mock_texture](HANDLE, REFIID riid, void** ppv) {
+        return mock_texture.CopyTo(riid, ppv);
+      });
+
+  auto test_sii = base::MakeRefCounted<gpu::TestSharedImageInterface>();
+  gfx::GpuMemoryBufferHandle gmb_handle{gfx::DXGIHandle::CreateFakeForTest()};
+  const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
+                        gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
+
+  auto shared_image = test_sii->CreateSharedImage(
+      {viz::MultiPlaneFormat::kNV12, input_visible_size, gfx::ColorSpace(),
+       gpu::SharedImageUsageSet(si_usage),
+       "MediaFoundationVideoEncodeAcceleratorTest"},
+      gpu::kNullSurfaceHandle, gfx::BufferUsage::GPU_READ,
+      std::move(gmb_handle));
+
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapMappableSharedImage(
+      std::move(shared_image), test_sii->GenVerifiedSyncToken(),
+      base::NullCallback(), gfx::Rect(input_visible_size), input_visible_size,
+      base::TimeDelta());
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(frame->format(), PIXEL_FORMAT_NV12);
+
+  VideoEncoder::EncodeOptions options(false);
+  EXPECT_CALL(client_, NotifyErrorStatus(Property(
+                           &EncoderStatus::code,
+                           EncoderStatus::Codes::kEncoderFailedEncode)));
+
+  encoder_->Encode(frame, options);
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          MediaFoundationVideoEncodeAcceleratorAlignmentTest,
                          ::testing::Values(PIXEL_FORMAT_NV12,
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
index f04b2f5..ecff140b 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win_unittest.cc
@@ -153,6 +153,8 @@
     : public MediaFoundationVideoEncodeAccelerator {
  public:
   using MediaFoundationVideoEncodeAccelerator::InitializeForTesting;
+  using MediaFoundationVideoEncodeAccelerator::
+      SetDxgiResourceMappingRequiredForTesting;
 
   TestMediaFoundationVideoEncodeAccelerator(
       const gpu::GpuPreferences& gpu_preferences,
@@ -451,6 +453,90 @@
   task_environment_.RunUntilIdle();
 }
 
+// Tests that when dxgi_resource_mapping_required_ is true, a frame whose
+// format is not NV12 is rejected rather than disclosing uninitialized memory.
+TEST_F(MediaFoundationVideoEncodeAcceleratorKeyedMutexTimeoutTest,
+       RejectFrameOnDxgiResourceMappingFrameFormatMismatch) {
+  encoder_->SetDxgiResourceMappingRequiredForTesting(true);
+
+  gfx::Size input_visible_size(1280, 720);
+  auto test_sii = base::MakeRefCounted<gpu::TestSharedImageInterface>();
+  gfx::GpuMemoryBufferHandle gmb_handle{gfx::DXGIHandle::CreateFakeForTest()};
+  const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
+                        gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
+
+  auto shared_image = test_sii->CreateSharedImage(
+      {viz::SinglePlaneFormat::kBGRA_8888, input_visible_size,
+       gfx::ColorSpace(), gpu::SharedImageUsageSet(si_usage),
+       "MediaFoundationVideoEncodeAcceleratorTest"},
+      gpu::kNullSurfaceHandle, gfx::BufferUsage::GPU_READ,
+      std::move(gmb_handle));
+
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapMappableSharedImage(
+      std::move(shared_image), test_sii->GenVerifiedSyncToken(),
+      base::NullCallback(), gfx::Rect(input_visible_size), input_visible_size,
+      base::TimeDelta());
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(frame->format(), PIXEL_FORMAT_ARGB);
+
+  VideoEncoder::EncodeOptions options(false);
+  EXPECT_CALL(client_, NotifyErrorStatus(Property(
+                           &EncoderStatus::code,
+                           EncoderStatus::Codes::kEncoderFailedEncode)));
+
+  encoder_->Encode(frame, options);
+}
+
+// Tests that when dxgi_resource_mapping_required_ is true, a frame backed by a
+// texture whose DXGI format is not NV12 is rejected rather than disclosing
+// uninitialized memory.
+TEST_F(MediaFoundationVideoEncodeAcceleratorKeyedMutexTimeoutTest,
+       RejectFrameOnDxgiResourceMappingTextureFormatMismatch) {
+  encoder_->SetDxgiResourceMappingRequiredForTesting(true);
+
+  auto mock_texture =
+      Microsoft::WRL::Make<MockD3D11Texture2D>(mock_d3d11_device_);
+
+  D3D11_TEXTURE2D_DESC desc = {};
+  gfx::Size input_visible_size(1280, 720);
+  desc.Width = input_visible_size.width();
+  desc.Height = input_visible_size.height();
+  desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+  EXPECT_CALL(*mock_texture.Get(), GetDesc(_))
+      .WillRepeatedly([desc](D3D11_TEXTURE2D_DESC* pDesc) { *pDesc = desc; });
+
+  EXPECT_CALL(*mock_d3d11_device_.Get(), OpenSharedResource1(_, _, _))
+      .WillOnce([&mock_texture](HANDLE, REFIID riid, void** ppv) {
+        return mock_texture.CopyTo(riid, ppv);
+      });
+
+  auto test_sii = base::MakeRefCounted<gpu::TestSharedImageInterface>();
+  gfx::GpuMemoryBufferHandle gmb_handle{gfx::DXGIHandle::CreateFakeForTest()};
+  const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
+                        gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
+
+  auto shared_image = test_sii->CreateSharedImage(
+      {viz::MultiPlaneFormat::kNV12, input_visible_size, gfx::ColorSpace(),
+       gpu::SharedImageUsageSet(si_usage),
+       "MediaFoundationVideoEncodeAcceleratorTest"},
+      gpu::kNullSurfaceHandle, gfx::BufferUsage::GPU_READ,
+      std::move(gmb_handle));
+
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapMappableSharedImage(
+      std::move(shared_image), test_sii->GenVerifiedSyncToken(),
+      base::NullCallback(), gfx::Rect(input_visible_size), input_visible_size,
+      base::TimeDelta());
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(frame->format(), PIXEL_FORMAT_NV12);
+
+  VideoEncoder::EncodeOptions options(false);
+  EXPECT_CALL(client_, NotifyErrorStatus(Property(
+                           &EncoderStatus::code,
+                           EncoderStatus::Codes::kEncoderFailedEncode)));
+
+  encoder_->Encode(frame, options);
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          MediaFoundationVideoEncodeAcceleratorAlignmentTest,
                          ::testing::Values(PIXEL_FORMAT_NV12,
Loading diff…