summaryrefslogtreecommitdiff
path: root/chromium/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
blob: 539553512c861f1ce3f822ee9e39a69a25376acc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media_capture_from_element/html_video_element_capturer_source.h"
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/base/limits.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebMediaPlayer.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"

using ::testing::_;
using ::testing::InSequence;
using ::testing::Mock;
using ::testing::SaveArg;

namespace content {

ACTION_P(RunClosure, closure) {
  closure.Run();
}

// An almost empty WebMediaPlayer to override paint() method.
class MockWebMediaPlayer : public blink::WebMediaPlayer,
                           public base::SupportsWeakPtr<MockWebMediaPlayer> {
 public:
  MockWebMediaPlayer()  = default;
  ~MockWebMediaPlayer() override = default;

  void Load(LoadType, const blink::WebMediaPlayerSource&, CORSMode) override {}
  void Play() override {}
  void Pause() override {}
  void Seek(double seconds) override {}
  void SetRate(double) override {}
  void SetVolume(double) override {}
  void EnterPictureInPicture() override {}
  blink::WebTimeRanges Buffered() const override {
    return blink::WebTimeRanges();
  }
  blink::WebTimeRanges Seekable() const override {
    return blink::WebTimeRanges();
  }
  void SetSinkId(const blink::WebString& sinkId,
                 const blink::WebSecurityOrigin&,
                 blink::WebSetSinkIdCallbacks*) override {}
  bool HasVideo() const override { return true; }
  bool HasAudio() const override { return false; }
  blink::WebSize NaturalSize() const override { return blink::WebSize(16, 10); }
  blink::WebSize VisibleRect() const override { return blink::WebSize(16, 10); }
  bool Paused() const override { return false; }
  bool Seeking() const override { return false; }
  double Duration() const override { return 0.0; }
  double CurrentTime() const override { return 0.0; }
  NetworkState GetNetworkState() const override { return kNetworkStateEmpty; }
  ReadyState GetReadyState() const override { return kReadyStateHaveNothing; }
  blink::WebString GetErrorMessage() const override {
    return blink::WebString();
  }

  bool DidLoadingProgress() override { return true; }
  bool DidGetOpaqueResponseFromServiceWorker() const override { return false; }
  bool HasSingleSecurityOrigin() const override { return true; }
  bool DidPassCORSAccessCheck() const override { return true; }
  double MediaTimeForTimeValue(double timeValue) const override { return 0.0; }
  unsigned DecodedFrameCount() const override { return 0; }
  unsigned DroppedFrameCount() const override { return 0; }
  unsigned CorruptedFrameCount() const override { return 0; }
  size_t AudioDecodedByteCount() const override { return 0; }
  size_t VideoDecodedByteCount() const override { return 0; }

  void Paint(blink::WebCanvas* canvas,
             const blink::WebRect& paint_rectangle,
             cc::PaintFlags&,
             int already_uploaded_id,
             VideoFrameUploadMetadata* out_metadata) override {
    // We could fill in |canvas| with a meaningful pattern in ARGB and verify
    // that is correctly captured (as I420) by HTMLVideoElementCapturerSource
    // but I don't think that'll be easy/useful/robust, so just let go here.
    return;
  }
};

class HTMLVideoElementCapturerSourceTest : public testing::Test {
 public:
  HTMLVideoElementCapturerSourceTest()
      : scoped_task_environment_(
            base::test::ScopedTaskEnvironment::MainThreadType::UI),
        web_media_player_(new MockWebMediaPlayer()),
        html_video_capturer_(new HtmlVideoElementCapturerSource(
            web_media_player_->AsWeakPtr(),
            blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
            blink::scheduler::GetSingleThreadTaskRunnerForTesting())) {}

  // Necessary callbacks and MOCK_METHODS for them.
  MOCK_METHOD2(DoOnDeliverFrame,
               void(const scoped_refptr<media::VideoFrame>&, base::TimeTicks));
  void OnDeliverFrame(const scoped_refptr<media::VideoFrame>& video_frame,
                    base::TimeTicks estimated_capture_time) {
    DoOnDeliverFrame(video_frame, estimated_capture_time);
  }

