| Index: remoting/host/video_frame_recorder_unittest.cc
|
| diff --git a/remoting/host/video_frame_recorder_unittest.cc b/remoting/host/video_frame_recorder_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f0f5b9d440295ebe534cb6cb9a7145be5f8e6960
|
| --- /dev/null
|
| +++ b/remoting/host/video_frame_recorder_unittest.cc
|
| @@ -0,0 +1,282 @@
|
| +// Copyright 2014 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 "remoting/host/video_frame_recorder.h"
|
| +
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/stl_util.h"
|
| +#include "remoting/codec/video_encoder_verbatim.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
|
| +#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
|
| +#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
|
| +
|
| +namespace webrtc {
|
| +
|
| +// Define equality operator for DesktopFrame to allow use of EXPECT_EQ().
|
| +static bool operator==(const DesktopFrame& a,
|
| + const DesktopFrame& b) {
|
| + if ((a.size().equals(b.size())) &&
|
| + (a.updated_region().Equals(b.updated_region())) &&
|
| + (a.dpi().equals(b.dpi()))) {
|
| + for (int i = 0; i < a.size().height(); ++i) {
|
| + if (memcmp(a.data() + a.stride() * i,
|
| + b.data() + b.stride() * i,
|
| + a.size().width() * DesktopFrame::kBytesPerPixel) != 0) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace remoting {
|
| +
|
| +const int64_t kMaxContentBytes = 10 * 1024 * 1024;
|
| +const int kWidth = 640;
|
| +const int kHeight = 480;
|
| +const int kTestFrameCount = 6;
|
| +
|
| +class VideoFrameRecorderTest : public testing::Test {
|
| + public:
|
| + VideoFrameRecorderTest();
|
| +
|
| + virtual void SetUp() OVERRIDE;
|
| + virtual void TearDown() OVERRIDE;
|
| +
|
| + void CreateAndWrapEncoder();
|
| + scoped_ptr<webrtc::DesktopFrame> CreateNextFrame();
|
| + void CreateTestFrames();
|
| + void EncodeTestFrames();
|
| + void EncodeDummyFrame();
|
| + void StartRecording();
|
| + void VerifyTestFrames();
|
| +
|
| + protected:
|
| + base::MessageLoop message_loop_;
|
| +
|
| + scoped_ptr<VideoFrameRecorder> recorder_;
|
| + scoped_ptr<VideoEncoder> encoder_;
|
| +
|
| + std::list<webrtc::DesktopFrame*> test_frames_;
|
| + int frame_count_;
|
| +};
|
| +
|
| +VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {}
|
| +
|
| +void VideoFrameRecorderTest::SetUp() {
|
| + recorder_.reset(new VideoFrameRecorder());
|
| + recorder_->SetMaxContentBytes(kMaxContentBytes);
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::TearDown() {
|
| + ASSERT_TRUE(test_frames_.empty());
|
| +
|
| + // Allow events posted to the recorder_, if still valid, to be processed.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Tear down the recorder, if necessary.
|
| + recorder_.reset();
|
| +
|
| + // Process any events resulting from recorder teardown.
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::CreateAndWrapEncoder() {
|
| + scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim());
|
| + encoder_ = recorder_->WrapVideoEncoder(encoder.Pass());
|
| +
|
| + // Encode a dummy frame to bind the wrapper to the TaskRunner.
|
| + EncodeDummyFrame();
|
| +}
|
| +
|
| +scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() {
|
| + scoped_ptr<webrtc::DesktopFrame> frame(
|
| + new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)));
|
| +
|
| + // Fill content, DPI and updated-region based on |frame_count_| so that each
|
| + // generated frame is different.
|
| + memset(frame->data(), frame_count_, frame->stride() * kHeight);
|
| + frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_));
|
| + frame->mutable_updated_region()->SetRect(
|
| + webrtc::DesktopRect::MakeWH(frame_count_, frame_count_));
|
| + ++frame_count_;
|
| +
|
| + return frame.Pass();
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::CreateTestFrames() {
|
| + for (int i=0; i < kTestFrameCount; ++i) {
|
| + test_frames_.push_back(CreateNextFrame().release());
|
| + }
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::EncodeTestFrames() {
|
| + std::list<webrtc::DesktopFrame*>::iterator i;
|
| + for (i = test_frames_.begin(); i != test_frames_.end(); ++i) {
|
| + scoped_ptr<VideoPacket> packet = encoder_->Encode(*(*i));
|
| +
|
| + // Process tasks to let the recorder pick up the frame.
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::EncodeDummyFrame() {
|
| + webrtc::BasicDesktopFrame dummy_frame(webrtc::DesktopSize(kWidth, kHeight));
|
| + scoped_ptr<VideoPacket> packet = encoder_->Encode(dummy_frame);
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::StartRecording() {
|
| + // Start the recorder and pump events to let things initialize.
|
| + recorder_->SetEnableRecording(true);
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +void VideoFrameRecorderTest::VerifyTestFrames() {
|
| + // Verify that the recorded frames match the ones passed to the encoder.
|
| + while (!test_frames_.empty()) {
|
| + scoped_ptr<webrtc::DesktopFrame> recorded_frame(recorder_->NextFrame());
|
| + ASSERT_TRUE(recorded_frame);
|
| +
|
| + scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front());
|
| + test_frames_.pop_front();
|
| +
|
| + EXPECT_EQ(*recorded_frame, *expected_frame);
|
| + }
|
| +
|
| + EXPECT_FALSE(recorder_->NextFrame());
|
| +}
|
| +
|
| +// Basic test that creating & tearing down VideoFrameRecorder doesn't crash.
|
| +TEST_F(VideoFrameRecorderTest, CreateDestroy) {
|
| +}
|
| +
|
| +// Basic test that creating, starting, stopping and destroying a
|
| +// VideoFrameRecorder don't end the world.
|
| +TEST_F(VideoFrameRecorderTest, StartStop) {
|
| + StartRecording();
|
| + recorder_->SetEnableRecording(false);
|
| +}
|
| +
|
| +// Test that tearing down the VideoFrameRecorder while the VideoEncoder
|
| +// wrapper exists doesn't crash.
|
| +TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Start the recorder, so that the wrapper will push frames to it.
|
| + StartRecording();
|
| +
|
| + // Tear down the recorder.
|
| + recorder_.reset();
|
| +
|
| + // Encode a dummy frame via the wrapper to ensure we don't crash.
|
| + EncodeDummyFrame();
|
| +}
|
| +
|
| +// Test that creating & tearing down the wrapper while the
|
| +// VideoFrameRecorder still exists doesn't crash.
|
| +TEST_F(VideoFrameRecorderTest, DestroyVideoEncoderWrapperFirst) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Start the recorder, so that the wrapper will push frames to it.
|
| + StartRecording();
|
| +
|
| + // Encode a dummy frame via the wrapper to ensure we don't crash.
|
| + EncodeDummyFrame();
|
| +
|
| + // Tear down the encoder wrapper.
|
| + encoder_.reset();
|
| +
|
| + // Test teardown will stop the recorder and process pending events.
|
| +}
|
| +
|
| +// Test that when asked to encode a short sequence of frames, those frames are
|
| +// all recorded, in sequence.
|
| +TEST_F(VideoFrameRecorderTest, RecordFrames) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Start the recorder, so that the wrapper will push frames to it.
|
| + StartRecording();
|
| +
|
| + // Create frames, store them and pass them to the encoder.
|
| + CreateTestFrames();
|
| + EncodeTestFrames();
|
| +
|
| + // Verify that the recorded frames match the ones passed to the encoder.
|
| + VerifyTestFrames();
|
| +}
|
| +
|
| +// Test that when asked to record more frames than the maximum content bytes
|
| +// limit allows, the first encoded frames are dropped.
|
| +TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Configure a maximum content size sufficient for five and a half frames.
|
| + int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel;
|
| + recorder_->SetMaxContentBytes((frame_bytes * 11) / 2);
|
| +
|
| + // Start the recorder, so that the wrapper will push frames to it.
|
| + StartRecording();
|
| +
|
| + // Create frames, store them and pass them to the encoder.
|
| + CreateTestFrames();
|
| + EncodeTestFrames();
|
| +
|
| + // Only five of the supplied frames should have been recorded.
|
| + while (test_frames_.size() > 5) {
|
| + scoped_ptr<webrtc::DesktopFrame> frame(test_frames_.front());
|
| + test_frames_.pop_front();
|
| + }
|
| +
|
| + // Verify that the recorded frames match the ones passed to the encoder.
|
| + VerifyTestFrames();
|
| +}
|
| +
|
| +// Test that when asked to record more frames than the maximum content bytes
|
| +// limit allows, the first encoded frames are dropped.
|
| +TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Configure a maximum content size sufficient for kTestFrameCount frames.
|
| + int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel;
|
| + recorder_->SetMaxContentBytes(frame_bytes * kTestFrameCount);
|
| +
|
| + // Start the recorder, so that the wrapper will push frames to it.
|
| + StartRecording();
|
| +
|
| + // Encode a frame, to record it, and consume it from the recorder.
|
| + EncodeDummyFrame();
|
| + scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame();
|
| + EXPECT_TRUE(frame);
|
| +
|
| + // Create frames, store them and pass them to the encoder.
|
| + CreateTestFrames();
|
| + EncodeTestFrames();
|
| +
|
| + // Verify that the recorded frames match the ones passed to the encoder.
|
| + VerifyTestFrames();
|
| +}
|
| +
|
| +// Test that when asked to encode a short sequence of frames, none are recorded
|
| +// if recording was not enabled.
|
| +TEST_F(VideoFrameRecorderTest, EncodeButDontRecord) {
|
| + CreateAndWrapEncoder();
|
| +
|
| + // Create frames, store them and pass them to the encoder.
|
| + CreateTestFrames();
|
| + EncodeTestFrames();
|
| +
|
| + // Clear the list of expected test frames, since none should be recorded.
|
| + STLDeleteElements(&test_frames_);
|
| +
|
| + // Verify that the recorded frames match the ones passed to the encoder.
|
| + VerifyTestFrames();
|
| +}
|
| +
|
| +} // namespace remoting
|
|
|