| // Copyright 2018 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 <memory> |
| |
| #include "base/bind.h" |
| #include "content/browser/devtools/devtools_video_consumer.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "net/test/embedded_test_server/controllable_http_response.h" |
| |
| namespace { |
| |
| // Helper to verify that |frame| dimensions are in the expected ranges. |
| bool VerifyFrameSize(scoped_refptr<media::VideoFrame> frame, |
| gfx::Size min_frame_size, |
| gfx::Size max_frame_size) { |
| // Returns true if |min_frame_size| <= |frame| <= |max_frame_size|. |
| return min_frame_size.width() <= frame->visible_rect().width() && |
| min_frame_size.height() <= frame->visible_rect().height() && |
| frame->visible_rect().width() <= max_frame_size.width() && |
| frame->visible_rect().height() <= max_frame_size.height(); |
| } |
| |
| // The default video pixel format. |
| // TODO(sundarrajs): Add |FrameSinkVideoCapturerImpl::kDefaultPixelFormat| to |
| // frame_sink_video_capture.mojom and use that instead of |
| // |kVideoCapturerDefaultPixelFormat|. |
| constexpr media::VideoPixelFormat kVideoCapturerDefaultPixelFormat = |
| media::PIXEL_FORMAT_I420; |
| |
| } // namespace |
| |
| namespace content { |
| |
| class DevToolsVideoConsumerTest : public ContentBrowserTest { |
| public: |
| DevToolsVideoConsumerTest() {} |
| |
| void SetUpOnMainThread() override { |
| consumer_ = std::make_unique<DevToolsVideoConsumer>(base::BindRepeating( |
| &DevToolsVideoConsumerTest::OnFrameFromVideoConsumer, |
| base::Unretained(this))); |
| consumer_->SetFrameSinkId( |
| static_cast<content::WebContentsImpl*>(shell()->web_contents()) |
| ->GetRenderViewHost() |
| ->GetWidget() |
| ->GetFrameSinkId()); |
| } |
| |
| scoped_refptr<media::VideoFrame> GetFrame(int i) { return frames_[i]; } |
| |
| size_t NumberOfFramesReceived() { return frames_.size(); } |
| |
| void OnFrameFromVideoConsumer(scoped_refptr<media::VideoFrame> frame) { |
| run_loop_->Quit(); |
| frames_.push_back(std::move(frame)); |
| } |
| |
| void WaitUntilFrameReceived() { |
| run_loop_.reset(new base::RunLoop); |
| run_loop_->Run(); |
| } |
| |
| static gfx::Size GetVideoConsumerDefaultMinFrameSize() { |
| return DevToolsVideoConsumer::kDefaultMinFrameSize; |
| } |
| |
| static gfx::Size GetVideoConsumerDefaultMaxFrameSize() { |
| return DevToolsVideoConsumer::kDefaultMaxFrameSize; |
| } |
| |
| protected: |
| std::unique_ptr<DevToolsVideoConsumer> consumer_; |
| |
| private: |
| std::vector<scoped_refptr<media::VideoFrame>> frames_; |
| std::unique_ptr<base::RunLoop> run_loop_; |
| }; |
| |
| // Tests that setting new frame dimensions via SetMinAndMaxFrameSizes |
| // produces frames of the new dimensions. |
| IN_PROC_BROWSER_TEST_F(DevToolsVideoConsumerTest, |
| SetMinAndMaxFramesChangesDimensions) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Complete navigation to a page and then start capture. Since navigation is |
| // complete before capturing, we only expect the refresh frame from the |
| // StartCapture call. Wait for this refresh frame and verify its info. |
| NavigateToURLBlockUntilNavigationsComplete( |
| shell(), embedded_test_server()->GetURL("/devtools/navigation.html"), 1); |
| consumer_->StartCapture(); |
| WaitUntilFrameReceived(); |
| size_t cur_frame_index = 0; |
| size_t num_frames_received = 1; |
| EXPECT_EQ(num_frames_received, NumberOfFramesReceived()); |
| scoped_refptr<media::VideoFrame> frame = GetFrame(cur_frame_index); |
| EXPECT_EQ(frame->format(), kVideoCapturerDefaultPixelFormat); |
| EXPECT_TRUE(VerifyFrameSize(frame, GetVideoConsumerDefaultMinFrameSize(), |
| GetVideoConsumerDefaultMaxFrameSize())); |
| |
| // Setting |kNewMinFrameSize| > |kDefaultMaxFrameSize| to disambiguate |
| // frames with older vs. newer dimensions. |
| const gfx::Size kNewMinFrameSize = |
| gfx::Size(GetVideoConsumerDefaultMaxFrameSize().width() + 1, |
| GetVideoConsumerDefaultMaxFrameSize().height() + 1); |
| // |kNewMaxFrameSize| only needs to be >= |kNewMinFrameSize|. |
| const gfx::Size kNewMaxFrameSize = gfx::Size(kNewMinFrameSize.width() + 500, |
| kNewMinFrameSize.height() + 500); |
| // Set the min and max frame sizes. This will call |
| // FrameSinkVideoCapturer::SetResolutionConstraints which triggers sending a |
| // refresh frame. Wait for this refresh frame and verify it's info. |
| consumer_->SetMinAndMaxFrameSize(kNewMinFrameSize, kNewMaxFrameSize); |
| WaitUntilFrameReceived(); |
| EXPECT_EQ(++num_frames_received, NumberOfFramesReceived()); |
| frame = GetFrame(++cur_frame_index); |
| EXPECT_EQ(frame->format(), kVideoCapturerDefaultPixelFormat); |
| EXPECT_TRUE(VerifyFrameSize(frame, kNewMinFrameSize, kNewMaxFrameSize)); |
| |
| // Stop capturing. |
| consumer_->StopCapture(); |
| } |
| |
| } // namespace content |