Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Unified Diff: content/renderer/media/webmediaplayer_ms_unittest.cc

Issue 1417533006: Unit test for WebMediaPlayerMS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase and merge some classes together Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/webmediaplayer_ms_unittest.cc
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..912a9cb995268a3a84e7cca826acbecaf8a89659
--- /dev/null
+++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -0,0 +1,595 @@
+// 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 "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "cc/layers/video_frame_provider.h"
+#include "content/public/renderer/media_stream_renderer_factory.h"
+#include "content/renderer/media/webmediaplayer_ms.h"
+#include "content/renderer/media/webmediaplayer_ms_compositor.h"
+#include "content/renderer/render_frame_impl.h"
+#include "media/base/test_helpers.h"
+#include "media/base/video_frame.h"
+#include "third_party/WebKit/public/platform/WebMediaPlayer.h"
+#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
+
+namespace content {
+
+class WebMediaPlayerMSTest;
mcasas 2015/11/04 22:20:31 Why this forward declaration?
qiangchen 2015/11/06 19:14:58 Done.
+
+class MockCB {
+ public:
+ MOCK_METHOD0(StartRendering, void());
+ MOCK_METHOD0(StopRendering, void());
+
+ MOCK_METHOD1(SetWebLayer, void(bool));
+ MOCK_METHOD1(NetworkStateChanged, void(blink::WebMediaPlayer::NetworkState));
+ MOCK_METHOD1(ReadyStateChanged, void(blink::WebMediaPlayer::ReadyState));
+ void VerifyAndClearExpectations() {
+ // Note: the raw value of "this" could be different from &mock_cb_.
+ // So this is not equivalent with calling
+ // VerifyAndClearExpectations(&mock_cb_) outside.
+ testing::Mock::VerifyAndClearExpectations(this);
+ }
+};
+
+struct TestFrame {
+ enum TestFrameType {
+ NORMAL_FRAME,
+ BROKEN_FRAME,
+ TEST_BRAKE // Signal to pause message loop.
+ };
+ TestFrame(TestFrameType input_category,
+ const scoped_refptr<media::VideoFrame>& input_frame)
+ : category(input_category), frame(input_frame) {}
+
+ TestFrameType category;
+ scoped_refptr<media::VideoFrame> frame;
+};
+
+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
+ public:
+ ReusableMessageLoopEvent() : event_(new media::WaitableMessageLoopEvent()) {}
+
+ base::Closure GetClosure() { return event_->GetClosure(); }
+
+ media::PipelineStatusCB GetPipelineStatusCB() {
+ return event_->GetPipelineStatusCB();
+ }
+
+ void RunAndWait() {
+ event_->RunAndWait();
+ event_.reset(new media::WaitableMessageLoopEvent());
+ }
+
+ void RunAndWaitForStatus(media::PipelineStatus expected) {
+ event_->RunAndWaitForStatus(expected);
+ event_.reset(new media::WaitableMessageLoopEvent());
+ }
+
+ private:
+ scoped_ptr<media::WaitableMessageLoopEvent> event_;
+};
+
+// The class mainly used to inject VideoFrames into WebMediaPlayerMS.
+class MockVideoFrameProvider : public VideoFrameProvider {
+ public:
+ MockVideoFrameProvider(base::MessageLoop* message_loop,
+ ReusableMessageLoopEvent* message_loop_controller,
+ const base::Closure& error_cb,
+ const VideoFrameProvider::RepaintCB& repaint_cb)
+ : started_(false),
+ message_loop_(message_loop),
+ message_loop_controller_(message_loop_controller),
+ error_cb_(error_cb),
+ repaint_cb_(repaint_cb),
+ delay_(base::TimeDelta::FromSecondsD(1.0 / 30.0)) {}
+
+ // Implementation of VideoFrameProvider
+ void Start() override {
+ 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.
+ paused_ = false;
+ message_loop_->PostTask(FROM_HERE,
+ base::Bind(&MockVideoFrameProvider::InjectFrame,
+ base::Unretained(this)));
+ }
+
+ void Stop() override {
+ started_ = false;
+ frames_.clear();
+ }
+
+ void Play() override {
+ CHECK(started_);
+ paused_ = false;
+ }
+
+ void Pause() override {
+ CHECK(started_);
+ paused_ = true;
+ }
+
+ // Methods for test use
+ void PrepareFrame(TestFrame::TestFrameType category,
+ const scoped_refptr<media::VideoFrame>& frame) {
+ frames_.push_back(TestFrame(category, frame));
+ }
+
+ void QueueFrames(const std::vector<int>& input) {
+ for (const int token : input) {
+ 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
+ PrepareFrame(TestFrame::TestFrameType::BROKEN_FRAME, nullptr);
+ continue;
+ }
+
+ if (token == -2) {
+ PrepareFrame(TestFrame::TestFrameType::TEST_BRAKE, nullptr);
+ continue;
+ }
+
+ if (token >= 0) {
+ gfx::Size natural_size = media::TestVideoConfig::NormalCodedSize();
+ auto frame = media::VideoFrame::CreateFrame(
+ media::PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size),
+ natural_size, base::TimeDelta::FromMilliseconds(token));
+
+ frame->metadata()->SetTimeTicks(
+ media::VideoFrameMetadata::Key::REFERENCE_TIME,
+ base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(token));
+
+ PrepareFrame(TestFrame::TestFrameType::NORMAL_FRAME, frame);
+ continue;
+ }
+
+ CHECK(false) << "Unrecognized token: " << token;
+ }
+ }
+
+ bool Started() { return started_; }
+
+ bool Paused() { return paused_; }
+
+ private:
+ ~MockVideoFrameProvider() override {}
+
+ // Main function that pushes frame into WebMediaPlayerMS
+ 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.
+ if (!started_)
+ return;
+
+ if (frames_.empty()) {
+ message_loop_controller_->GetClosure().Run();
+ return;
+ }
+
+ auto frame = frames_.front();
+ frames_.pop_front();
+
+ if (frame.category == TestFrame::TestFrameType::BROKEN_FRAME) {
+ error_cb_.Run();
+ return;
+ }
+
+ // For pause case, the provider will still let the stream continue, but
+ // not send the frames to the player. As is the same case in reality.
+ if (frame.category == TestFrame::TestFrameType::NORMAL_FRAME) {
+ if (!paused_)
+ repaint_cb_.Run(frame.frame);
+
+ size_t i = 0;
+ while (i < frames_.size() &&
+ frames_[i].category != TestFrame::TestFrameType::NORMAL_FRAME) {
+ ++i;
+ }
+
+ if (i < frames_.size()) {
+ delay_ = (frames_[i].frame->timestamp() - frame.frame->timestamp()) /
+ (i + 1);
+ }
+ }
+
+ message_loop_->PostDelayedTask(
+ FROM_HERE, base::Bind(&MockVideoFrameProvider::InjectFrame,
+ base::Unretained(this)),
+ delay_);
+
+ if (frame.category == TestFrame::TestFrameType::TEST_BRAKE)
+ message_loop_controller_->GetClosure().Run();
+ }
+
+ bool started_;
+ bool paused_;
+
+ base::MessageLoop* message_loop_;
+ ReusableMessageLoopEvent* message_loop_controller_;
+ base::Closure error_cb_;
+ 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.
+
+ std::deque<TestFrame> frames_;
+ base::TimeDelta delay_;
+};
+
+// 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.
+class MockRenderFactory : public MediaStreamRendererFactory {
+ public:
+ MockRenderFactory(base::MessageLoop* message_loop,
+ ReusableMessageLoopEvent* message_loop_controller)
+ : message_loop_(message_loop),
+ message_loop_controller_(message_loop_controller) {}
+
+ scoped_refptr<VideoFrameProvider> GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const VideoFrameProvider::RepaintCB& repaint_cb,
+ const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+ const scoped_refptr<base::TaskRunner>& worker_task_runner,
+ media::GpuVideoAcceleratorFactories* gpu_factories) override {
+ provider_ = new MockVideoFrameProvider(
+ message_loop_, message_loop_controller_, error_cb, repaint_cb);
+
+ return provider_;
+ }
+
+ MockVideoFrameProvider* GetVideoFrameProvider() {
+ return static_cast<MockVideoFrameProvider*>(provider_.get());
+ }
+
+ scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer(
+ const GURL& url,
+ int render_frame_id,
+ const std::string& device_id,
+ const url::Origin& security_origin) override {
+ return nullptr;
+ }
+
+ private:
+ base::MessageLoop* message_loop_;
mcasas 2015/11/04 22:20:31 const?
qiangchen 2015/11/06 19:14:58 Done.
+ scoped_refptr<VideoFrameProvider> provider_;
+ ReusableMessageLoopEvent* message_loop_controller_;
mcasas 2015/11/04 22:20:31 const?
qiangchen 2015/11/06 19:14:58 Done.
+};
+
+class WebMediaPlayerMSTest : public testing::Test,
+ public blink::WebMediaPlayerClient,
+ public cc::VideoFrameProvider::Client {
+ public:
+ WebMediaPlayerMSTest()
+ : render_factory_(
+ new MockRenderFactory(&message_loop_, &message_loop_controller_)),
+ player_(nullptr,
+ this,
+ base::WeakPtr<RenderFrameImpl>(),
+ new media::MediaLog(),
+ scoped_ptr<MediaStreamRendererFactory>(render_factory_),
+ message_loop_.task_runner(),
+ message_loop_.task_runner(),
+ message_loop_.task_runner(),
+ nullptr,
+ blink::WebString(),
+ blink::WebSecurityOrigin()),
+ rendering_(false) {}
+ ~WebMediaPlayerMSTest() override {}
+
+ MockVideoFrameProvider* LoadAndGetFrameProvider(bool algorithm_enabled) {
+ MockVideoFrameProvider* provider = render_factory_->GetVideoFrameProvider();
+ EXPECT_EQ(nullptr, provider);
+
+ EXPECT_CALL(mock_cb_, NetworkStateChanged(
+ blink::WebMediaPlayer::NetworkStateLoading));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveNothing));
+ player_.load(blink::WebMediaPlayer::LoadTypeURL, blink::WebURL(),
+ blink::WebMediaPlayer::CORSModeUnspecified);
+ 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.
+ EXPECT_NE(nullptr, compositor_);
+ compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled);
+
+ provider = render_factory_->GetVideoFrameProvider();
+ EXPECT_NE(nullptr, provider);
+ EXPECT_TRUE(provider->Started());
+
+ mock_cb_.VerifyAndClearExpectations();
+ return provider;
+ }
+
+ // Implementation of WebMediaPlayerClient
+ void networkStateChanged() override {
+ blink::WebMediaPlayer::NetworkState state = player_.networkState();
+ mock_cb_.NetworkStateChanged(state);
+ if (state == blink::WebMediaPlayer::NetworkState::NetworkStateFormatError ||
+ state == blink::WebMediaPlayer::NetworkState::NetworkStateDecodeError ||
+ state ==
+ blink::WebMediaPlayer::NetworkState::NetworkStateNetworkError) {
+ message_loop_controller_.GetPipelineStatusCB().Run(
+ media::PipelineStatus::PIPELINE_ERROR_NETWORK);
+ }
+ }
+
+ void readyStateChanged() override {
+ blink::WebMediaPlayer::ReadyState state = player_.readyState();
+ mock_cb_.ReadyStateChanged(state);
+ if (state == blink::WebMediaPlayer::ReadyState::ReadyStateHaveEnoughData)
+ player_.play();
+ }
+
+ void timeChanged() override {}
+ void repaint() override {}
+ void durationChanged() override {}
+ void sizeChanged() override {}
+ void playbackStateChanged() override {}
+ void setWebLayer(blink::WebLayer* layer) override {
+ if (layer) {
+ compositor_->SetVideoFrameProviderClient(this);
+ }
mcasas 2015/11/04 22:20:30 No need for {} [1] " In general, curly braces are
qiangchen 2015/11/06 19:14:58 Done.
+ mock_cb_.SetWebLayer(!!layer);
+ }
+
+ blink::WebMediaPlayer::TrackId addAudioTrack(const blink::WebString& id,
+ AudioTrackKind,
+ const blink::WebString& label,
+ const blink::WebString& language,
+ bool enabled) override {
+ return 0;
+ }
+ void removeAudioTrack(blink::WebMediaPlayer::TrackId) override {}
+
+ blink::WebMediaPlayer::TrackId addVideoTrack(const blink::WebString& id,
+ VideoTrackKind,
+ const blink::WebString& label,
+ const blink::WebString& language,
+ bool selected) override {
+ return 0;
+ }
+ void removeVideoTrack(blink::WebMediaPlayer::TrackId) override {}
+ void addTextTrack(blink::WebInbandTextTrack*) override {}
+ void removeTextTrack(blink::WebInbandTextTrack*) override {}
+ void mediaSourceOpened(blink::WebMediaSource*) override {}
+ void requestSeek(double) override {}
+ void remoteRouteAvailabilityChanged(bool) override {}
+ void connectedToRemoteDevice() override {}
+ void disconnectedFromRemoteDevice() override {}
+
+ // Implementation of cc::VideoFrameProvider::Client
+ void StopUsingProvider() {
+ if (rendering_)
+ StopRendering();
+ }
+
+ void StartRendering() {
+ if (!rendering_) {
+ rendering_ = true;
+ message_loop_.PostTask(FROM_HERE,
+ base::Bind(&WebMediaPlayerMSTest::RenderFrame,
+ base::Unretained(this)));
+ }
+ mock_cb_.StartRendering();
+ }
+
+ void StopRendering() {
+ rendering_ = false;
+ mock_cb_.StopRendering();
+ }
+ void DidReceiveFrame() override {}
+ void DidUpdateMatrix(const float* matrix) override {}
+
+ // For test use
+ void SetBackgroundRendering(bool background_rendering) {
+ background_rendering_ = background_rendering;
+ }
+
+ protected:
+ // Use StrictMock<T> to catch missing/extra callbacks.
+ testing::StrictMock<MockCB> mock_cb_;
+
+ base::MessageLoop message_loop_;
+ MockRenderFactory* render_factory_;
+ WebMediaPlayerMS player_;
+ WebMediaPlayerMSCompositor* compositor_;
+
+ ReusableMessageLoopEvent message_loop_controller_;
+
+ private:
+ // Main function trying to ask WebMediaPlayerMS to submit a frame for
+ // rendering.
+ void RenderFrame() {
+ if (!rendering_ || !compositor_)
+ return;
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks deadline_min =
+ now + base::TimeDelta::FromSecondsD(1.0 / 60.0);
+ base::TimeTicks deadline_max =
+ deadline_min + base::TimeDelta::FromSecondsD(1.0 / 60.0);
+
+ // Background rendering is different from stop rendering. The rendering loop
+ // is still running but we do not ask frames from compositor_. And
+ // background rendering is not initiated from compositor_.
+ if (!background_rendering_) {
+ compositor_->UpdateCurrentFrame(deadline_min, deadline_max);
+ auto frame = compositor_->GetCurrentFrame();
+ compositor_->PutCurrentFrame();
+ }
+ message_loop_.PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&WebMediaPlayerMSTest::RenderFrame, base::Unretained(this)),
+ base::TimeDelta::FromSecondsD(1.0 / 60.0));
+ }
+
+ bool rendering_;
+ bool background_rendering_;
+};
+
+TEST_F(WebMediaPlayerMSTest, Playing_Normal) {
+ // Workflow:
+ // 1. WMPMS::Load will generate and start content::VideoFrameProvider.
+ // 2. content::VideoFrameProvider will start pushing frames into WMPMS
+ // repeatedly.
+ // 3. On WMPMS receiving the first frame, a WebLayer will be created.
+ // 4. The WebLayer will call WMPMSCompositor::SetVideoFrameProviderClient,
+ // which in turn will trigger cc::VideoFrameProviderClient::StartRendering.
+ // 5. Then cc::VideoFrameProviderClient will start calling
+ // WMPMSCompositor::UpdateCurrentFrame, GetCurrentFrame for rendering
+ // repeatedly.
+ // 6. When WMPSMS::pause gets called, it should trigger
+ // content::VideoFrameProvider::Pause, and then the provider will stop
+ // pushing frames into WMPMS, but instead digesting them; simultanously, it
+ // should call cc::VideoFrameProviderClient::StopRendering, so the client
+ // will stop asking frames from WMPMSCompositor.
+ // 7. When WMPMS::play gets called, evething paused in step 6 should be
+ // resumed.
+ MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true);
+
+ int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300,
+ 333, 366, 400, 433, 466, 500, 533, 566, 600};
+ std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
+ provider->QueueFrames(timestamps);
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(true));
+ EXPECT_CALL(mock_cb_, StartRendering());
+ EXPECT_CALL(mock_cb_,
+ ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveEnoughData));
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ mock_cb_.VerifyAndClearExpectations();
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(false));
+}
+
+TEST_F(WebMediaPlayerMSTest, Playing_ErrorFrame) {
+ MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false);
+
+ int tokens[] = {0, 33, 66, 100, 133, 166, 200, 233, 266, 300,
+ 333, 366, 400, 433, 466, 500, 533, 566, 600, -1};
+ std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
+ provider->QueueFrames(timestamps);
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(true));
+ EXPECT_CALL(mock_cb_, StartRendering());
+ EXPECT_CALL(mock_cb_,
+ ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveEnoughData));
+ EXPECT_CALL(mock_cb_, NetworkStateChanged(
+ blink::WebMediaPlayer::NetworkStateFormatError));
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_ERROR_NETWORK);
+ mock_cb_.VerifyAndClearExpectations();
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(false));
+}
+
+TEST_F(WebMediaPlayerMSTest, PlayThenPause) {
+ MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false);
+
+ int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266,
+ 300, 333, 366, 400, 433, 466, 500, 533, 566, 600};
+ std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
+ provider->QueueFrames(timestamps);
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(true));
+ EXPECT_CALL(mock_cb_, StartRendering());
+ EXPECT_CALL(mock_cb_,
+ ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveEnoughData));
+ // Rendering will be "paused" at the TestBrake.
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ mock_cb_.VerifyAndClearExpectations();
+
+ // Here No more rendering. 1. Render should not be called, 2. Frame freeze.
+ EXPECT_CALL(mock_cb_, StopRendering());
+ player_.pause();
+ auto prev_frame = compositor_->GetCurrentFrame();
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ auto after_frame = compositor_->GetCurrentFrame();
+ EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp());
+ mock_cb_.VerifyAndClearExpectations();
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(false));
+}
+
+TEST_F(WebMediaPlayerMSTest, PlayThenPauseThenPlay) {
+ MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false);
+
+ int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266, 300,
+ 333, 366, 400, 433, -2, 466, 500, 533, 566, 600};
+ std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
+ provider->QueueFrames(timestamps);
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(true));
+ EXPECT_CALL(mock_cb_, StartRendering());
+ EXPECT_CALL(mock_cb_,
+ ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveEnoughData));
+ // Rendering will be "paused" at the TestBrake.
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ mock_cb_.VerifyAndClearExpectations();
+
+ // Here No more rendering. 1. Render should not be called, 2. Frame freeze.
+ EXPECT_CALL(mock_cb_, StopRendering());
+ player_.pause();
+ auto prev_frame = compositor_->GetCurrentFrame();
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ auto after_frame = compositor_->GetCurrentFrame();
+ EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp());
+ mock_cb_.VerifyAndClearExpectations();
+
+ // We resume the player
+ EXPECT_CALL(mock_cb_, StartRendering());
+ player_.play();
+ prev_frame = compositor_->GetCurrentFrame();
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ after_frame = compositor_->GetCurrentFrame();
+ EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp());
+ mock_cb_.VerifyAndClearExpectations();
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(false));
+}
+
+TEST_F(WebMediaPlayerMSTest, BackgroudRendering) {
+ MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true);
+
+ int tokens[] = {0, 33, 66, 100, 133, -2, 166, 200, 233, 266, 300,
+ 333, 366, 400, 433, -2, 466, 500, 533, 566, 600};
+ std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int));
+ provider->QueueFrames(timestamps);
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(true));
+ EXPECT_CALL(mock_cb_, StartRendering());
+ EXPECT_CALL(mock_cb_,
+ ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata));
+ EXPECT_CALL(mock_cb_, ReadyStateChanged(
+ blink::WebMediaPlayer::ReadyStateHaveEnoughData));
+ // Rendering will be "paused" at the TestBrake.
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ mock_cb_.VerifyAndClearExpectations();
+
+ // Switch to background rendering, expect rendering to continue
+ SetBackgroundRendering(true);
+ auto prev_frame = compositor_->GetCurrentFrame();
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ auto after_frame = compositor_->GetCurrentFrame();
+ EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp());
+
+ // Switch to foreground rendering
+ SetBackgroundRendering(false);
+ prev_frame = compositor_->GetCurrentFrame();
+ message_loop_controller_.RunAndWaitForStatus(
+ media::PipelineStatus::PIPELINE_OK);
+ after_frame = compositor_->GetCurrentFrame();
+ EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp());
+ mock_cb_.VerifyAndClearExpectations();
+
+ EXPECT_CALL(mock_cb_, SetWebLayer(false));
+}
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698