1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6 #include <vector>
7
8 #include <stdint.h>
9
10 #include "base/bind.h"
11 #include "base/callback_forward.h"
12 #include "base/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/test/gmock_callback_support.h"
19 #include "base/test/metrics/histogram_tester.h"
20 #include "base/test/mock_callback.h"
21 #include "base/test/task_environment.h"
22 #include "base/time/time.h"
23 #include "gpu/command_buffer/common/mailbox_holder.h"
24 #include "media/base/decode_status.h"
25 #include "media/base/decoder_buffer.h"
26 #include "media/base/decrypt_config.h"
27 #include "media/base/media_log.h"
28 #include "media/base/mock_media_log.h"
29 #include "media/base/test_helpers.h"
30 #include "media/base/video_decoder.h"
31 #include "media/base/video_frame.h"
32 #include "media/base/waiting.h"
33 #include "media/mojo/clients/mojo_video_decoder.h"
34 #include "media/mojo/services/mojo_cdm_service_context.h"
35 #include "media/mojo/services/mojo_media_client.h"
36 #include "media/mojo/services/mojo_video_decoder_service.h"
37 #include "mojo/public/cpp/bindings/pending_remote.h"
38 #include "mojo/public/cpp/bindings/remote.h"
39 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "ui/gfx/color_space.h"
43
44 using ::base::test::RunOnceCallback;
45 using ::testing::_;
46 using ::testing::AnyNumber;
47 using ::testing::AtLeast;
48 using ::testing::HasSubstr;
49 using ::testing::InSequence;
50 using ::testing::Invoke;
51 using ::testing::Mock;
52 using ::testing::Return;
53 using ::testing::SaveArg;
54 using ::testing::StrictMock;
55
56 namespace media {
57
58 namespace {
59
60 const int kMaxDecodeRequests = 4;
61 const int kErrorDataSize = 7;
62
63 // A mock VideoDecoder with helpful default functionality.
64 // TODO(sandersd): Determine how best to merge this with MockVideoDecoder
65 // declared in mock_filters.h.
66 class MockVideoDecoder : public VideoDecoder {
67 public:
MockVideoDecoder()68 MockVideoDecoder() {
69 // Treat const getters like a NiceMock.
70 EXPECT_CALL(*this, GetDisplayName())
71 .WillRepeatedly(Return("MockVideoDecoder"));
72 EXPECT_CALL(*this, NeedsBitstreamConversion())
73 .WillRepeatedly(Return(false));
74 EXPECT_CALL(*this, CanReadWithoutStalling()).WillRepeatedly(Return(true));
75 EXPECT_CALL(*this, GetMaxDecodeRequests())
76 .WillRepeatedly(Return(kMaxDecodeRequests));
77
78 // For regular methods, only configure a default action.
79 ON_CALL(*this, Decode_(_, _))
80 .WillByDefault(Invoke(this, &MockVideoDecoder::DoDecode));
81 ON_CALL(*this, Reset_(_))
82 .WillByDefault(Invoke(this, &MockVideoDecoder::DoReset));
83 }
84
85 // Re-declare as public.
~MockVideoDecoder()86 ~MockVideoDecoder() override {}
87
88 // media::VideoDecoder implementation
89 MOCK_CONST_METHOD0(GetDisplayName, std::string());
90
91 // Initialize() records values before delegating to the mock method.
Initialize(const VideoDecoderConfig & config,bool,CdmContext *,InitCB init_cb,const OutputCB & output_cb,const WaitingCB & waiting_cb)92 void Initialize(const VideoDecoderConfig& config,
93 bool /* low_delay */,
94 CdmContext* /* cdm_context */,
95 InitCB init_cb,
96 const OutputCB& output_cb,
97 const WaitingCB& waiting_cb) override {
98 config_ = config;
99 output_cb_ = output_cb;
100 waiting_cb_ = waiting_cb;
101 DoInitialize(init_cb);
102 }
103
Decode(scoped_refptr<DecoderBuffer> buffer,DecodeCB cb)104 void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB cb) override {
105 Decode_(std::move(buffer), cb);
106 }
107 MOCK_METHOD2(Decode_, void(scoped_refptr<DecoderBuffer> buffer, DecodeCB&));
Reset(base::OnceClosure cb)108 void Reset(base::OnceClosure cb) override { Reset_(cb); }
109 MOCK_METHOD1(Reset_, void(base::OnceClosure&));
110 MOCK_CONST_METHOD0(NeedsBitstreamConversion, bool());
111 MOCK_CONST_METHOD0(CanReadWithoutStalling, bool());
112 MOCK_CONST_METHOD0(GetMaxDecodeRequests, int());
113
114 // Mock helpers.
115 MOCK_METHOD1(DoInitialize, void(InitCB&));
GetReleaseMailboxCB()116 VideoFrame::ReleaseMailboxCB GetReleaseMailboxCB() {
117 DidGetReleaseMailboxCB();
118 return std::move(release_mailbox_cb);
119 }
120
121 MOCK_METHOD0(DidGetReleaseMailboxCB, void());
122
123 VideoFrame::ReleaseMailboxCB release_mailbox_cb;
124
125 // Returns an output frame immediately.
126 // TODO(sandersd): Extend to support tests of MojoVideoFrame frames.
DoDecode(scoped_refptr<DecoderBuffer> buffer,DecodeCB & decode_cb)127 void DoDecode(scoped_refptr<DecoderBuffer> buffer, DecodeCB& decode_cb) {
128 if (!buffer->end_of_stream()) {
129 if (buffer->data_size() == kErrorDataSize) {
130 // This size buffer indicates that decoder should return an error.
131 // |decode_cb| must not be called from the same stack.
132 base::ThreadTaskRunnerHandle::Get()->PostTask(
133 FROM_HERE,
134 base::BindOnce(std::move(decode_cb), DecodeStatus::DECODE_ERROR));
135 return;
136 }
137 if (buffer->decrypt_config()) {
138 // Simulate the case where outputs are only returned when key arrives.
139 waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
140 } else {
141 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
142 mailbox_holders[0].mailbox.name[0] = 1;
143 scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures(
144 PIXEL_FORMAT_ARGB, mailbox_holders, GetReleaseMailboxCB(),
145 config_.coded_size(), config_.visible_rect(),
146 config_.natural_size(), buffer->timestamp());
147 frame->metadata()->power_efficient = true;
148 output_cb_.Run(frame);
149 }
150 }
151
152 // |decode_cb| must not be called from the same stack.
153 base::ThreadTaskRunnerHandle::Get()->PostTask(
154 FROM_HERE, base::BindOnce(std::move(decode_cb), DecodeStatus::OK));
155 }
156
DoReset(base::OnceClosure & reset_cb)157 void DoReset(base::OnceClosure& reset_cb) {
158 // |reset_cb| must not be called from the same stack.
159 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
160 std::move(reset_cb));
161 }
162
GetWeakPtr()163 base::WeakPtr<MockVideoDecoder> GetWeakPtr() {
164 return weak_this_factory_.GetWeakPtr();
165 }
166
167 private:
168 VideoDecoderConfig config_;
169 OutputCB output_cb_;
170 WaitingCB waiting_cb_;
171 base::WeakPtrFactory<MockVideoDecoder> weak_this_factory_{this};
172
173 DISALLOW_COPY_AND_ASSIGN(MockVideoDecoder);
174 };
175
176 // Proxies CreateVideoDecoder() to a callback.
177 class FakeMojoMediaClient : public MojoMediaClient {
178 public:
179 using CreateVideoDecoderCB =
180 base::RepeatingCallback<std::unique_ptr<VideoDecoder>(MediaLog*)>;
181
FakeMojoMediaClient(CreateVideoDecoderCB create_video_decoder_cb)182 explicit FakeMojoMediaClient(CreateVideoDecoderCB create_video_decoder_cb)
183 : create_video_decoder_cb_(std::move(create_video_decoder_cb)) {}
184
CreateVideoDecoder(scoped_refptr<base::SingleThreadTaskRunner> task_runner,MediaLog * media_log,mojom::CommandBufferIdPtr command_buffer_id,VideoDecoderImplementation implementation,RequestOverlayInfoCB request_overlay_info_cb,const gfx::ColorSpace & target_color_space)185 std::unique_ptr<VideoDecoder> CreateVideoDecoder(
186 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
187 MediaLog* media_log,
188 mojom::CommandBufferIdPtr command_buffer_id,
189 VideoDecoderImplementation implementation,
190 RequestOverlayInfoCB request_overlay_info_cb,
191 const gfx::ColorSpace& target_color_space) override {
192 return create_video_decoder_cb_.Run(media_log);
193 }
194
195 private:
196 CreateVideoDecoderCB create_video_decoder_cb_;
197
198 DISALLOW_COPY_AND_ASSIGN(FakeMojoMediaClient);
199 };
200
201 } // namespace
202
203 class MojoVideoDecoderIntegrationTest : public ::testing::Test {
204 public:
MojoVideoDecoderIntegrationTest()205 MojoVideoDecoderIntegrationTest()
206 : mojo_media_client_(base::BindRepeating(
207 &MojoVideoDecoderIntegrationTest::CreateVideoDecoder,
208 base::Unretained(this))) {}
209
TearDown()210 void TearDown() override {
211 if (client_) {
212 client_.reset();
213 RunUntilIdle();
214 }
215 }
216
217 protected:
RunUntilIdle()218 void RunUntilIdle() { task_environment_.RunUntilIdle(); }
219
SetWriterCapacity(uint32_t capacity)220 void SetWriterCapacity(uint32_t capacity) { writer_capacity_ = capacity; }
221
CreateRemoteVideoDecoder()222 mojo::PendingRemote<mojom::VideoDecoder> CreateRemoteVideoDecoder() {
223 mojo::PendingRemote<mojom::VideoDecoder> remote_video_decoder;
224 mojo::MakeSelfOwnedReceiver(
225 std::make_unique<MojoVideoDecoderService>(&mojo_media_client_,
226 &mojo_cdm_service_context_),
227 remote_video_decoder.InitWithNewPipeAndPassReceiver());
228 return remote_video_decoder;
229 }
230
CreateClient()231 void CreateClient() {
232 DCHECK(!client_);
233 // TODO(sandersd): Pass a GpuVideoAcceleratorFactories so that the cache can
234 // be tested.
235 client_ = std::make_unique<MojoVideoDecoder>(
236 base::ThreadTaskRunnerHandle::Get(), nullptr, &client_media_log_,
237 CreateRemoteVideoDecoder(), VideoDecoderImplementation::kDefault,
238 RequestOverlayInfoCB(), gfx::ColorSpace());
239 if (writer_capacity_)
240 client_->set_writer_capacity_for_testing(writer_capacity_);
241 }
242
Initialize()243 bool Initialize() {
244 CreateClient();
245
246 EXPECT_CALL(*decoder_, DoInitialize(_))
247 .WillOnce(RunOnceCallback<0>(OkStatus()));
248
249 Status result = OkStatus();
250 StrictMock<base::MockCallback<VideoDecoder::InitCB>> init_cb;
251 EXPECT_CALL(init_cb, Run(_)).WillOnce(SaveArg<0>(&result));
252
253 client_->Initialize(TestVideoConfig::NormalH264(), false, nullptr,
254 init_cb.Get(), output_cb_.Get(), waiting_cb_.Get());
255 RunUntilIdle();
256
257 return result.is_ok();
258 }
259
Decode(scoped_refptr<DecoderBuffer> buffer,VideoFrame::ReleaseMailboxCB release_cb=VideoFrame::ReleaseMailboxCB ())260 Status Decode(scoped_refptr<DecoderBuffer> buffer,
261 VideoFrame::ReleaseMailboxCB release_cb =
262 VideoFrame::ReleaseMailboxCB()) {
263 Status result(DecodeStatus::DECODE_ERROR);
264
265 if (!buffer->end_of_stream()) {
266 decoder_->release_mailbox_cb = std::move(release_cb);
267 EXPECT_CALL(*decoder_, DidGetReleaseMailboxCB());
268 }
269 EXPECT_CALL(*decoder_, Decode_(_, _));
270
271 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
272 EXPECT_CALL(decode_cb, Run(_)).WillOnce(SaveArg<0>(&result));
273
274 client_->Decode(buffer, decode_cb.Get());
275 RunUntilIdle();
276
277 return result;
278 }
279
CreateKeyframe(int64_t timestamp_ms)280 scoped_refptr<DecoderBuffer> CreateKeyframe(int64_t timestamp_ms) {
281 // Use 32 bytes to simulated chunked write (with capacity 10; see below).
282 std::vector<uint8_t> data(32, 0);
283
284 scoped_refptr<DecoderBuffer> buffer =
285 DecoderBuffer::CopyFrom(data.data(), data.size());
286
287 buffer->set_timestamp(base::TimeDelta::FromMilliseconds(timestamp_ms));
288 buffer->set_duration(base::TimeDelta::FromMilliseconds(10));
289 buffer->set_is_key_frame(true);
290
291 return buffer;
292 }
293
CreateErrorFrame(int64_t timestamp_ms)294 scoped_refptr<DecoderBuffer> CreateErrorFrame(int64_t timestamp_ms) {
295 std::vector<uint8_t> data(kErrorDataSize, 0);
296
297 scoped_refptr<DecoderBuffer> buffer =
298 DecoderBuffer::CopyFrom(data.data(), data.size());
299
300 buffer->set_timestamp(base::TimeDelta::FromMilliseconds(timestamp_ms));
301 buffer->set_duration(base::TimeDelta::FromMilliseconds(10));
302 buffer->set_is_key_frame(true);
303
304 return buffer;
305 }
306
307 // TODO(xhwang): Add a function to help create encrypted video buffers in
308 // media/base/test_helpers.h.
CreateEncryptedKeyframe(int64_t timestamp_ms)309 scoped_refptr<DecoderBuffer> CreateEncryptedKeyframe(int64_t timestamp_ms) {
310 auto buffer = CreateKeyframe(timestamp_ms);
311
312 const uint8_t kFakeKeyId[] = {0x4b, 0x65, 0x79, 0x20, 0x49, 0x44};
313 const uint8_t kFakeIv[DecryptConfig::kDecryptionKeySize] = {0};
314 buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
315 std::string(reinterpret_cast<const char*>(kFakeKeyId),
316 base::size(kFakeKeyId)),
317 std::string(reinterpret_cast<const char*>(kFakeIv),
318 base::size(kFakeIv)),
319 {}));
320
321 return buffer;
322 }
323
324 // Callback that |client_| will deliver VideoFrames to.
325 StrictMock<base::MockCallback<VideoDecoder::OutputCB>> output_cb_;
326
327 StrictMock<base::MockCallback<WaitingCB>> waiting_cb_;
328
329 // MojoVideoDecoder (client) under test.
330 std::unique_ptr<MojoVideoDecoder> client_;
331
332 // MediaLog that |client_| will deliver log events to.
333 StrictMock<MockMediaLog> client_media_log_;
334
335 // VideoDecoder (impl used by service) under test.
336 // |decoder_owner_| owns the decoder until ownership is transferred to the
337 // |MojoVideoDecoderService|. |decoder_| references it for the duration of its
338 // lifetime.
339 std::unique_ptr<MockVideoDecoder> decoder_owner_ =
340 std::make_unique<MockVideoDecoder>();
341 base::WeakPtr<MockVideoDecoder> decoder_ = decoder_owner_->GetWeakPtr();
342
343 // MediaLog that the service has provided to |decoder_|. This should be
344 // proxied to |client_media_log_|.
345 MediaLog* decoder_media_log_ = nullptr;
346
347 private:
348 // Passes |decoder_| to the service.
CreateVideoDecoder(MediaLog * media_log)349 std::unique_ptr<VideoDecoder> CreateVideoDecoder(MediaLog* media_log) {
350 DCHECK(!decoder_media_log_);
351 decoder_media_log_ = media_log;
352 return std::move(decoder_owner_);
353 }
354
355 base::test::TaskEnvironment task_environment_;
356
357 // Capacity that will be used for the MojoDecoderBufferWriter.
358 uint32_t writer_capacity_ = 0;
359
360 MojoCdmServiceContext mojo_cdm_service_context_;
361
362 // Provides |decoder_| to the service.
363 FakeMojoMediaClient mojo_media_client_;
364
365 DISALLOW_COPY_AND_ASSIGN(MojoVideoDecoderIntegrationTest);
366 };
367
TEST_F(MojoVideoDecoderIntegrationTest,CreateAndDestroy)368 TEST_F(MojoVideoDecoderIntegrationTest, CreateAndDestroy) {}
369
TEST_F(MojoVideoDecoderIntegrationTest,GetSupportedConfigs)370 TEST_F(MojoVideoDecoderIntegrationTest, GetSupportedConfigs) {
371 mojo::Remote<mojom::VideoDecoder> remote_video_decoder(
372 CreateRemoteVideoDecoder());
373 StrictMock<
374 base::MockCallback<mojom::VideoDecoder::GetSupportedConfigsCallback>>
375 callback;
376
377 // TODO(sandersd): Expect there to be an entry.
378 EXPECT_CALL(callback, Run(_));
379 remote_video_decoder->GetSupportedConfigs(callback.Get());
380 RunUntilIdle();
381 }
382
TEST_F(MojoVideoDecoderIntegrationTest,Initialize)383 TEST_F(MojoVideoDecoderIntegrationTest, Initialize) {
384 ASSERT_TRUE(Initialize());
385 EXPECT_EQ(client_->GetDisplayName(), "MojoVideoDecoder");
386 EXPECT_EQ(client_->NeedsBitstreamConversion(), false);
387 EXPECT_EQ(client_->CanReadWithoutStalling(), true);
388 EXPECT_EQ(client_->GetMaxDecodeRequests(), kMaxDecodeRequests);
389 }
390
TEST_F(MojoVideoDecoderIntegrationTest,InitializeFailNoDecoder)391 TEST_F(MojoVideoDecoderIntegrationTest, InitializeFailNoDecoder) {
392 CreateClient();
393
394 StrictMock<base::MockCallback<VideoDecoder::InitCB>> init_cb;
395 EXPECT_CALL(init_cb,
396 Run(HasStatusCode(StatusCode::kMojoDecoderNoWrappedDecoder)));
397
398 // Clear |decoder_| so that Initialize() should fail.
399 decoder_owner_.reset();
400 client_->Initialize(TestVideoConfig::NormalH264(), false, nullptr,
401 init_cb.Get(), output_cb_.Get(), waiting_cb_.Get());
402 RunUntilIdle();
403 }
404
TEST_F(MojoVideoDecoderIntegrationTest,InitializeFailNoCdm)405 TEST_F(MojoVideoDecoderIntegrationTest, InitializeFailNoCdm) {
406 CreateClient();
407
408 StrictMock<base::MockCallback<VideoDecoder::InitCB>> init_cb;
409 EXPECT_CALL(
410 init_cb,
411 Run(HasStatusCode(StatusCode::kDecoderMissingCdmForEncryptedContent)));
412
413 // CdmContext* (3rd parameter) is not provided but the VideoDecoderConfig
414 // specifies encrypted video, so Initialize() should fail.
415 client_->Initialize(TestVideoConfig::NormalEncrypted(), false, nullptr,
416 init_cb.Get(), output_cb_.Get(), waiting_cb_.Get());
417 RunUntilIdle();
418 }
419
TEST_F(MojoVideoDecoderIntegrationTest,MediaLogIsProxied)420 TEST_F(MojoVideoDecoderIntegrationTest, MediaLogIsProxied) {
421 ASSERT_TRUE(Initialize());
422 EXPECT_MEDIA_LOG_ON(client_media_log_, HasSubstr("\"test\""));
423 MEDIA_LOG(DEBUG, decoder_media_log_) << "test";
424 RunUntilIdle();
425 }
426
TEST_F(MojoVideoDecoderIntegrationTest,WaitingForKey)427 TEST_F(MojoVideoDecoderIntegrationTest, WaitingForKey) {
428 ASSERT_TRUE(Initialize());
429
430 auto buffer = CreateEncryptedKeyframe(0);
431 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
432
433 EXPECT_CALL(*decoder_, Decode_(_, _));
434 EXPECT_CALL(waiting_cb_, Run(WaitingReason::kNoDecryptionKey));
435 EXPECT_CALL(decode_cb, Run(IsOkStatus()));
436
437 client_->Decode(buffer, decode_cb.Get());
438 RunUntilIdle();
439 }
440
TEST_F(MojoVideoDecoderIntegrationTest,Decode)441 TEST_F(MojoVideoDecoderIntegrationTest, Decode) {
442 ASSERT_TRUE(Initialize());
443
444 EXPECT_CALL(output_cb_, Run(_));
445 ASSERT_TRUE(Decode(CreateKeyframe(0)).is_ok());
446 Mock::VerifyAndClearExpectations(&output_cb_);
447
448 ASSERT_TRUE(Decode(DecoderBuffer::CreateEOSBuffer()).is_ok());
449 }
450
TEST_F(MojoVideoDecoderIntegrationTest,Release)451 TEST_F(MojoVideoDecoderIntegrationTest, Release) {
452 ASSERT_TRUE(Initialize());
453
454 StrictMock<base::MockCallback<VideoFrame::ReleaseMailboxCB>> release_cb;
455 scoped_refptr<VideoFrame> frame;
456
457 EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame));
458 ASSERT_TRUE(Decode(CreateKeyframe(0), release_cb.Get()).is_ok());
459 Mock::VerifyAndClearExpectations(&output_cb_);
460
461 EXPECT_CALL(release_cb, Run(_));
462 frame = nullptr;
463 RunUntilIdle();
464 }
465
TEST_F(MojoVideoDecoderIntegrationTest,ReleaseAfterShutdown)466 TEST_F(MojoVideoDecoderIntegrationTest, ReleaseAfterShutdown) {
467 ASSERT_TRUE(Initialize());
468
469 StrictMock<base::MockCallback<VideoFrame::ReleaseMailboxCB>> release_cb;
470 scoped_refptr<VideoFrame> frame;
471
472 EXPECT_CALL(output_cb_, Run(_)).WillOnce(SaveArg<0>(&frame));
473 ASSERT_TRUE(Decode(CreateKeyframe(0), release_cb.Get()).is_ok());
474 Mock::VerifyAndClearExpectations(&output_cb_);
475
476 client_.reset();
477 RunUntilIdle();
478
479 EXPECT_CALL(release_cb, Run(_));
480 frame = nullptr;
481 RunUntilIdle();
482 }
483
TEST_F(MojoVideoDecoderIntegrationTest,ResetDuringDecode)484 TEST_F(MojoVideoDecoderIntegrationTest, ResetDuringDecode) {
485 ASSERT_TRUE(Initialize());
486
487 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
488 StrictMock<base::MockCallback<base::OnceClosure>> reset_cb;
489
490 EXPECT_CALL(*decoder_, DidGetReleaseMailboxCB()).Times(AtLeast(0));
491 EXPECT_CALL(output_cb_, Run(_)).Times(kMaxDecodeRequests);
492 EXPECT_CALL(*decoder_, Decode_(_, _)).Times(kMaxDecodeRequests);
493 EXPECT_CALL(*decoder_, Reset_(_));
494
495 InSequence s; // Make sure all callbacks are fired in order.
496 EXPECT_CALL(decode_cb, Run(_)).Times(kMaxDecodeRequests);
497 EXPECT_CALL(reset_cb, Run());
498
499 int64_t timestamp_ms = 0;
500 for (int j = 0; j < kMaxDecodeRequests; ++j) {
501 client_->Decode(CreateKeyframe(timestamp_ms++), decode_cb.Get());
502 }
503
504 client_->Reset(reset_cb.Get());
505
506 RunUntilIdle();
507 }
508
TEST_F(MojoVideoDecoderIntegrationTest,ResetDuringDecode_ChunkedWrite)509 TEST_F(MojoVideoDecoderIntegrationTest, ResetDuringDecode_ChunkedWrite) {
510 // Use a small writer capacity to force chunked write.
511 SetWriterCapacity(10);
512 ASSERT_TRUE(Initialize());
513
514 VideoFrame::ReleaseMailboxCB release_cb = VideoFrame::ReleaseMailboxCB();
515 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
516 StrictMock<base::MockCallback<base::OnceClosure>> reset_cb;
517
518 EXPECT_CALL(*decoder_, DidGetReleaseMailboxCB()).Times(AtLeast(0));
519 EXPECT_CALL(output_cb_, Run(_)).Times(kMaxDecodeRequests);
520 EXPECT_CALL(*decoder_, Decode_(_, _)).Times(kMaxDecodeRequests);
521 EXPECT_CALL(*decoder_, Reset_(_));
522
523 InSequence s; // Make sure all callbacks are fired in order.
524 EXPECT_CALL(decode_cb, Run(_)).Times(kMaxDecodeRequests);
525 EXPECT_CALL(reset_cb, Run());
526
527 int64_t timestamp_ms = 0;
528 for (int j = 0; j < kMaxDecodeRequests; ++j) {
529 client_->Decode(CreateKeyframe(timestamp_ms++), decode_cb.Get());
530 }
531
532 client_->Reset(reset_cb.Get());
533
534 RunUntilIdle();
535 }
536
TEST_F(MojoVideoDecoderIntegrationTest,InitialPlaybackUMASuccess)537 TEST_F(MojoVideoDecoderIntegrationTest, InitialPlaybackUMASuccess) {
538 base::HistogramTester histogram_tester_;
539 const int frames_to_decode = kMojoDecoderInitialPlaybackFrameCount;
540
541 ASSERT_TRUE(Initialize());
542
543 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
544
545 EXPECT_CALL(*decoder_, DidGetReleaseMailboxCB()).Times(AnyNumber());
546 EXPECT_CALL(output_cb_, Run(_)).Times(frames_to_decode);
547 EXPECT_CALL(*decoder_, Decode_(_, _)).Times(frames_to_decode);
548
549 EXPECT_CALL(decode_cb, Run(IsOkStatus())).Times(frames_to_decode);
550
551 for (int i = 0; i < frames_to_decode - 1; i++)
552 client_->Decode(CreateKeyframe(i * 16), decode_cb.Get());
553
554 RunUntilIdle();
555 histogram_tester_.ExpectBucketCount(
556 kMojoVideoDecoderInitialPlaybackSuccessCodecCounterUMA, 1, 0);
557
558 client_->Decode(CreateKeyframe(0), decode_cb.Get());
559
560 RunUntilIdle();
561 histogram_tester_.ExpectBucketCount(
562 kMojoVideoDecoderInitialPlaybackSuccessCodecCounterUMA, 1, 1);
563 }
564
TEST_F(MojoVideoDecoderIntegrationTest,InitialPlaybackUMAError)565 TEST_F(MojoVideoDecoderIntegrationTest, InitialPlaybackUMAError) {
566 base::HistogramTester histogram_tester_;
567 const int frames_to_decode = kMojoDecoderInitialPlaybackFrameCount;
568
569 ASSERT_TRUE(Initialize());
570
571 StrictMock<base::MockCallback<VideoDecoder::DecodeCB>> decode_cb;
572
573 EXPECT_CALL(*decoder_, DidGetReleaseMailboxCB()).Times(AnyNumber());
574 EXPECT_CALL(output_cb_, Run(_)).Times(frames_to_decode - 1);
575 EXPECT_CALL(*decoder_, Decode_(_, _)).Times(frames_to_decode);
576
577 EXPECT_CALL(decode_cb, Run(IsOkStatus())).Times(frames_to_decode - 1);
578
579 EXPECT_CALL(decode_cb, Run(IsDecodeErrorStatus())).Times(1);
580
581 for (int i = 0; i < frames_to_decode - 1; i++)
582 client_->Decode(CreateKeyframe(i * 16), decode_cb.Get());
583
584 RunUntilIdle();
585 histogram_tester_.ExpectBucketCount(
586 kMojoVideoDecoderInitialPlaybackErrorCodecCounterUMA, 1, 0);
587 histogram_tester_.ExpectBucketCount(
588 kMojoVideoDecoderInitialPlaybackSuccessCodecCounterUMA, 1, 0);
589
590 client_->Decode(CreateErrorFrame(0), decode_cb.Get());
591
592 RunUntilIdle();
593 histogram_tester_.ExpectBucketCount(
594 kMojoVideoDecoderInitialPlaybackErrorCodecCounterUMA, 1, 1);
595 histogram_tester_.ExpectBucketCount(
596 kMojoVideoDecoderInitialPlaybackSuccessCodecCounterUMA, 1, 0);
597 }
598
599 } // namespace media
600