1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/memory/unsafe_shared_memory_region.h"
11 #include "base/run_loop.h"
12 #include "base/task/single_thread_task_runner.h"
13 #include "base/test/task_environment.h"
14 #include "gpu/config/gpu_driver_bug_workarounds.h"
15 #include "gpu/config/gpu_info.h"
16 #include "gpu/config/gpu_preferences.h"
17 #include "media/mojo/clients/mojo_media_log_service.h"
18 #include "media/mojo/mojom/video_encode_accelerator.mojom.h"
19 #include "media/mojo/services/mojo_video_encode_accelerator_service.h"
20 #include "media/video/fake_video_encode_accelerator.h"
21 #include "media/video/video_encode_accelerator.h"
22 #include "mojo/public/cpp/bindings/associated_remote.h"
23 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
24 #include "mojo/public/cpp/bindings/pending_remote.h"
25 #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
30 struct GpuPreferences;
37 static const gfx::Size kInputVisibleSize(64, 48);
39 std::unique_ptr<VideoEncodeAccelerator> CreateAndInitializeFakeVEA(
40 bool will_initialization_succeed,
41 const VideoEncodeAccelerator::Config& config,
42 VideoEncodeAccelerator::Client* client,
43 const gpu::GpuPreferences& gpu_preferences,
44 const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
45 const gpu::GPUInfo::GPUDevice& gpu_device,
46 std::unique_ptr<MediaLog> media_log) {
47 // Use FakeVEA as scoped_ptr to guarantee proper destruction via Destroy().
48 auto vea = std::make_unique<FakeVideoEncodeAccelerator>(
49 base::SingleThreadTaskRunner::GetCurrentDefault());
50 vea->SetWillInitializationSucceed(will_initialization_succeed);
51 const bool result = vea->Initialize(config, client, media_log->Clone());
53 // Mimic the behaviour of GpuVideoEncodeAcceleratorFactory::CreateVEA().
54 return result ? base::WrapUnique<VideoEncodeAccelerator>(vea.release())
58 class MockMojoVideoEncodeAcceleratorClient
59 : public mojom::VideoEncodeAcceleratorClient {
61 MockMojoVideoEncodeAcceleratorClient() = default;
63 MockMojoVideoEncodeAcceleratorClient(
64 const MockMojoVideoEncodeAcceleratorClient&) = delete;
65 MockMojoVideoEncodeAcceleratorClient& operator=(
66 const MockMojoVideoEncodeAcceleratorClient&) = delete;
68 MOCK_METHOD3(RequireBitstreamBuffers,
69 void(uint32_t, const gfx::Size&, uint32_t));
70 MOCK_METHOD2(BitstreamBufferReady,
71 void(int32_t, const media::BitstreamBufferMetadata&));
72 MOCK_METHOD1(NotifyErrorStatus, void(const EncoderStatus&));
73 MOCK_METHOD1(NotifyEncoderInfoChange, void(const VideoEncoderInfo& info));
76 // Test harness for a MojoVideoEncodeAcceleratorService; the tests manipulate it
77 // via its MojoVideoEncodeAcceleratorService interface while observing a
78 // "remote" mojo::VideoEncodeAcceleratorClient (that we keep inside a Mojo
79 // binding). The class under test uses a FakeVideoEncodeAccelerator as
81 class MojoVideoEncodeAcceleratorServiceTest : public ::testing::Test {
83 MojoVideoEncodeAcceleratorServiceTest() = default;
85 MojoVideoEncodeAcceleratorServiceTest(
86 const MojoVideoEncodeAcceleratorServiceTest&) = delete;
87 MojoVideoEncodeAcceleratorServiceTest& operator=(
88 const MojoVideoEncodeAcceleratorServiceTest&) = delete;
90 void TearDown() override {
91 // The destruction of a mojo::SelfOwnedReceiver closes the bound message
92 // pipe but does not destroy the implementation object: needs to happen
93 // manually, otherwise we leak it. This only applies if BindAndInitialize()
95 if (mojo_vea_receiver_)
96 mojo_vea_receiver_->Close();
99 // Creates the class under test, configuring the underlying FakeVEA to succeed
100 // upon initialization (by default) or not.
101 void CreateMojoVideoEncodeAccelerator(
102 bool will_fake_vea_initialization_succeed = true) {
103 mojo_vea_service_ = std::make_unique<MojoVideoEncodeAcceleratorService>(
104 base::BindRepeating(&CreateAndInitializeFakeVEA,
105 will_fake_vea_initialization_succeed),
106 gpu::GpuPreferences(), gpu::GpuDriverBugWorkarounds(),
107 gpu::GPUInfo::GPUDevice());
110 void BindAndInitialize() {
111 // Create an Mojo VEA Client remote and bind it to our Mock.
112 mojo::PendingAssociatedRemote<mojom::VideoEncodeAcceleratorClient>
113 pending_client_remote;
114 auto pending_client_receiver =
115 pending_client_remote.InitWithNewEndpointAndPassReceiver();
116 pending_client_receiver.EnableUnassociatedUsage();
118 mojo_vea_receiver_ = mojo::MakeSelfOwnedAssociatedReceiver(
119 std::make_unique<MockMojoVideoEncodeAcceleratorClient>(),
120 std::move(pending_client_receiver));
122 EXPECT_CALL(*mock_mojo_vea_client(),
123 RequireBitstreamBuffers(_, kInputVisibleSize, _));
125 constexpr media::Bitrate kInitialBitrate =
126 media::Bitrate::ConstantBitrate(100000u);
127 const media::VideoEncodeAccelerator::Config config(
128 PIXEL_FORMAT_I420, kInputVisibleSize, H264PROFILE_MIN, kInitialBitrate);
130 mojo::PendingReceiver<mojom::MediaLog> media_log_pending_receiver;
131 auto media_log_pending_remote =
132 media_log_pending_receiver.InitWithNewPipeAndPassRemote();
134 mojo_vea_service()->Initialize(
135 config, std::move(pending_client_remote),
136 std::move(media_log_pending_remote),
137 base::BindOnce([](bool success) { ASSERT_TRUE(success); }));
138 base::RunLoop().RunUntilIdle();
141 MojoVideoEncodeAcceleratorService* mojo_vea_service() {
142 return mojo_vea_service_.get();
145 MockMojoVideoEncodeAcceleratorClient* mock_mojo_vea_client() const {
146 return static_cast<media::MockMojoVideoEncodeAcceleratorClient*>(
147 mojo_vea_receiver_->impl());
150 FakeVideoEncodeAccelerator* fake_vea() const {
151 return static_cast<FakeVideoEncodeAccelerator*>(
152 mojo_vea_service_->encoder_.get());
156 base::test::SingleThreadTaskEnvironment task_environment_;
158 mojo::SelfOwnedAssociatedReceiverRef<mojom::VideoEncodeAcceleratorClient>
161 // The class under test.
162 std::unique_ptr<MojoVideoEncodeAcceleratorService> mojo_vea_service_;
165 // This test verifies the BindAndInitialize() communication prologue in
167 TEST_F(MojoVideoEncodeAcceleratorServiceTest,
168 InitializeAndRequireBistreamBuffers) {
169 CreateMojoVideoEncodeAccelerator();
173 // This test verifies the BindAndInitialize() communication prologue followed by
174 // a sharing of a single bitstream buffer and the Encode() of one frame.
175 TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodeOneFrame) {
176 CreateMojoVideoEncodeAccelerator();
179 const int32_t kBitstreamBufferId = 17;
181 const uint64_t kShMemSize = fake_vea()->minimum_output_buffer_size();
182 auto region = base::UnsafeSharedMemoryRegion::Create(kShMemSize);
184 mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
186 base::RunLoop().RunUntilIdle();
190 const auto video_frame = VideoFrame::CreateBlackFrame(kInputVisibleSize);
191 EXPECT_CALL(*mock_mojo_vea_client(),
192 BitstreamBufferReady(kBitstreamBufferId, _));
194 media::VideoEncoder::EncodeOptions options(/* key_frame */ true);
195 mojo_vea_service()->Encode(video_frame, options, base::DoNothing());
196 base::RunLoop().RunUntilIdle();
200 // Tests that a RequestEncodingParametersChange() ripples through correctly.
201 TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodingParametersChange) {
202 CreateMojoVideoEncodeAccelerator();
205 const uint32_t kNewBitrate = 123123u;
206 const uint32_t kNewFramerate = 321321u;
207 VideoBitrateAllocation bitrate_allocation;
208 bitrate_allocation.SetBitrate(0, 0, kNewBitrate);
209 mojo_vea_service()->RequestEncodingParametersChangeWithLayers(
210 bitrate_allocation, kNewFramerate);
211 base::RunLoop().RunUntilIdle();
213 ASSERT_TRUE(fake_vea());
214 VideoBitrateAllocation expected_allocation;
215 expected_allocation.SetBitrate(0, 0, kNewBitrate);
216 EXPECT_EQ(expected_allocation,
217 fake_vea()->stored_bitrate_allocations().back());
220 // Tests that a RequestEncodingParametersChange() ripples through correctly.
221 TEST_F(MojoVideoEncodeAcceleratorServiceTest,
222 EncodingParametersWithBitrateAllocation) {
223 CreateMojoVideoEncodeAccelerator();
226 const uint32_t kNewFramerate = 321321u;
227 const size_t kMaxNumBitrates = VideoBitrateAllocation::kMaxSpatialLayers *
228 VideoBitrateAllocation::kMaxTemporalLayers;
230 // Verify translation of VideoBitrateAllocation into vector of bitrates for
231 // everything from empty array up to max number of layers.
232 VideoBitrateAllocation bitrate_allocation;
233 for (size_t i = 0; i <= kMaxNumBitrates; ++i) {
235 uint32_t layer_bitrate = i * 1000;
236 const size_t si = (i - 1) / VideoBitrateAllocation::kMaxTemporalLayers;
237 const size_t ti = (i - 1) % VideoBitrateAllocation::kMaxTemporalLayers;
238 bitrate_allocation.SetBitrate(si, ti, layer_bitrate);
241 mojo_vea_service()->RequestEncodingParametersChangeWithLayers(
242 bitrate_allocation, kNewFramerate);
243 base::RunLoop().RunUntilIdle();
245 ASSERT_TRUE(fake_vea());
246 EXPECT_EQ(bitrate_allocation,
247 fake_vea()->stored_bitrate_allocations().back());
251 // This test verifies that MojoVEA::Initialize() fails with an invalid |client|.
252 TEST_F(MojoVideoEncodeAcceleratorServiceTest,
253 InitializeWithInvalidClientFails) {
254 CreateMojoVideoEncodeAccelerator();
256 mojo::PendingAssociatedRemote<mojom::VideoEncodeAcceleratorClient>
257 invalid_mojo_vea_client;
259 constexpr media::Bitrate kInitialBitrate =
260 media::Bitrate::ConstantBitrate(100000u);
261 const media::VideoEncodeAccelerator::Config config(
262 PIXEL_FORMAT_I420, kInputVisibleSize, H264PROFILE_MIN, kInitialBitrate);
263 mojo::PendingReceiver<mojom::MediaLog> media_log_pending_receiver;
264 auto media_log_pending_remote =
265 media_log_pending_receiver.InitWithNewPipeAndPassRemote();
267 mojo_vea_service()->Initialize(
268 config, std::move(invalid_mojo_vea_client),
269 std::move(media_log_pending_remote),
270 base::BindOnce([](bool success) { ASSERT_FALSE(success); }));
271 base::RunLoop().RunUntilIdle();
274 // This test verifies that when FakeVEA is configured to fail upon start,
275 // MojoVEA::Initialize() causes a NotifyError().
276 TEST_F(MojoVideoEncodeAcceleratorServiceTest, InitializeFailure) {
277 CreateMojoVideoEncodeAccelerator(
278 false /* will_fake_vea_initialization_succeed */);
280 mojo::PendingAssociatedRemote<mojom::VideoEncodeAcceleratorClient>
282 auto mojo_vea_receiver = mojo::MakeSelfOwnedAssociatedReceiver(
283 std::make_unique<MockMojoVideoEncodeAcceleratorClient>(),
284 mojo_vea_client.InitWithNewEndpointAndPassReceiver());
286 constexpr media::Bitrate kInitialBitrate =
287 media::Bitrate::ConstantBitrate(100000u);
288 const media::VideoEncodeAccelerator::Config config(
289 PIXEL_FORMAT_I420, kInputVisibleSize, H264PROFILE_MIN, kInitialBitrate);
290 mojo::PendingReceiver<mojom::MediaLog> media_log_pending_receiver;
291 auto media_log_pending_remote =
292 media_log_pending_receiver.InitWithNewPipeAndPassRemote();
294 mojo_vea_service()->Initialize(
295 config, std::move(mojo_vea_client), std::move(media_log_pending_remote),
296 base::BindOnce([](bool success) { ASSERT_FALSE(success); }));
297 base::RunLoop().RunUntilIdle();
299 mojo_vea_receiver->Close();
302 // This test verifies that UseOutputBitstreamBuffer() with a wrong ShMem size
303 // causes NotifyError().
304 TEST_F(MojoVideoEncodeAcceleratorServiceTest,
305 UseOutputBitstreamBufferWithWrongSizeFails) {
306 CreateMojoVideoEncodeAccelerator();
309 const int32_t kBitstreamBufferId = 17;
310 const uint64_t wrong_size = fake_vea()->minimum_output_buffer_size() / 2;
311 auto region = base::UnsafeSharedMemoryRegion::Create(wrong_size);
313 EXPECT_CALL(*mock_mojo_vea_client(), NotifyErrorStatus);
315 mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
317 base::RunLoop().RunUntilIdle();
320 // This test verifies that Encode() with wrong coded size causes NotifyError().
321 TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodeWithWrongSizeFails) {
322 CreateMojoVideoEncodeAccelerator();
325 // We should send a UseOutputBitstreamBuffer() first but in unit tests we can
326 // skip that prologue.
328 const gfx::Size wrong_size(kInputVisibleSize.width() / 2,
329 kInputVisibleSize.height() / 2);
330 const auto video_frame = VideoFrame::CreateBlackFrame(wrong_size);
332 EXPECT_CALL(*mock_mojo_vea_client(), NotifyErrorStatus);
334 media::VideoEncoder::EncodeOptions options(/* key_frame */ true);
335 mojo_vea_service()->Encode(video_frame, options, base::DoNothing());
336 base::RunLoop().RunUntilIdle();
339 // This test verifies that an any mojom::VEA method call (e.g. Encode(),
340 // UseOutputBitstreamBuffer() etc) before MojoVEA::Initialize() is ignored (we
341 // can't expect NotifyError()s since there's no mojo client registered).
342 TEST_F(MojoVideoEncodeAcceleratorServiceTest, CallsBeforeInitializeAreIgnored) {
343 CreateMojoVideoEncodeAccelerator();
345 const auto video_frame = VideoFrame::CreateBlackFrame(kInputVisibleSize);
346 media::VideoEncoder::EncodeOptions options(/* key_frame */ true);
347 mojo_vea_service()->Encode(video_frame, options, base::DoNothing());
348 base::RunLoop().RunUntilIdle();
351 const int32_t kBitstreamBufferId = 17;
352 const uint64_t kShMemSize = 10;
353 auto region = base::UnsafeSharedMemoryRegion::Create(kShMemSize);
354 mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
356 base::RunLoop().RunUntilIdle();
359 const uint32_t kNewBitrate = 123123u;
360 const uint32_t kNewFramerate = 321321u;
361 media::VideoBitrateAllocation bitrate_allocation;
362 bitrate_allocation.SetBitrate(0, 0, kNewBitrate);
363 mojo_vea_service()->RequestEncodingParametersChangeWithLayers(
364 bitrate_allocation, kNewFramerate);
365 base::RunLoop().RunUntilIdle();
369 // This test verifies that IsFlushSupported/Flush on FakeVEA.
370 TEST_F(MojoVideoEncodeAcceleratorServiceTest, IsFlushSupportedAndFlush) {
371 CreateMojoVideoEncodeAccelerator();
374 ASSERT_TRUE(fake_vea());
376 // media::VideoEncodeAccelerator::IsFlushSupported and Flush are return
377 // false as default, so here expect false for both IsFlushSupported and
380 base::BindOnce([](bool status) { EXPECT_EQ(status, false); });
381 mojo_vea_service()->IsFlushSupported(std::move(flush_support));
382 base::RunLoop().RunUntilIdle();
384 auto flush_callback =
385 base::BindOnce([](bool status) { EXPECT_EQ(status, false); });
386 mojo_vea_service()->IsFlushSupported(std::move(flush_callback));