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