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