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

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: Style 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..368d2a5abf250643a48715bc5b848060015df860
--- /dev/null
+++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -0,0 +1,621 @@
+// 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 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);
+ }
+};
mcasas 2015/12/02 19:42:31 Suggestion: Move all these MOCK_METHOD? to WebMedi
qiangchen 2015/12/05 00:24:14 Done.
+
+enum {
+ 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.
+ BROKEN_FRAME = -1,
+ TEST_BRAKE = -2 // Signal to pause message loop.
+};
+
+struct TestFrame {
+ TestFrame(int input_category,
+ const scoped_refptr<media::VideoFrame>& input_frame)
+ : category(input_category), frame(input_frame) {}
+
+ int category;
+ scoped_refptr<media::VideoFrame> frame;
+};
mcasas 2015/12/02 19:42:31 I'd use here std::pair<scoped_refptr<VideoFrame>,
qiangchen 2015/12/05 00:24:15 Done.
+
+class ReusableMessageLoopEvent {
+ public:
+ ReusableMessageLoopEvent() : event_(new media::WaitableMessageLoopEvent()) {}
+
+ base::Closure GetClosure() const { return event_->GetClosure(); }
+
+ media::PipelineStatusCB GetPipelineStatusCB() const {
+ 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 {
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
+ 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;
+ void Stop() override;
+ void Play() override;
+ void Pause() override;
+
+ // Methods for test use
+ void PrepareFrame(int category,
+ const scoped_refptr<media::VideoFrame>& frame);
+ void QueueFrames(const std::vector<int>& input);
+ bool Started() { return started_; }
+ bool Paused() { return paused_; }
+
+ private:
+ ~MockVideoFrameProvider() override {}
+
+ // Main function that pushes frame into WebMediaPlayerMS
+ void InjectFrame();
+
+ bool started_;
+ bool paused_;
+
+ base::MessageLoop* const message_loop_;
+ ReusableMessageLoopEvent* const message_loop_controller_;
+ const base::Closure error_cb_;
+ const VideoFrameProvider::RepaintCB repaint_cb_;
+
+ std::deque<TestFrame> frames_;
+ base::TimeDelta delay_;
+};
+
+void MockVideoFrameProvider::Start() {
+ started_ = true;
+ paused_ = false;
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this)));
+}
+
+void MockVideoFrameProvider::Stop() {
+ started_ = false;
+ frames_.clear();
+}
+
+void MockVideoFrameProvider::Play() {
+ CHECK(started_);
+ paused_ = false;
+}
+
+void MockVideoFrameProvider::Pause() {
+ CHECK(started_);
+ paused_ = true;
+}
+
+void MockVideoFrameProvider::PrepareFrame(
+ int category,
+ const scoped_refptr<media::VideoFrame>& frame) {
+ frames_.push_back(TestFrame(category, frame));
+}
+
+void MockVideoFrameProvider::QueueFrames(const std::vector<int>& input) {
+ for (const int token : input) {
+ if (token < 0) {
+ PrepareFrame(token, 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(NORMAL_FRAME, frame);
+ continue;
+ }
+
+ CHECK(false) << "Unrecognized token: " << token;
+ }
+}
+
+void MockVideoFrameProvider::InjectFrame() {
+ DCHECK(message_loop_->task_runner()->BelongsToCurrentThread());
+ if (!started_)
+ return;
+
+ if (frames_.empty()) {
+ message_loop_controller_->GetClosure().Run();
+ return;
+ }
+
+ auto frame = frames_.front();
+ frames_.pop_front();
+
+ if (frame.category == 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 == NORMAL_FRAME) {
+ if (!paused_)
+ repaint_cb_.Run(frame.frame);
+
+ size_t i = 0;
+ while (i < frames_.size() && frames_[i].category != NORMAL_FRAME) {
+ ++i;
+ }
+
+ if (i < frames_.size()) {
+ delay_ =
+ (frames_[i].frame->timestamp() - frame.frame->timestamp()) / (i + 1);
+ }
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.
+ }
+
+ message_loop_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this)),
+ delay_);
+
+ // This will pause the |message_loop_|, and the purpose is to allow main test
+ // function to do some operations (e.g. call pause(), switch to background
+ // rendering, etc) on WebMediaPlayerMS before resuming the |message_loop_|.
+ if (frame.category == TEST_BRAKE)
+ message_loop_controller_->GetClosure().Run();
+}
+
+// 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.
+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;
+
+ MockVideoFrameProvider* GetVideoFrameProvider() {
+ 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
+ }
+
+ 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* const message_loop_;
+ 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
+ ReusableMessageLoopEvent* const message_loop_controller_;
+};
+
+scoped_refptr<VideoFrameProvider> MockRenderFactory::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) {
+ provider_ = new MockVideoFrameProvider(
+ message_loop_, message_loop_controller_, error_cb, repaint_cb);
+
+ return provider_;
+}
+
+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);
+
+ // Implementation of WebMediaPlayerClient
+ void networkStateChanged() override;
+ void readyStateChanged() override;
+ void timeChanged() override {}
+ void repaint() override {}
+ void durationChanged() override {}
+ void sizeChanged() override {}
+ void playbackStateChanged() override {}
+ void setWebLayer(blink::WebLayer* layer) override;
+ 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() override;
+ void StartRendering() override;
+ void StopRendering() override;
+ 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_;
mcasas 2015/12/02 19:42:31 All this passing around |message_loop_| as naked p
qiangchen 2015/12/05 00:24:15 Done.
+ 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();
+
+ bool rendering_;
+ bool background_rendering_;
+};
+
+MockVideoFrameProvider* WebMediaPlayerMSTest::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_.compositor_.get();
+ EXPECT_NE(nullptr, compositor_);
+ compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled);
+
+ provider = render_factory_->GetVideoFrameProvider();
+ 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
+ EXPECT_TRUE(provider->Started());
+
+ mock_cb_.VerifyAndClearExpectations();
+ return provider;
+}
+
+void WebMediaPlayerMSTest::networkStateChanged() {
+ 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 WebMediaPlayerMSTest::readyStateChanged() {
+ blink::WebMediaPlayer::ReadyState state = player_.readyState();
+ mock_cb_.ReadyStateChanged(state);
+ if (state == blink::WebMediaPlayer::ReadyState::ReadyStateHaveEnoughData)
+ player_.play();
+}
+
+void WebMediaPlayerMSTest::setWebLayer(blink::WebLayer* layer) {
+ if (layer)
+ compositor_->SetVideoFrameProviderClient(this);
+ mock_cb_.SetWebLayer(!!layer);
+}
+
+void WebMediaPlayerMSTest::StopUsingProvider() {
+ if (rendering_)
+ StopRendering();
+}
+
+void WebMediaPlayerMSTest::StartRendering() {
+ if (!rendering_) {
+ rendering_ = true;
+ message_loop_.PostTask(
+ FROM_HERE,
+ base::Bind(&WebMediaPlayerMSTest::RenderFrame, base::Unretained(this)));
+ }
+ mock_cb_.StartRendering();
+}
+
+void WebMediaPlayerMSTest::StopRendering() {
+ rendering_ = false;
+ mock_cb_.StopRendering();
+}
+
+void WebMediaPlayerMSTest::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));
+}
+
+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, BROKEN_FRAME};
+ 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, TEST_BRAKE, 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, TEST_BRAKE, 166,
+ 200, 233, 266, 300, 333, 366, 400,
+ 433, TEST_BRAKE, 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, TEST_BRAKE, 166,
+ 200, 233, 266, 300, 333, 366, 400,
+ 433, TEST_BRAKE, 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