Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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 "base/strings/string_number_conversions.h" | |
| 6 #include "base/strings/string_split.h" | |
| 7 #include "cc/layers/video_frame_provider.h" | |
| 8 #include "content/public/renderer/media_stream_renderer_factory.h" | |
| 9 #include "content/renderer/media/webmediaplayer_ms.h" | |
| 10 #include "content/renderer/media/webmediaplayer_ms_compositor.h" | |
| 11 #include "content/renderer/render_frame_impl.h" | |
| 12 #include "media/base/test_helpers.h" | |
| 13 #include "media/base/video_frame.h" | |
| 14 #include "third_party/WebKit/public/platform/WebMediaPlayer.h" | |
| 15 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" | |
| 16 | |
| 17 namespace content { | |
| 18 | |
| 19 class WebMediaPlayerMSTest; | |
|
mcasas
2015/11/04 22:20:31
Why this forward declaration?
qiangchen
2015/11/06 19:14:58
Done.
| |
| 20 | |
| 21 class MockCB { | |
| 22 public: | |
| 23 MOCK_METHOD0(StartRendering, void()); | |
| 24 MOCK_METHOD0(StopRendering, void()); | |
| 25 | |
| 26 MOCK_METHOD1(SetWebLayer, void(bool)); | |
| 27 MOCK_METHOD1(NetworkStateChanged, void(blink::WebMediaPlayer::NetworkState)); | |
| 28 MOCK_METHOD1(ReadyStateChanged, void(blink::WebMediaPlayer::ReadyState)); | |
| 29 void VerifyAndClearExpectations() { | |
| 30 // Note: the raw value of "this" could be different from &mock_cb_. | |
| 31 // So this is not equivalent with calling | |
| 32 // VerifyAndClearExpectations(&mock_cb_) outside. | |
| 33 testing::Mock::VerifyAndClearExpectations(this); | |
| 34 } | |
| 35 }; | |
| 36 | |
| 37 struct TestFrame { | |
| 38 enum TestFrameType { | |
| 39 NORMAL_FRAME, | |
| 40 BROKEN_FRAME, | |
| 41 TEST_BRAKE // Signal to pause message loop. | |
| 42 }; | |
| 43 TestFrame(TestFrameType input_category, | |
| 44 const scoped_refptr<media::VideoFrame>& input_frame) | |
| 45 : category(input_category), frame(input_frame) {} | |
| 46 | |
| 47 TestFrameType category; | |
| 48 scoped_refptr<media::VideoFrame> frame; | |
| 49 }; | |
| 50 | |
| 51 class ReusableMessageLoopEvent { | |
|
mcasas
2015/11/04 22:20:31
How's this class different from media::WaitableMes
qiangchen
2015/11/06 19:14:58
The main reason I made this class is to deal with
| |
| 52 public: | |
| 53 ReusableMessageLoopEvent() : event_(new media::WaitableMessageLoopEvent()) {} | |
| 54 | |
| 55 base::Closure GetClosure() { return event_->GetClosure(); } | |
| 56 | |
| 57 media::PipelineStatusCB GetPipelineStatusCB() { | |
| 58 return event_->GetPipelineStatusCB(); | |
| 59 } | |
| 60 | |
| 61 void RunAndWait() { | |
| 62 event_->RunAndWait(); | |
| 63 event_.reset(new media::WaitableMessageLoopEvent()); | |
| 64 } | |
| 65 | |
| 66 void RunAndWaitForStatus(media::PipelineStatus expected) { | |
| 67 event_->RunAndWaitForStatus(expected); | |
| 68 event_.reset(new media::WaitableMessageLoopEvent()); | |
| 69 } | |
| 70 | |
| 71 private: | |
| 72 scoped_ptr<media::WaitableMessageLoopEvent> event_; | |
| 73 }; | |
| 74 | |
| 75 // The class mainly used to inject VideoFrames into WebMediaPlayerMS. | |
| 76 class MockVideoFrameProvider : public VideoFrameProvider { | |
| 77 public: | |
| 78 MockVideoFrameProvider(base::MessageLoop* message_loop, | |
| 79 ReusableMessageLoopEvent* message_loop_controller, | |
| 80 const base::Closure& error_cb, | |
| 81 const VideoFrameProvider::RepaintCB& repaint_cb) | |
| 82 : started_(false), | |
| 83 message_loop_(message_loop), | |
| 84 message_loop_controller_(message_loop_controller), | |
| 85 error_cb_(error_cb), | |
| 86 repaint_cb_(repaint_cb), | |
| 87 delay_(base::TimeDelta::FromSecondsD(1.0 / 30.0)) {} | |
| 88 | |
| 89 // Implementation of VideoFrameProvider | |
| 90 void Start() override { | |
| 91 started_ = true; | |
|
mcasas
2015/11/04 22:20:31
Do not inline method bodies if the body is >= 2 li
qiangchen
2015/11/06 19:14:58
Done.
| |
| 92 paused_ = false; | |
| 93 message_loop_->PostTask(FROM_HERE, | |
| 94 base::Bind(&MockVideoFrameProvider::InjectFrame, | |
| 95 base::Unretained(this))); | |
| 96 } | |
| 97 | |
| 98 void Stop() override { | |
| 99 started_ = false; | |
| 100 frames_.clear(); | |
| 101 } | |
| 102 | |
| 103 void Play() override { | |
| 104 CHECK(started_); | |
| 105 paused_ = false; | |
| 106 } | |
| 107 | |
| 108 void Pause() override { | |
| 109 CHECK(started_); | |
| 110 paused_ = true; | |
| 111 } | |
| 112 | |
| 113 // Methods for test use | |
| 114 void PrepareFrame(TestFrame::TestFrameType category, | |
| 115 const scoped_refptr<media::VideoFrame>& frame) { | |
| 116 frames_.push_back(TestFrame(category, frame)); | |
| 117 } | |
| 118 | |
| 119 void QueueFrames(const std::vector<int>& input) { | |
| 120 for (const int token : input) { | |
| 121 if (token == -1) { | |
|
mcasas
2015/11/04 22:20:31
please add anonymous enums for -1 and -2,
enum {
qiangchen
2015/11/06 19:14:57
Done. Just pull the TestFrameType out to be an ano
| |
| 122 PrepareFrame(TestFrame::TestFrameType::BROKEN_FRAME, nullptr); | |
| 123 continue; | |
| 124 } | |
| 125 | |
| 126 if (token == -2) { | |
| 127 PrepareFrame(TestFrame::TestFrameType::TEST_BRAKE, nullptr); | |
| 128 continue; | |
| 129 } | |
| 130 | |
| 131 if (token >= 0) { | |
| 132 gfx::Size natural_size = media::TestVideoConfig::NormalCodedSize(); | |
| 133 auto frame = media::VideoFrame::CreateFrame( | |
| 134 media::PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size), | |
| 135 natural_size, base::TimeDelta::FromMilliseconds(token)); | |
| 136 | |
| 137 frame->metadata()->SetTimeTicks( | |
| 138 media::VideoFrameMetadata::Key::REFERENCE_TIME, | |
| 139 base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(token)); | |
| 140 | |
| 141 PrepareFrame(TestFrame::TestFrameType::NORMAL_FRAME, frame); | |
| 142 continue; | |
| 143 } | |
| 144 | |
| 145 CHECK(false) << "Unrecognized token: " << token; | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 bool Started() { return started_; } | |
| 150 | |
| 151 bool Paused() { return paused_; } | |
| 152 | |
| 153 private: | |
| 154 ~MockVideoFrameProvider() override {} | |
| 155 | |
| 156 // Main function that pushes frame into WebMediaPlayerMS | |
| 157 void InjectFrame() { | |
|
mcasas
2015/11/04 22:20:31
If this is just meant to be run on |message_loop_|
qiangchen
2015/11/06 19:14:58
Done.
| |
| 158 if (!started_) | |
| 159 return; | |
| 160 | |
| 161 if (frames_.empty()) { | |
| 162 message_loop_controller_->GetClosure().Run(); | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 auto frame = frames_.front(); | |
| 167 frames_.pop_front(); | |
| 168 | |
| 169 if (frame.category == TestFrame::TestFrameType::BROKEN_FRAME) { | |
| 170 error_cb_.Run(); | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 // For pause case, the provider will still let the stream continue, but | |
| 175 // not send the frames to the player. As is the same case in reality. | |
| 176 if (frame.category == TestFrame::TestFrameType::NORMAL_FRAME) { | |
| 177 if (!paused_) | |
| 178 repaint_cb_.Run(frame.frame); | |
| 179 | |
| 180 size_t i = 0; | |
| 181 while (i < frames_.size() && | |
| 182 frames_[i].category != TestFrame::TestFrameType::NORMAL_FRAME) { | |
| 183 ++i; | |
| 184 } | |
| 185 | |
| 186 if (i < frames_.size()) { | |
| 187 delay_ = (frames_[i].frame->timestamp() - frame.frame->timestamp()) / | |
| 188 (i + 1); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 message_loop_->PostDelayedTask( | |
| 193 FROM_HERE, base::Bind(&MockVideoFrameProvider::InjectFrame, | |
| 194 base::Unretained(this)), | |
| 195 delay_); | |
| 196 | |
| 197 if (frame.category == TestFrame::TestFrameType::TEST_BRAKE) | |
| 198 message_loop_controller_->GetClosure().Run(); | |
| 199 } | |
| 200 | |
| 201 bool started_; | |
| 202 bool paused_; | |
| 203 | |
| 204 base::MessageLoop* message_loop_; | |
| 205 ReusableMessageLoopEvent* message_loop_controller_; | |
| 206 base::Closure error_cb_; | |
| 207 VideoFrameProvider::RepaintCB repaint_cb_; | |
|
mcasas
2015/11/04 22:20:31
I believe all these 4 members can be const.
qiangchen
2015/11/06 19:14:57
Done.
| |
| 208 | |
| 209 std::deque<TestFrame> frames_; | |
| 210 base::TimeDelta delay_; | |
| 211 }; | |
| 212 | |
| 213 // The class is used to generate MockVideoProvider | |
|
mcasas
2015/11/04 22:20:31
"... used to generate _a_ MockVideoProvider".
qiangchen
2015/11/06 19:14:58
Done.
| |
| 214 class MockRenderFactory : public MediaStreamRendererFactory { | |
| 215 public: | |
| 216 MockRenderFactory(base::MessageLoop* message_loop, | |
| 217 ReusableMessageLoopEvent* message_loop_controller) | |
| 218 : message_loop_(message_loop), | |
| 219 message_loop_controller_(message_loop_controller) {} | |
| 220 | |
| 221 scoped_refptr<VideoFrameProvider> GetVideoFrameProvider( | |
| 222 const GURL& url, | |
| 223 const base::Closure& error_cb, | |
| 224 const VideoFrameProvider::RepaintCB& repaint_cb, | |
| 225 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | |
| 226 const scoped_refptr<base::TaskRunner>& worker_task_runner, | |
| 227 media::GpuVideoAcceleratorFactories* gpu_factories) override { | |
| 228 provider_ = new MockVideoFrameProvider( | |
| 229 message_loop_, message_loop_controller_, error_cb, repaint_cb); | |
| 230 | |
| 231 return provider_; | |
| 232 } | |
| 233 | |
| 234 MockVideoFrameProvider* GetVideoFrameProvider() { | |
| 235 return static_cast<MockVideoFrameProvider*>(provider_.get()); | |
| 236 } | |
| 237 | |
| 238 scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer( | |
| 239 const GURL& url, | |
| 240 int render_frame_id, | |
| 241 const std::string& device_id, | |
| 242 const url::Origin& security_origin) override { | |
| 243 return nullptr; | |
| 244 } | |
| 245 | |
| 246 private: | |
| 247 base::MessageLoop* message_loop_; | |
|
mcasas
2015/11/04 22:20:31
const?
qiangchen
2015/11/06 19:14:58
Done.
| |
| 248 scoped_refptr<VideoFrameProvider> provider_; | |
| 249 ReusableMessageLoopEvent* message_loop_controller_; | |
|
mcasas
2015/11/04 22:20:31
const?
qiangchen
2015/11/06 19:14:58
Done.
| |
| 250 }; | |
| 251 | |
| 252 class WebMediaPlayerMSTest : public testing::Test, | |
| 253 public blink::WebMediaPlayerClient, | |
| 254 public cc::VideoFrameProvider::Client { | |
| 255 public: | |
| 256 WebMediaPlayerMSTest() | |
| 257 : render_factory_( | |
| 258 new MockRenderFactory(&message_loop_, &message_loop_controller_)), | |
| 259 player_(nullptr, | |
| 260 this, | |
| 261 base::WeakPtr<RenderFrameImpl>(), | |
| 262 new media::MediaLog(), | |
| 263 scoped_ptr<MediaStreamRendererFactory>(render_factory_), | |
| 264 message_loop_.task_runner(), | |
| 265 message_loop_.task_runner(), | |
| 266 message_loop_.task_runner(), | |
| 267 nullptr, | |
| 268 blink::WebString(), | |
| 269 blink::WebSecurityOrigin()), | |
| 270 rendering_(false) {} | |
| 271 ~WebMediaPlayerMSTest() override {} | |
| 272 | |
| 273 MockVideoFrameProvider* LoadAndGetFrameProvider(bool algorithm_enabled) { | |
| 274 MockVideoFrameProvider* provider = render_factory_->GetVideoFrameProvider(); | |
| 275 EXPECT_EQ(nullptr, provider); | |
| 276 | |
| 277 EXPECT_CALL(mock_cb_, NetworkStateChanged( | |
| 278 blink::WebMediaPlayer::NetworkStateLoading)); | |
| 279 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 280 blink::WebMediaPlayer::ReadyStateHaveNothing)); | |
| 281 player_.load(blink::WebMediaPlayer::LoadTypeURL, blink::WebURL(), | |
| 282 blink::WebMediaPlayer::CORSModeUnspecified); | |
| 283 compositor_ = player_.GetCompositorForTesting(); | |
|
mcasas
2015/11/04 22:20:31
You don't need GetCompositorForTesting() since
We
qiangchen
2015/11/06 19:14:58
Done.
| |
| 284 EXPECT_NE(nullptr, compositor_); | |
| 285 compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled); | |
| 286 | |
| 287 provider = render_factory_->GetVideoFrameProvider(); | |
| 288 EXPECT_NE(nullptr, provider); | |
| 289 EXPECT_TRUE(provider->Started()); | |
| 290 | |
| 291 mock_cb_.VerifyAndClearExpectations(); | |
| 292 return provider; | |
| 293 } | |
| 294 | |
| 295 // Implementation of WebMediaPlayerClient | |
| 296 void networkStateChanged() override { | |
| 297 blink::WebMediaPlayer::NetworkState state = player_.networkState(); | |
| 298 mock_cb_.NetworkStateChanged(state); | |
| 299 if (state == blink::WebMediaPlayer::NetworkState::NetworkStateFormatError || | |
| 300 state == blink::WebMediaPlayer::NetworkState::NetworkStateDecodeError || | |
| 301 state == | |
| 302 blink::WebMediaPlayer::NetworkState::NetworkStateNetworkError) { | |
| 303 message_loop_controller_.GetPipelineStatusCB().Run( | |
| 304 media::PipelineStatus::PIPELINE_ERROR_NETWORK); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 void readyStateChanged() override { | |
| 309 blink::WebMediaPlayer::ReadyState state = player_.readyState(); | |
| 310 mock_cb_.ReadyStateChanged(state); | |
| 311 if (state == blink::WebMediaPlayer::ReadyState::ReadyStateHaveEnoughData) | |
| 312 player_.play(); | |
| 313 } | |
| 314 | |
| 315 void timeChanged() override {} | |
| 316 void repaint() override {} | |
| 317 void durationChanged() override {} | |
| 318 void sizeChanged() override {} | |
| 319 void playbackStateChanged() override {} | |
| 320 void setWebLayer(blink::WebLayer* layer) override { | |
| 321 if (layer) { | |
| 322 compositor_->SetVideoFrameProviderClient(this); | |
| 323 } | |
|
mcasas
2015/11/04 22:20:30
No need for {} [1]
" In general, curly braces are
qiangchen
2015/11/06 19:14:58
Done.
| |
| 324 mock_cb_.SetWebLayer(!!layer); | |
| 325 } | |
| 326 | |
| 327 blink::WebMediaPlayer::TrackId addAudioTrack(const blink::WebString& id, | |
| 328 AudioTrackKind, | |
| 329 const blink::WebString& label, | |
| 330 const blink::WebString& language, | |
| 331 bool enabled) override { | |
| 332 return 0; | |
| 333 } | |
| 334 void removeAudioTrack(blink::WebMediaPlayer::TrackId) override {} | |
| 335 | |
| 336 blink::WebMediaPlayer::TrackId addVideoTrack(const blink::WebString& id, | |
| 337 VideoTrackKind, | |
| 338 const blink::WebString& label, | |
| 339 const blink::WebString& language, | |
| 340 bool selected) override { | |
| 341 return 0; | |
| 342 } | |
| 343 void removeVideoTrack(blink::WebMediaPlayer::TrackId) override {} | |
| 344 void addTextTrack(blink::WebInbandTextTrack*) override {} | |
| 345 void removeTextTrack(blink::WebInbandTextTrack*) override {} | |
| 346 void mediaSourceOpened(blink::WebMediaSource*) override {} | |
| 347 void requestSeek(double) override {} | |
| 348 void remoteRouteAvailabilityChanged(bool) override {} | |
| 349 void connectedToRemoteDevice() override {} | |
| 350 void disconnectedFromRemoteDevice() override {} | |
| 351 | |
| 352 // Implementation of cc::VideoFrameProvider::Client | |
| 353 void StopUsingProvider() { | |
| 354 if (rendering_) | |
| 355 StopRendering(); | |
| 356 } | |
| 357 | |
| 358 void StartRendering() { | |
| 359 if (!rendering_) { | |
| 360 rendering_ = true; | |
| 361 message_loop_.PostTask(FROM_HERE, | |
| 362 base::Bind(&WebMediaPlayerMSTest::RenderFrame, | |
| 363 base::Unretained(this))); | |
| 364 } | |
| 365 mock_cb_.StartRendering(); | |
| 366 } | |
| 367 | |
| 368 void StopRendering() { | |
| 369 rendering_ = false; | |
| 370 mock_cb_.StopRendering(); | |
| 371 } | |
| 372 void DidReceiveFrame() override {} | |
| 373 void DidUpdateMatrix(const float* matrix) override {} | |
| 374 | |
| 375 // For test use | |
| 376 void SetBackgroundRendering(bool background_rendering) { | |
| 377 background_rendering_ = background_rendering; | |
| 378 } | |
| 379 | |
| 380 protected: | |
| 381 // Use StrictMock<T> to catch missing/extra callbacks. | |
| 382 testing::StrictMock<MockCB> mock_cb_; | |
| 383 | |
| 384 base::MessageLoop message_loop_; | |
| 385 MockRenderFactory* render_factory_; | |
| 386 WebMediaPlayerMS player_; | |
| 387 WebMediaPlayerMSCompositor* compositor_; | |
| 388 | |
| 389 ReusableMessageLoopEvent message_loop_controller_; | |
| 390 | |
| 391 private: | |
| 392 // Main function trying to ask WebMediaPlayerMS to submit a frame for | |
| 393 // rendering. | |
| 394 void RenderFrame() { | |
| 395 if (!rendering_ || !compositor_) | |
| 396 return; | |
| 397 | |
| 398 base::TimeTicks now = base::TimeTicks::Now(); | |
| 399 base::TimeTicks deadline_min = | |
| 400 now + base::TimeDelta::FromSecondsD(1.0 / 60.0); | |
| 401 base::TimeTicks deadline_max = | |
| 402 deadline_min + base::TimeDelta::FromSecondsD(1.0 / 60.0); | |
| 403 | |
| 404 // Background rendering is different from stop rendering. The rendering loop | |
| 405 // is still running but we do not ask frames from compositor_. And | |
| 406 // background rendering is not initiated from compositor_. | |
| 407 if (!background_rendering_) { | |
| 408 compositor_->UpdateCurrentFrame(deadline_min, deadline_max); | |
| 409 auto frame = compositor_->GetCurrentFrame(); | |
| 410 compositor_->PutCurrentFrame(); | |
| 411 } | |
| 412 message_loop_.PostDelayedTask( | |
| 413 FROM_HERE, | |
| 414 base::Bind(&WebMediaPlayerMSTest::RenderFrame, base::Unretained(this)), | |
| 415 base::TimeDelta::FromSecondsD(1.0 / 60.0)); | |
| 416 } | |
| 417 | |
| 418 bool rendering_; | |
| 419 bool background_rendering_; | |
| 420 }; | |
| 421 | |
| 422 TEST_F(WebMediaPlayerMSTest, Playing_Normal) { | |
| 423 // Workflow: | |
| 424 // 1. WMPMS::Load will generate and start content::VideoFrameProvider. | |
| 425 // 2. content::VideoFrameProvider will start pushing frames into WMPMS | |
| 426 // repeatedly. | |
| 427 // 3. On WMPMS receiving the first frame, a WebLayer will be created. | |
| 428 // 4. The WebLayer will call WMPMSCompositor::SetVideoFrameProviderClient, | |
| 429 // which in turn will trigger cc::VideoFrameProviderClient::StartRendering. | |
| 430 // 5. Then cc::VideoFrameProviderClient will start calling | |
| 431 // WMPMSCompositor::UpdateCurrentFrame, GetCurrentFrame for rendering | |
| 432 // repeatedly. | |
| 433 // 6. When WMPSMS::pause gets called, it should trigger | |
| 434 // content::VideoFrameProvider::Pause, and then the provider will stop | |
| 435 // pushing frames into WMPMS, but instead digesting them; simultanously, it | |
| 436 // should call cc::VideoFrameProviderClient::StopRendering, so the client | |
| 437 // will stop asking frames from WMPMSCompositor. | |
| 438 // 7. When WMPMS::play gets called, evething paused in step 6 should be | |
| 439 // resumed. | |
| 440 MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); | |
| 441 | |
| 442 int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300, | |
| 443 333, 366, 400, 433, 466, 500, 533, 566, 600}; | |
| 444 std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | |
| 445 provider->QueueFrames(timestamps); | |
| 446 | |
| 447 EXPECT_CALL(mock_cb_, SetWebLayer(true)); | |
| 448 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 449 EXPECT_CALL(mock_cb_, | |
| 450 ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); | |
| 451 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 452 blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | |
| 453 message_loop_controller_.RunAndWaitForStatus( | |
| 454 media::PipelineStatus::PIPELINE_OK); | |
| 455 mock_cb_.VerifyAndClearExpectations(); | |
| 456 | |
| 457 EXPECT_CALL(mock_cb_, SetWebLayer(false)); | |
| 458 } | |
| 459 | |
| 460 TEST_F(WebMediaPlayerMSTest, Playing_ErrorFrame) { | |
| 461 MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | |
| 462 | |
| 463 int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300, | |
| 464 333, 366, 400, 433, 466, 500, 533, 566, 600, -1}; | |
| 465 std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | |
| 466 provider->QueueFrames(timestamps); | |
| 467 | |
| 468 EXPECT_CALL(mock_cb_, SetWebLayer(true)); | |
| 469 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 470 EXPECT_CALL(mock_cb_, | |
| 471 ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); | |
| 472 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 473 blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | |
| 474 EXPECT_CALL(mock_cb_, NetworkStateChanged( | |
| 475 blink::WebMediaPlayer::NetworkStateFormatError)); | |
| 476 message_loop_controller_.RunAndWaitForStatus( | |
| 477 media::PipelineStatus::PIPELINE_ERROR_NETWORK); | |
| 478 mock_cb_.VerifyAndClearExpectations(); | |
| 479 | |
| 480 EXPECT_CALL(mock_cb_, SetWebLayer(false)); | |
| 481 } | |
| 482 | |
| 483 TEST_F(WebMediaPlayerMSTest, PlayThenPause) { | |
| 484 MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | |
| 485 | |
| 486 int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266, | |
| 487 300, 333, 366, 400, 433, 466, 500, 533, 566, 600}; | |
| 488 std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | |
| 489 provider->QueueFrames(timestamps); | |
| 490 | |
| 491 EXPECT_CALL(mock_cb_, SetWebLayer(true)); | |
| 492 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 493 EXPECT_CALL(mock_cb_, | |
| 494 ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); | |
| 495 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 496 blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | |
| 497 // Rendering will be "paused" at the TestBrake. | |
| 498 message_loop_controller_.RunAndWaitForStatus( | |
| 499 media::PipelineStatus::PIPELINE_OK); | |
| 500 mock_cb_.VerifyAndClearExpectations(); | |
| 501 | |
| 502 // Here No more rendering. 1. Render should not be called, 2. Frame freeze. | |
| 503 EXPECT_CALL(mock_cb_, StopRendering()); | |
| 504 player_.pause(); | |
| 505 auto prev_frame = compositor_->GetCurrentFrame(); | |
| 506 message_loop_controller_.RunAndWaitForStatus( | |
| 507 media::PipelineStatus::PIPELINE_OK); | |
| 508 auto after_frame = compositor_->GetCurrentFrame(); | |
| 509 EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp()); | |
| 510 mock_cb_.VerifyAndClearExpectations(); | |
| 511 | |
| 512 EXPECT_CALL(mock_cb_, SetWebLayer(false)); | |
| 513 } | |
| 514 | |
| 515 TEST_F(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { | |
| 516 MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | |
| 517 | |
| 518 int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266, 300, | |
| 519 333, 366, 400, 433, -2, 466, 500, 533, 566, 600}; | |
| 520 std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | |
| 521 provider->QueueFrames(timestamps); | |
| 522 | |
| 523 EXPECT_CALL(mock_cb_, SetWebLayer(true)); | |
| 524 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 525 EXPECT_CALL(mock_cb_, | |
| 526 ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); | |
| 527 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 528 blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | |
| 529 // Rendering will be "paused" at the TestBrake. | |
| 530 message_loop_controller_.RunAndWaitForStatus( | |
| 531 media::PipelineStatus::PIPELINE_OK); | |
| 532 mock_cb_.VerifyAndClearExpectations(); | |
| 533 | |
| 534 // Here No more rendering. 1. Render should not be called, 2. Frame freeze. | |
| 535 EXPECT_CALL(mock_cb_, StopRendering()); | |
| 536 player_.pause(); | |
| 537 auto prev_frame = compositor_->GetCurrentFrame(); | |
| 538 message_loop_controller_.RunAndWaitForStatus( | |
| 539 media::PipelineStatus::PIPELINE_OK); | |
| 540 auto after_frame = compositor_->GetCurrentFrame(); | |
| 541 EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp()); | |
| 542 mock_cb_.VerifyAndClearExpectations(); | |
| 543 | |
| 544 // We resume the player | |
| 545 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 546 player_.play(); | |
| 547 prev_frame = compositor_->GetCurrentFrame(); | |
| 548 message_loop_controller_.RunAndWaitForStatus( | |
| 549 media::PipelineStatus::PIPELINE_OK); | |
| 550 after_frame = compositor_->GetCurrentFrame(); | |
| 551 EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | |
| 552 mock_cb_.VerifyAndClearExpectations(); | |
| 553 | |
| 554 EXPECT_CALL(mock_cb_, SetWebLayer(false)); | |
| 555 } | |
| 556 | |
| 557 TEST_F(WebMediaPlayerMSTest, BackgroudRendering) { | |
| 558 MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); | |
| 559 | |
| 560 int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266, 300, | |
| 561 333, 366, 400, 433, -2, 466, 500, 533, 566, 600}; | |
| 562 std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | |
| 563 provider->QueueFrames(timestamps); | |
| 564 | |
| 565 EXPECT_CALL(mock_cb_, SetWebLayer(true)); | |
| 566 EXPECT_CALL(mock_cb_, StartRendering()); | |
| 567 EXPECT_CALL(mock_cb_, | |
| 568 ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); | |
| 569 EXPECT_CALL(mock_cb_, ReadyStateChanged( | |
| 570 blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | |
| 571 // Rendering will be "paused" at the TestBrake. | |
| 572 message_loop_controller_.RunAndWaitForStatus( | |
| 573 media::PipelineStatus::PIPELINE_OK); | |
| 574 mock_cb_.VerifyAndClearExpectations(); | |
| 575 | |
| 576 // Switch to background rendering, expect rendering to continue | |
| 577 SetBackgroundRendering(true); | |
| 578 auto prev_frame = compositor_->GetCurrentFrame(); | |
| 579 message_loop_controller_.RunAndWaitForStatus( | |
| 580 media::PipelineStatus::PIPELINE_OK); | |
| 581 auto after_frame = compositor_->GetCurrentFrame(); | |
| 582 EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | |
| 583 | |
| 584 // Switch to foreground rendering | |
| 585 SetBackgroundRendering(false); | |
| 586 prev_frame = compositor_->GetCurrentFrame(); | |
| 587 message_loop_controller_.RunAndWaitForStatus( | |
| 588 media::PipelineStatus::PIPELINE_OK); | |
| 589 after_frame = compositor_->GetCurrentFrame(); | |
| 590 EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | |
| 591 mock_cb_.VerifyAndClearExpectations(); | |
| 592 | |
| 593 EXPECT_CALL(mock_cb_, SetWebLayer(false)); | |
| 594 } | |
| 595 } // namespace content | |
| OLD | NEW |