  MOCK_METHOD1(DoOnRunning, void(bool));
  void OnRunning(bool state) { DoOnRunning(state); }

 protected:
  // We need some kind of message loop to allow |html_video_capturer_| to
  // schedule capture events.
  const base::test::ScopedTaskEnvironment scoped_task_environment_;

  std::unique_ptr<MockWebMediaPlayer> web_media_player_;
  std::unique_ptr<HtmlVideoElementCapturerSource> html_video_capturer_;
};

// Constructs and destructs all objects, in particular |html_video_capturer_|
// and its inner object(s). This is a non trivial sequence.
TEST_F(HTMLVideoElementCapturerSourceTest, ConstructAndDestruct) {}

// Checks that the usual sequence of GetPreferredFormats() ->
// StartCapture() -> StopCapture() works as expected and let it capture two
// frames.
TEST_F(HTMLVideoElementCapturerSourceTest, GetFormatsAndStartAndStop) {
  InSequence s;
  media::VideoCaptureFormats formats =
      html_video_capturer_->GetPreferredFormats();
  ASSERT_EQ(1u, formats.size());
  EXPECT_EQ(web_media_player_->NaturalSize().width,
            formats[0].frame_size.width());
  EXPECT_EQ(web_media_player_->NaturalSize().height,
            formats[0].frame_size.height());

  media::VideoCaptureParams params;
  params.requested_format = formats[0];

  EXPECT_CALL(*this, DoOnRunning(true)).Times(1);

  base::RunLoop run_loop;
  base::Closure quit_closure = run_loop.QuitClosure();
  scoped_refptr<media::VideoFrame> first_frame;
  scoped_refptr<media::VideoFrame> second_frame;
  EXPECT_CALL(*this, DoOnDeliverFrame(_, _)).WillOnce(SaveArg<0>(&first_frame));
  EXPECT_CALL(*this, DoOnDeliverFrame(_, _))
      .Times(1)
      .WillOnce(DoAll(SaveArg<0>(&second_frame), RunClosure(quit_closure)));

  html_video_capturer_->StartCapture(
      params, base::Bind(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
                         base::Unretained(this)),
      base::Bind(&HTMLVideoElementCapturerSourceTest::OnRunning,
                 base::Unretained(this)));

  run_loop.Run();

  EXPECT_EQ(0u, first_frame->timestamp().InMilliseconds());
  EXPECT_GT(second_frame->timestamp().InMilliseconds(), 30u);
  html_video_capturer_->StopCapture();
  Mock::VerifyAndClearExpectations(this);
}

// When a new source is created and started, it is stopped in the same task
// when cross-origin data is detected. This test checks that no data is
// delivered in this case.
TEST_F(HTMLVideoElementCapturerSourceTest,
       StartAndStopInSameTaskCaptureZeroFrames) {
  InSequence s;
  media::VideoCaptureFormats formats =
      html_video_capturer_->GetPreferredFormats();
  ASSERT_EQ(1u, formats.size());
  EXPECT_EQ(web_media_player_->NaturalSize().width,
            formats[0].frame_size.width());
  EXPECT_EQ(web_media_player_->NaturalSize().height,
            formats[0].frame_size.height());

  media::VideoCaptureParams params;
  params.requested_format = formats[0];

  EXPECT_CALL(*this, DoOnRunning(true));
  EXPECT_CALL(*this, DoOnDeliverFrame(_, _)).Times(0);

  html_video_capturer_->StartCapture(
      params,
      base::Bind(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
                 base::Unretained(this)),
      base::Bind(&HTMLVideoElementCapturerSourceTest::OnRunning,
                 base::Unretained(this)));
  html_video_capturer_->StopCapture();
  base::RunLoop().RunUntilIdle();

  Mock::VerifyAndClearExpectations(this);
}

}  // namespace content