1 // Copyright 2022 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/posix/eintr_wrapper.h"
8 #include "base/test/mock_callback.h"
9 #include "base/test/task_environment.h"
10 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
11 #include "media/mojo/common/mojo_decoder_buffer_converter.h"
12 #include "media/mojo/mojom/media_log.mojom.h"
13 #include "media/mojo/mojom/video_decoder.mojom.h"
14 #include "media/mojo/services/stable_video_decoder_factory_service.h"
15 #include "media/mojo/services/stable_video_decoder_service.h"
16 #include "mojo/public/cpp/bindings/associated_receiver.h"
17 #include "mojo/public/cpp/bindings/remote.h"
18 #include "mojo/public/cpp/system/data_pipe.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "ui/gfx/gpu_memory_buffer.h"
24 using testing::ByMove;
26 using testing::Return;
27 using testing::SaveArg;
28 using testing::StrictMock;
29 using testing::WithArgs;
35 VideoDecoderConfig CreateValidVideoDecoderConfig() {
36 const VideoDecoderConfig config(
37 VideoCodec::kH264, VideoCodecProfile::H264PROFILE_BASELINE,
38 VideoDecoderConfig::AlphaMode::kHasAlpha, VideoColorSpace::REC709(),
39 VideoTransformation(VIDEO_ROTATION_90, /*mirrored=*/true),
40 /*coded_size=*/gfx::Size(640, 368),
41 /*visible_rect=*/gfx::Rect(1, 1, 630, 360),
42 /*natural_size=*/gfx::Size(1260, 720),
43 /*extra_data=*/std::vector<uint8_t>{1, 2, 3},
44 EncryptionScheme::kUnencrypted);
45 DCHECK(config.IsValidConfig());
49 scoped_refptr<VideoFrame> CreateTestNV12GpuMemoryBufferVideoFrame() {
50 gfx::GpuMemoryBufferHandle gmb_handle;
51 gmb_handle.type = gfx::NATIVE_PIXMAP;
53 // We need to create something that looks like a dma-buf in order to pass the
54 // validation in the mojo traits, so we use memfd_create() + ftruncate().
55 auto y_fd = base::ScopedFD(memfd_create("nv12_dummy_buffer", 0));
56 if (!y_fd.is_valid()) {
59 if (HANDLE_EINTR(ftruncate(y_fd.get(), 280000 + 140000)) < 0) {
62 auto uv_fd = base::ScopedFD(HANDLE_EINTR(dup(y_fd.get())));
63 if (!uv_fd.is_valid()) {
67 gfx::NativePixmapPlane y_plane;
70 y_plane.size = 280000;
71 y_plane.fd = std::move(y_fd);
72 gmb_handle.native_pixmap_handle.planes.push_back(std::move(y_plane));
74 gfx::NativePixmapPlane uv_plane;
75 uv_plane.stride = 700;
76 uv_plane.offset = 280000;
77 uv_plane.size = 140000;
78 uv_plane.fd = std::move(uv_fd);
79 gmb_handle.native_pixmap_handle.planes.push_back(std::move(uv_plane));
81 gpu::GpuMemoryBufferSupport gmb_support;
82 auto gmb = gmb_support.CreateGpuMemoryBufferImplFromHandle(
83 std::move(gmb_handle), gfx::Size(640, 368),
84 gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::SCANOUT_VDA_WRITE,
90 gpu::MailboxHolder dummy_mailbox[media::VideoFrame::kMaxPlanes];
91 auto gmb_video_frame = VideoFrame::WrapExternalGpuMemoryBuffer(
92 /*visible_rect=*/gfx::Rect(640, 368),
93 /*natural_size=*/gfx::Size(640, 368), std::move(gmb), dummy_mailbox,
94 base::NullCallback(), base::TimeDelta());
95 if (!gmb_video_frame) {
99 gmb_video_frame->metadata().allow_overlay = true;
100 gmb_video_frame->metadata().end_of_stream = false;
101 gmb_video_frame->metadata().read_lock_fences_enabled = true;
102 gmb_video_frame->metadata().power_efficient = true;
104 return gmb_video_frame;
107 class MockVideoFrameHandleReleaser : public mojom::VideoFrameHandleReleaser {
109 explicit MockVideoFrameHandleReleaser(
110 mojo::PendingReceiver<mojom::VideoFrameHandleReleaser>
111 video_frame_handle_releaser)
112 : video_frame_handle_releaser_receiver_(
114 std::move(video_frame_handle_releaser)) {}
115 MockVideoFrameHandleReleaser(const MockVideoFrameHandleReleaser&) = delete;
116 MockVideoFrameHandleReleaser& operator=(const MockVideoFrameHandleReleaser&) =
118 ~MockVideoFrameHandleReleaser() override = default;
120 // mojom::VideoFrameHandleReleaser implementation.
121 MOCK_METHOD2(ReleaseVideoFrame,
122 void(const base::UnguessableToken& release_token,
123 const absl::optional<gpu::SyncToken>& release_sync_token));
126 mojo::Receiver<mojom::VideoFrameHandleReleaser>
127 video_frame_handle_releaser_receiver_;
130 class MockVideoDecoder : public mojom::VideoDecoder {
132 MockVideoDecoder() = default;
133 MockVideoDecoder(const MockVideoDecoder&) = delete;
134 MockVideoDecoder& operator=(const MockVideoDecoder&) = delete;
135 ~MockVideoDecoder() override = default;
137 mojo::AssociatedRemote<mojom::VideoDecoderClient> TakeClientRemote() {
138 return std::move(client_remote_);
140 mojo::Remote<mojom::MediaLog> TakeMediaLogRemote() {
141 return std::move(media_log_remote_);
143 std::unique_ptr<StrictMock<MockVideoFrameHandleReleaser>>
144 TakeVideoFrameHandleReleaser() {
145 return std::move(video_frame_handle_releaser_);
147 std::unique_ptr<MojoDecoderBufferReader> TakeMojoDecoderBufferReader() {
148 return std::move(mojo_decoder_buffer_reader_);
151 // mojom::VideoDecoder implementation.
152 MOCK_METHOD1(GetSupportedConfigs, void(GetSupportedConfigsCallback callback));
154 mojo::PendingAssociatedRemote<mojom::VideoDecoderClient> client,
155 mojo::PendingRemote<mojom::MediaLog> media_log,
156 mojo::PendingReceiver<mojom::VideoFrameHandleReleaser>
157 video_frame_handle_releaser,
158 mojo::ScopedDataPipeConsumerHandle decoder_buffer_pipe,
159 mojom::CommandBufferIdPtr command_buffer_id,
160 const gfx::ColorSpace& target_color_space) final {
161 client_remote_.Bind(std::move(client));
162 media_log_remote_.Bind(std::move(media_log));
163 video_frame_handle_releaser_ =
164 std::make_unique<StrictMock<MockVideoFrameHandleReleaser>>(
165 std::move(video_frame_handle_releaser));
166 mojo_decoder_buffer_reader_ = std::make_unique<MojoDecoderBufferReader>(
167 std::move(decoder_buffer_pipe));
168 DoConstruct(std::move(command_buffer_id), target_color_space);
170 MOCK_METHOD2(DoConstruct,
171 void(mojom::CommandBufferIdPtr command_buffer_id,
172 const gfx::ColorSpace& target_color_space));
173 MOCK_METHOD4(Initialize,
174 void(const VideoDecoderConfig& config,
176 const absl::optional<base::UnguessableToken>& cdm_id,
177 InitializeCallback callback));
179 void(mojom::DecoderBufferPtr buffer, DecodeCallback callback));
180 MOCK_METHOD1(Reset, void(ResetCallback callback));
181 MOCK_METHOD1(OnOverlayInfoChanged, void(const OverlayInfo& overlay_info));
184 mojo::AssociatedRemote<mojom::VideoDecoderClient> client_remote_;
185 mojo::Remote<mojom::MediaLog> media_log_remote_;
186 std::unique_ptr<StrictMock<MockVideoFrameHandleReleaser>>
187 video_frame_handle_releaser_;
188 std::unique_ptr<MojoDecoderBufferReader> mojo_decoder_buffer_reader_;
191 class MockStableVideoDecoderTracker
192 : public stable::mojom::StableVideoDecoderTracker {};
194 class MockStableVideoDecoderClient : public stable::mojom::VideoDecoderClient {
196 explicit MockStableVideoDecoderClient(
197 mojo::PendingAssociatedReceiver<stable::mojom::VideoDecoderClient>
199 : receiver_(this, std::move(pending_receiver)) {}
200 MockStableVideoDecoderClient(const MockStableVideoDecoderClient&) = delete;
201 MockStableVideoDecoderClient& operator=(const MockStableVideoDecoderClient&) =
203 ~MockStableVideoDecoderClient() override = default;
205 // stable::mojom::VideoDecoderClient implementation.
206 MOCK_METHOD3(OnVideoFrameDecoded,
207 void(stable::mojom::VideoFramePtr frame,
208 bool can_read_without_stalling,
209 const base::UnguessableToken& release_token));
210 MOCK_METHOD1(OnWaiting, void(WaitingReason reason));
213 mojo::AssociatedReceiver<stable::mojom::VideoDecoderClient> receiver_;
216 class MockStableMediaLog : public stable::mojom::MediaLog {
218 explicit MockStableMediaLog(
219 mojo::PendingReceiver<stable::mojom::MediaLog> pending_receiver)
220 : receiver_(this, std::move(pending_receiver)) {}
221 MockStableMediaLog(const MockStableMediaLog&) = delete;
222 MockStableMediaLog& operator=(const MockStableMediaLog&) = delete;
223 ~MockStableMediaLog() override = default;
225 // stable::mojom::MediaLog implementation.
226 MOCK_METHOD1(AddLogRecord, void(const MediaLogRecord& event));
229 mojo::Receiver<stable::mojom::MediaLog> receiver_;
232 // AuxiliaryEndpoints groups the endpoints that support the operation of a
233 // StableVideoDecoderService and that come from the Construct() call. That way,
234 // tests can easily poke at one endpoint and set expectations on the other. For
235 // example, a test might want to simulate the scenario in which a frame has been
236 // decoded by the underlying mojom::VideoDecoder. In this case, the test can
237 // call |video_decoder_client_remote|->OnVideoFrameDecoded() and then set an
238 // expectation on |mock_stable_video_decoder_client|->OnVideoFrameDecoded().
239 struct AuxiliaryEndpoints {
240 // |video_decoder_client_remote| is the client that the underlying
241 // mojom::VideoDecoder receives through the Construct() call. Tests can make
242 // calls on it and those calls should ultimately be received by the
243 // |mock_stable_video_decoder_client|.
244 mojo::AssociatedRemote<mojom::VideoDecoderClient> video_decoder_client_remote;
245 std::unique_ptr<StrictMock<MockStableVideoDecoderClient>>
246 mock_stable_video_decoder_client;
248 // |media_log_remote| is the MediaLog that the underlying mojom::VideoDecoder
249 // receives through the Construct() call. Tests can make calls on it and those
250 // calls should ultimately be received by the |mock_stable_media_log|.
251 mojo::Remote<mojom::MediaLog> media_log_remote;
252 std::unique_ptr<StrictMock<MockStableMediaLog>> mock_stable_media_log;
254 // Tests can use |stable_video_frame_handle_releaser_remote| to simulate
255 // releasing a VideoFrame.
256 // |mock_video_frame_handle_releaser| is the VideoFrameHandleReleaser that's
257 // setup when the underlying mojom::VideoDecoder receives a Construct() call.
258 // Tests can make calls on |stable_video_frame_handle_releaser_remote| and
259 // they should be ultimately received by the
260 // |mock_video_frame_handle_releaser|.
261 mojo::Remote<stable::mojom::VideoFrameHandleReleaser>
262 stable_video_frame_handle_releaser_remote;
263 std::unique_ptr<StrictMock<MockVideoFrameHandleReleaser>>
264 mock_video_frame_handle_releaser;
266 // |mojo_decoder_buffer_reader| wraps the reading end of the data pipe that
267 // the underlying mojom::VideoDecoder receives through the Construct() call.
268 // Tests can write data using the |mojo_decoder_buffer_writer| and that data
269 // should be ultimately received by the |mojo_decoder_buffer_reader|.
270 std::unique_ptr<MojoDecoderBufferWriter> mojo_decoder_buffer_writer;
271 std::unique_ptr<MojoDecoderBufferReader> mojo_decoder_buffer_reader;
274 // Calls Construct() on |stable_video_decoder_remote| and, if
275 // |expect_construct_call| is true, expects a corresponding Construct() call on
276 // |mock_video_decoder| which is assumed to be the backing decoder of
277 // |stable_video_decoder_remote|. Returns nullptr if the expectations on
278 // |mock_video_decoder| are violated. Otherwise, returns an AuxiliaryEndpoints
279 // instance that contains the supporting endpoints that tests can use to
280 // interact with the auxiliary interfaces used by the
281 // |stable_video_decoder_remote|.
282 std::unique_ptr<AuxiliaryEndpoints> ConstructStableVideoDecoder(
283 mojo::Remote<stable::mojom::StableVideoDecoder>&
284 stable_video_decoder_remote,
285 StrictMock<MockVideoDecoder>& mock_video_decoder,
286 bool expect_construct_call) {
287 constexpr gfx::ColorSpace kTargetColorSpace = gfx::ColorSpace::CreateSRGB();
288 if (expect_construct_call) {
289 EXPECT_CALL(mock_video_decoder,
290 DoConstruct(/*command_buffer_id=*/_,
291 /*target_color_space=*/kTargetColorSpace));
293 mojo::PendingAssociatedRemote<stable::mojom::VideoDecoderClient>
294 stable_video_decoder_client_remote;
295 auto mock_stable_video_decoder_client =
296 std::make_unique<StrictMock<MockStableVideoDecoderClient>>(
297 stable_video_decoder_client_remote
298 .InitWithNewEndpointAndPassReceiver());
300 mojo::PendingRemote<stable::mojom::MediaLog> stable_media_log_remote;
301 auto mock_stable_media_log = std::make_unique<StrictMock<MockStableMediaLog>>(
302 stable_media_log_remote.InitWithNewPipeAndPassReceiver());
304 mojo::Remote<stable::mojom::VideoFrameHandleReleaser>
305 video_frame_handle_releaser_remote;
307 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle;
308 std::unique_ptr<MojoDecoderBufferWriter> mojo_decoder_buffer_writer =
309 MojoDecoderBufferWriter::Create(
310 GetDefaultDecoderBufferConverterCapacity(DemuxerStream::VIDEO),
311 &remote_consumer_handle);
313 stable_video_decoder_remote->Construct(
314 std::move(stable_video_decoder_client_remote),
315 std::move(stable_media_log_remote),
316 video_frame_handle_releaser_remote.BindNewPipeAndPassReceiver(),
317 std::move(remote_consumer_handle), kTargetColorSpace);
318 stable_video_decoder_remote.FlushForTesting();
320 if (!Mock::VerifyAndClearExpectations(&mock_video_decoder))
323 auto auxiliary_endpoints = std::make_unique<AuxiliaryEndpoints>();
325 auxiliary_endpoints->video_decoder_client_remote =
326 mock_video_decoder.TakeClientRemote();
327 auxiliary_endpoints->mock_stable_video_decoder_client =
328 std::move(mock_stable_video_decoder_client);
330 auxiliary_endpoints->media_log_remote =
331 mock_video_decoder.TakeMediaLogRemote();
332 auxiliary_endpoints->mock_stable_media_log = std::move(mock_stable_media_log);
334 auxiliary_endpoints->stable_video_frame_handle_releaser_remote =
335 std::move(video_frame_handle_releaser_remote);
336 auxiliary_endpoints->mock_video_frame_handle_releaser =
337 mock_video_decoder.TakeVideoFrameHandleReleaser();
339 auxiliary_endpoints->mojo_decoder_buffer_writer =
340 std::move(mojo_decoder_buffer_writer);
341 auxiliary_endpoints->mojo_decoder_buffer_reader =
342 mock_video_decoder.TakeMojoDecoderBufferReader();
344 return auxiliary_endpoints;
347 class StableVideoDecoderServiceTest : public testing::Test {
349 StableVideoDecoderServiceTest()
350 : stable_video_decoder_factory_service_(
351 gpu::GpuFeatureInfo(),
352 /*enable_direct_video_decoder=*/true) {
353 stable_video_decoder_factory_service_
354 .SetVideoDecoderCreationCallbackForTesting(
355 video_decoder_creation_cb_.Get());
358 StableVideoDecoderServiceTest(const StableVideoDecoderServiceTest&) = delete;
359 StableVideoDecoderServiceTest& operator=(
360 const StableVideoDecoderServiceTest&) = delete;
361 ~StableVideoDecoderServiceTest() override = default;
363 void SetUp() override {
364 mojo::PendingReceiver<stable::mojom::StableVideoDecoderFactory>
365 stable_video_decoder_factory_receiver;
366 stable_video_decoder_factory_remote_ =
367 mojo::Remote<stable::mojom::StableVideoDecoderFactory>(
368 stable_video_decoder_factory_receiver
369 .InitWithNewPipeAndPassRemote());
370 stable_video_decoder_factory_service_.BindReceiver(
371 std::move(stable_video_decoder_factory_receiver),
372 /*disconnect_cb=*/base::DoNothing());
373 ASSERT_TRUE(stable_video_decoder_factory_remote_.is_connected());
377 mojo::Remote<stable::mojom::StableVideoDecoder> CreateStableVideoDecoder(
378 std::unique_ptr<StrictMock<MockVideoDecoder>> dst_video_decoder,
379 mojo::PendingRemote<stable::mojom::StableVideoDecoderTracker> tracker) {
380 // Each CreateStableVideoDecoder() should result in exactly one call to the
381 // video decoder creation callback, i.e., the
382 // StableVideoDecoderFactoryService should not re-use mojom::VideoDecoder
383 // implementation instances.
384 EXPECT_CALL(video_decoder_creation_cb_, Run(_, _))
385 .WillOnce(Return(ByMove(std::move(dst_video_decoder))));
386 mojo::PendingReceiver<stable::mojom::StableVideoDecoder>
387 stable_video_decoder_receiver;
388 mojo::Remote<stable::mojom::StableVideoDecoder> video_decoder_remote(
389 stable_video_decoder_receiver.InitWithNewPipeAndPassRemote());
390 stable_video_decoder_factory_remote_->CreateStableVideoDecoder(
391 std::move(stable_video_decoder_receiver), std::move(tracker));
392 stable_video_decoder_factory_remote_.FlushForTesting();
393 if (!Mock::VerifyAndClearExpectations(&video_decoder_creation_cb_))
395 return video_decoder_remote;
398 base::test::TaskEnvironment task_environment_;
399 StrictMock<base::MockRepeatingCallback<std::unique_ptr<
400 mojom::VideoDecoder>(MojoMediaClient*, MojoCdmServiceContext*)>>
401 video_decoder_creation_cb_;
402 StableVideoDecoderFactoryService stable_video_decoder_factory_service_;
403 mojo::Remote<stable::mojom::StableVideoDecoderFactory>
404 stable_video_decoder_factory_remote_;
405 mojo::Remote<stable::mojom::StableVideoDecoder> stable_video_decoder_remote_;
408 // Tests that we can create multiple StableVideoDecoder implementation instances
409 // through the StableVideoDecoderFactory and that they can exist concurrently.
410 TEST_F(StableVideoDecoderServiceTest, FactoryCanCreateStableVideoDecoders) {
411 std::vector<mojo::Remote<stable::mojom::StableVideoDecoder>>
412 stable_video_decoder_remotes;
413 constexpr size_t kNumConcurrentDecoders = 5u;
414 for (size_t i = 0u; i < kNumConcurrentDecoders; i++) {
415 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
416 auto stable_video_decoder_remote =
417 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
418 stable_video_decoder_remotes.push_back(
419 std::move(stable_video_decoder_remote));
421 for (const auto& remote : stable_video_decoder_remotes) {
422 ASSERT_TRUE(remote.is_bound());
423 ASSERT_TRUE(remote.is_connected());
427 // Tests that a call to stable::mojom::VideoDecoder::Construct() gets routed
428 // correctly to the underlying mojom::VideoDecoder.
429 TEST_F(StableVideoDecoderServiceTest, StableVideoDecoderCanBeConstructed) {
430 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
431 auto* mock_video_decoder_raw = mock_video_decoder.get();
432 auto stable_video_decoder_remote =
433 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
434 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
435 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
436 ASSERT_TRUE(ConstructStableVideoDecoder(stable_video_decoder_remote,
437 *mock_video_decoder_raw,
438 /*expect_construct_call=*/true));
441 // Tests that if two calls to stable::mojom::VideoDecoder::Construct() are made,
442 // only one is routed to the underlying mojom::VideoDecoder.
443 TEST_F(StableVideoDecoderServiceTest,
444 StableVideoDecoderCannotBeConstructedTwice) {
445 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
446 auto* mock_video_decoder_raw = mock_video_decoder.get();
447 auto stable_video_decoder_remote =
448 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
449 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
450 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
451 EXPECT_TRUE(ConstructStableVideoDecoder(stable_video_decoder_remote,
452 *mock_video_decoder_raw,
453 /*expect_construct_call=*/true));
454 EXPECT_TRUE(ConstructStableVideoDecoder(stable_video_decoder_remote,
455 *mock_video_decoder_raw,
456 /*expect_construct_call=*/false));
459 // Tests that a call to stable::mojom::VideoDecoder::GetSupportedConfigs() gets
460 // routed correctly to the underlying mojom::VideoDecoder. Also tests that the
461 // underlying mojom::VideoDecoder's reply gets routed correctly back to the
463 TEST_F(StableVideoDecoderServiceTest,
464 StableVideoDecoderCanGetSupportedConfigs) {
465 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
466 auto* mock_video_decoder_raw = mock_video_decoder.get();
467 auto stable_video_decoder_remote =
468 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
469 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
470 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
472 StrictMock<base::MockOnceCallback<void(
473 const std::vector<SupportedVideoDecoderConfig>& supported_configs,
474 VideoDecoderType decoder_type)>>
475 get_supported_configs_cb_to_send;
476 mojom::VideoDecoder::GetSupportedConfigsCallback
477 received_get_supported_configs_cb;
478 constexpr VideoDecoderType kDecoderTypeToReplyWith = VideoDecoderType::kVaapi;
479 const std::vector<SupportedVideoDecoderConfig>
480 supported_configs_to_reply_with({
481 {/*profile_min=*/H264PROFILE_MIN, /*profile_max=*/H264PROFILE_MAX,
482 /*coded_size_min=*/gfx::Size(320, 180),
483 /*coded_size_max=*/gfx::Size(1280, 720), /*allow_encrypted=*/false,
484 /*require_encrypted=*/false},
485 {/*profile_min=*/VP9PROFILE_MIN, /*profile_max=*/VP9PROFILE_MAX,
486 /*coded_size_min=*/gfx::Size(8, 8),
487 /*coded_size_max=*/gfx::Size(640, 360), /*allow_encrypted=*/true,
488 /*require_encrypted=*/true},
490 std::vector<SupportedVideoDecoderConfig> received_supported_configs;
492 EXPECT_CALL(*mock_video_decoder_raw, GetSupportedConfigs(/*callback=*/_))
493 .WillOnce([&](mojom::VideoDecoder::GetSupportedConfigsCallback callback) {
494 received_get_supported_configs_cb = std::move(callback);
496 EXPECT_CALL(get_supported_configs_cb_to_send, Run(_, kDecoderTypeToReplyWith))
497 .WillOnce(SaveArg<0>(&received_supported_configs));
499 stable_video_decoder_remote->GetSupportedConfigs(
500 get_supported_configs_cb_to_send.Get());
501 stable_video_decoder_remote.FlushForTesting();
502 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mock_video_decoder_raw));
504 std::move(received_get_supported_configs_cb)
505 .Run(supported_configs_to_reply_with, kDecoderTypeToReplyWith);
506 task_environment_.RunUntilIdle();
508 EXPECT_EQ(received_supported_configs, supported_configs_to_reply_with);
511 // Tests that a call to stable::mojom::VideoDecoder::Initialize() gets routed
512 // correctly to the underlying mojom::VideoDecoder. Also tests that when the
513 // underlying mojom::VideoDecoder calls the initialization callback, the call
514 // gets routed to the client.
515 TEST_F(StableVideoDecoderServiceTest, StableVideoDecoderCanBeInitialized) {
516 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
517 auto* mock_video_decoder_raw = mock_video_decoder.get();
518 auto stable_video_decoder_remote =
519 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
520 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
521 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
522 auto auxiliary_endpoints = ConstructStableVideoDecoder(
523 stable_video_decoder_remote, *mock_video_decoder_raw,
524 /*expect_construct_call=*/true);
525 ASSERT_TRUE(auxiliary_endpoints);
527 const VideoDecoderConfig config_to_send = CreateValidVideoDecoderConfig();
528 VideoDecoderConfig received_config;
529 constexpr bool kLowDelay = true;
530 constexpr absl::optional<base::UnguessableToken> kCdmId = absl::nullopt;
531 StrictMock<base::MockOnceCallback<void(
532 const media::DecoderStatus& status, bool needs_bitstream_conversion,
533 int32_t max_decode_requests, VideoDecoderType decoder_type,
534 bool needs_transcryption)>>
535 initialize_cb_to_send;
536 mojom::VideoDecoder::InitializeCallback received_initialize_cb;
537 const DecoderStatus kDecoderStatus = DecoderStatus::Codes::kAborted;
538 constexpr bool kNeedsBitstreamConversion = true;
539 constexpr int32_t kMaxDecodeRequests = 123;
540 constexpr VideoDecoderType kDecoderType = VideoDecoderType::kVda;
542 EXPECT_CALL(*mock_video_decoder_raw,
543 Initialize(/*config=*/_, kLowDelay, kCdmId,
545 .WillOnce([&](const VideoDecoderConfig& config, bool low_delay,
546 const absl::optional<base::UnguessableToken>& cdm_id,
547 mojom::VideoDecoder::InitializeCallback callback) {
548 received_config = config;
549 received_initialize_cb = std::move(callback);
551 EXPECT_CALL(initialize_cb_to_send,
552 Run(kDecoderStatus, kNeedsBitstreamConversion, kMaxDecodeRequests,
553 kDecoderType, /*needs_transcryption=*/false));
554 stable_video_decoder_remote->Initialize(
555 config_to_send, kLowDelay,
556 mojo::PendingRemote<stable::mojom::StableCdmContext>(),
557 initialize_cb_to_send.Get());
558 stable_video_decoder_remote.FlushForTesting();
559 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mock_video_decoder_raw));
561 std::move(received_initialize_cb)
562 .Run(kDecoderStatus, kNeedsBitstreamConversion, kMaxDecodeRequests,
564 task_environment_.RunUntilIdle();
567 // Tests that the StableVideoDecoderService rejects a call to
568 // stable::mojom::VideoDecoder::Initialize() before
569 // stable::mojom::VideoDecoder::Construct() gets called.
570 TEST_F(StableVideoDecoderServiceTest,
571 StableVideoDecoderCannotBeInitializedBeforeConstruction) {
572 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
573 auto stable_video_decoder_remote =
574 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
575 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
576 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
578 const VideoDecoderConfig config_to_send = CreateValidVideoDecoderConfig();
579 constexpr bool kLowDelay = true;
580 StrictMock<base::MockOnceCallback<void(
581 const media::DecoderStatus& status, bool needs_bitstream_conversion,
582 int32_t max_decode_requests, VideoDecoderType decoder_type,
583 bool needs_transcryption)>>
584 initialize_cb_to_send;
586 EXPECT_CALL(initialize_cb_to_send,
587 Run(DecoderStatus(DecoderStatus::Codes::kFailed),
588 /*needs_bitstream_conversion=*/false,
589 /*max_decode_requests=*/1, VideoDecoderType::kUnknown,
590 /*needs_transcryption=*/false));
591 stable_video_decoder_remote->Initialize(
592 config_to_send, kLowDelay,
593 mojo::PendingRemote<stable::mojom::StableCdmContext>(),
594 initialize_cb_to_send.Get());
595 stable_video_decoder_remote.FlushForTesting();
598 // Tests that a call to stable::mojom::VideoDecoder::Decode() gets routed
599 // correctly to the underlying mojom::VideoDecoder and that the data pipe is
600 // plumbed correctly. Also tests that when the underlying mojom::VideoDecoder
601 // calls the decode callback, the call gets routed to the client.
602 TEST_F(StableVideoDecoderServiceTest, StableVideoDecoderCanDecode) {
603 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
604 auto* mock_video_decoder_raw = mock_video_decoder.get();
605 auto stable_video_decoder_remote =
606 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
607 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
608 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
609 auto auxiliary_endpoints = ConstructStableVideoDecoder(
610 stable_video_decoder_remote, *mock_video_decoder_raw,
611 /*expect_construct_call=*/true);
612 ASSERT_TRUE(auxiliary_endpoints);
613 ASSERT_TRUE(auxiliary_endpoints->mojo_decoder_buffer_writer);
614 ASSERT_TRUE(auxiliary_endpoints->mojo_decoder_buffer_reader);
616 constexpr uint8_t kEncodedData[] = {1, 2, 3};
617 scoped_refptr<DecoderBuffer> decoder_buffer_to_send =
618 DecoderBuffer::CopyFrom(kEncodedData, std::size(kEncodedData));
619 decoder_buffer_to_send->WritableSideData().secure_handle = 42;
620 ASSERT_TRUE(decoder_buffer_to_send);
621 mojom::DecoderBufferPtr received_decoder_buffer_ptr;
622 scoped_refptr<DecoderBuffer> received_decoder_buffer;
623 StrictMock<base::MockOnceCallback<void(const media::DecoderStatus& status)>>
625 mojom::VideoDecoder::DecodeCallback received_decode_cb;
626 const DecoderStatus kDecoderStatus = DecoderStatus::Codes::kAborted;
628 EXPECT_CALL(*mock_video_decoder_raw, Decode(/*buffer=*/_, /*callback=*/_))
629 .WillOnce([&](mojom::DecoderBufferPtr buffer,
630 mojom::VideoDecoder::DecodeCallback callback) {
631 received_decoder_buffer_ptr = std::move(buffer);
632 received_decode_cb = std::move(callback);
634 EXPECT_CALL(decode_cb_to_send, Run(kDecoderStatus));
636 auxiliary_endpoints->mojo_decoder_buffer_writer->WriteDecoderBuffer(
637 decoder_buffer_to_send));
638 stable_video_decoder_remote->Decode(decoder_buffer_to_send,
639 decode_cb_to_send.Get());
640 stable_video_decoder_remote.FlushForTesting();
641 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mock_video_decoder_raw));
643 ASSERT_TRUE(received_decoder_buffer_ptr);
644 auxiliary_endpoints->mojo_decoder_buffer_reader->ReadDecoderBuffer(
645 std::move(received_decoder_buffer_ptr),
647 [](scoped_refptr<DecoderBuffer>* dst_buffer,
648 scoped_refptr<DecoderBuffer> buffer) {
649 *dst_buffer = std::move(buffer);
651 &received_decoder_buffer));
652 task_environment_.RunUntilIdle();
653 ASSERT_TRUE(received_decoder_buffer);
655 received_decoder_buffer->MatchesForTesting(*decoder_buffer_to_send));
657 std::move(received_decode_cb).Run(kDecoderStatus);
658 task_environment_.RunUntilIdle();
661 // Tests that the StableVideoDecoderService rejects a call to
662 // stable::mojom::VideoDecoder::Decode() before
663 // stable::mojom::VideoDecoder::Construct() gets called.
664 TEST_F(StableVideoDecoderServiceTest,
665 StableVideoDecoderCannotDecodeBeforeConstruction) {
666 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
667 auto stable_video_decoder_remote =
668 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
669 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
670 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
672 constexpr uint8_t kEncodedData[] = {1, 2, 3};
673 scoped_refptr<DecoderBuffer> decoder_buffer_to_send =
674 DecoderBuffer::CopyFrom(kEncodedData, std::size(kEncodedData));
675 ASSERT_TRUE(decoder_buffer_to_send);
676 StrictMock<base::MockOnceCallback<void(const media::DecoderStatus& status)>>
679 EXPECT_CALL(decode_cb_to_send,
680 Run(DecoderStatus(DecoderStatus::Codes::kFailed)));
681 stable_video_decoder_remote->Decode(decoder_buffer_to_send,
682 decode_cb_to_send.Get());
683 stable_video_decoder_remote.FlushForTesting();
686 // Tests that a call to stable::mojom::VideoDecoder::Reset() gets routed
687 // correctly to the underlying mojom::VideoDecoder. Also tests that when the
688 // underlying mojom::VideoDecoder calls the reset callback, the call gets routed
690 TEST_F(StableVideoDecoderServiceTest, StableVideoDecoderCanBeReset) {
691 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
692 auto* mock_video_decoder_raw = mock_video_decoder.get();
693 auto stable_video_decoder_remote =
694 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
695 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
696 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
697 auto auxiliary_endpoints = ConstructStableVideoDecoder(
698 stable_video_decoder_remote, *mock_video_decoder_raw,
699 /*expect_construct_call=*/true);
700 ASSERT_TRUE(auxiliary_endpoints);
702 StrictMock<base::MockOnceCallback<void()>> reset_cb_to_send;
703 mojom::VideoDecoder::ResetCallback received_reset_cb;
705 EXPECT_CALL(*mock_video_decoder_raw, Reset(/*callback=*/_))
706 .WillOnce([&](mojom::VideoDecoder::ResetCallback callback) {
707 received_reset_cb = std::move(callback);
709 EXPECT_CALL(reset_cb_to_send, Run());
710 stable_video_decoder_remote->Reset(reset_cb_to_send.Get());
711 stable_video_decoder_remote.FlushForTesting();
712 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mock_video_decoder_raw));
714 std::move(received_reset_cb).Run();
715 task_environment_.RunUntilIdle();
718 // Tests that the StableVideoDecoderService doesn't route a
719 // stable::mojom::VideoDecoder::Reset() call to the underlying
720 // mojom::VideoDecoder before stable::mojom::VideoDecoder::Construct() gets
721 // called and that it just calls the reset callback.
722 TEST_F(StableVideoDecoderServiceTest,
723 StableVideoDecoderCannotBeResetBeforeConstruction) {
724 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
725 auto stable_video_decoder_remote =
726 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
727 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
728 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
730 StrictMock<base::MockOnceCallback<void()>> reset_cb_to_send;
732 EXPECT_CALL(reset_cb_to_send, Run());
733 stable_video_decoder_remote->Reset(reset_cb_to_send.Get());
734 stable_video_decoder_remote.FlushForTesting();
737 // Tests that a call to
738 // stable::mojom::VideoFrameHandleReleaser::ReleaseVideoFrame() gets routed
739 // correctly to the underlying mojom::VideoFrameHandleReleaser.
740 TEST_F(StableVideoDecoderServiceTest, VideoFramesCanBeReleased) {
741 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
742 auto* mock_video_decoder_raw = mock_video_decoder.get();
743 auto stable_video_decoder_remote =
744 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
745 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
746 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
747 auto auxiliary_endpoints = ConstructStableVideoDecoder(
748 stable_video_decoder_remote, *mock_video_decoder_raw,
749 /*expect_construct_call=*/true);
750 ASSERT_TRUE(auxiliary_endpoints);
751 ASSERT_TRUE(auxiliary_endpoints->stable_video_frame_handle_releaser_remote);
752 ASSERT_TRUE(auxiliary_endpoints->mock_video_frame_handle_releaser);
754 const base::UnguessableToken release_token_to_send =
755 base::UnguessableToken::Create();
756 const absl::optional<gpu::SyncToken> expected_release_sync_token =
760 *auxiliary_endpoints->mock_video_frame_handle_releaser,
761 ReleaseVideoFrame(release_token_to_send, expected_release_sync_token));
762 auxiliary_endpoints->stable_video_frame_handle_releaser_remote
763 ->ReleaseVideoFrame(release_token_to_send);
764 auxiliary_endpoints->stable_video_frame_handle_releaser_remote
768 TEST_F(StableVideoDecoderServiceTest,
769 StableVideoDecoderClientReceivesOnVideoFrameDecodedEvent) {
770 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
771 auto* mock_video_decoder_raw = mock_video_decoder.get();
772 auto stable_video_decoder_remote =
773 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
774 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
775 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
776 auto auxiliary_endpoints = ConstructStableVideoDecoder(
777 stable_video_decoder_remote, *mock_video_decoder_raw,
778 /*expect_construct_call=*/true);
779 ASSERT_TRUE(auxiliary_endpoints);
780 ASSERT_TRUE(auxiliary_endpoints->video_decoder_client_remote);
781 ASSERT_TRUE(auxiliary_endpoints->mock_stable_video_decoder_client);
783 const auto token_for_release = base::UnguessableToken::Create();
784 scoped_refptr<VideoFrame> video_frame_to_send =
785 CreateTestNV12GpuMemoryBufferVideoFrame();
786 ASSERT_TRUE(video_frame_to_send);
787 stable::mojom::VideoFramePtr video_frame_received;
788 constexpr bool kCanReadWithoutStalling = true;
790 *auxiliary_endpoints->mock_stable_video_decoder_client,
791 OnVideoFrameDecoded(_, kCanReadWithoutStalling, token_for_release))
792 .WillOnce(WithArgs<0>(
793 [&video_frame_received](stable::mojom::VideoFramePtr frame) {
794 video_frame_received = std::move(frame);
796 auxiliary_endpoints->video_decoder_client_remote->OnVideoFrameDecoded(
797 video_frame_to_send, kCanReadWithoutStalling, token_for_release);
798 auxiliary_endpoints->video_decoder_client_remote.FlushForTesting();
799 ASSERT_TRUE(video_frame_received);
800 EXPECT_FALSE(video_frame_received->metadata.end_of_stream);
801 EXPECT_TRUE(video_frame_received->metadata.read_lock_fences_enabled);
802 EXPECT_TRUE(video_frame_received->metadata.power_efficient);
803 EXPECT_TRUE(video_frame_received->metadata.allow_overlay);
806 // Tests that a mojom::VideoDecoderClient::OnWaiting() call originating from the
807 // underlying mojom::VideoDecoder gets forwarded to the
808 // stable::mojom::VideoDecoderClient correctly.
809 TEST_F(StableVideoDecoderServiceTest,
810 StableVideoDecoderClientReceivesOnWaitingEvent) {
811 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
812 auto* mock_video_decoder_raw = mock_video_decoder.get();
813 auto stable_video_decoder_remote =
814 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
815 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
816 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
817 auto auxiliary_endpoints = ConstructStableVideoDecoder(
818 stable_video_decoder_remote, *mock_video_decoder_raw,
819 /*expect_construct_call=*/true);
820 ASSERT_TRUE(auxiliary_endpoints);
821 ASSERT_TRUE(auxiliary_endpoints->video_decoder_client_remote);
822 ASSERT_TRUE(auxiliary_endpoints->mock_stable_video_decoder_client);
824 constexpr WaitingReason kWaitingReason = WaitingReason::kNoDecryptionKey;
825 EXPECT_CALL(*auxiliary_endpoints->mock_stable_video_decoder_client,
826 OnWaiting(kWaitingReason));
827 auxiliary_endpoints->video_decoder_client_remote->OnWaiting(kWaitingReason);
828 auxiliary_endpoints->video_decoder_client_remote.FlushForTesting();
831 // Tests that a mojom::MediaLog::AddLogRecord() call originating from the
832 // underlying mojom::VideoDecoder gets forwarded to the stable::mojom::MediaLog
834 TEST_F(StableVideoDecoderServiceTest,
835 StableVideoDecoderClientReceivesAddLogRecordEvent) {
836 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
837 auto* mock_video_decoder_raw = mock_video_decoder.get();
838 auto stable_video_decoder_remote =
839 CreateStableVideoDecoder(std::move(mock_video_decoder), /*tracker=*/{});
840 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
841 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
842 auto auxiliary_endpoints = ConstructStableVideoDecoder(
843 stable_video_decoder_remote, *mock_video_decoder_raw,
844 /*expect_construct_call=*/true);
845 ASSERT_TRUE(auxiliary_endpoints);
846 ASSERT_TRUE(auxiliary_endpoints->media_log_remote);
847 ASSERT_TRUE(auxiliary_endpoints->mock_stable_media_log);
849 MediaLogRecord media_log_record_to_send;
850 media_log_record_to_send.id = 2;
851 media_log_record_to_send.type = MediaLogRecord::Type::kMediaStatus;
852 media_log_record_to_send.params.Set("Test", "Value");
853 media_log_record_to_send.time = base::TimeTicks::Now();
855 EXPECT_CALL(*auxiliary_endpoints->mock_stable_media_log,
856 AddLogRecord(media_log_record_to_send));
857 auxiliary_endpoints->media_log_remote->AddLogRecord(media_log_record_to_send);
858 auxiliary_endpoints->media_log_remote.FlushForTesting();
861 // Tests that a StableVideoDecoderTracker can be used to know when the remote
862 // StableVideoDecoder implementation dies.
863 TEST_F(StableVideoDecoderServiceTest,
864 StableVideoDecoderTrackerDisconnectsWhenStableVideoDecoderDies) {
865 auto mock_video_decoder = std::make_unique<StrictMock<MockVideoDecoder>>();
867 MockStableVideoDecoderTracker tracker;
868 mojo::Receiver<stable::mojom::StableVideoDecoderTracker> tracker_receiver(
870 mojo::PendingRemote<stable::mojom::StableVideoDecoderTracker> tracker_remote =
871 tracker_receiver.BindNewPipeAndPassRemote();
872 StrictMock<base::MockOnceCallback<void()>> tracker_disconnect_cb;
873 tracker_receiver.set_disconnect_handler(tracker_disconnect_cb.Get());
875 auto stable_video_decoder_remote = CreateStableVideoDecoder(
876 std::move(mock_video_decoder), std::move(tracker_remote));
877 ASSERT_TRUE(stable_video_decoder_remote.is_bound());
878 ASSERT_TRUE(stable_video_decoder_remote.is_connected());
880 // Until now, nothing in particular should happen.
881 task_environment_.RunUntilIdle();
882 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&tracker_disconnect_cb));
884 // Once we reset the |stable_video_decoder_remote|, the StableVideoDecoder
885 // implementation should die and the |tracker| should get disconnected.
886 EXPECT_CALL(tracker_disconnect_cb, Run());
887 stable_video_decoder_remote.reset();
888 task_environment_.RunUntilIdle();