| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "remoting/host/video_frame_recorder.h" | |
| 6 | |
| 7 #include "base/message_loop/message_loop.h" | |
| 8 #include "base/run_loop.h" | |
| 9 #include "remoting/codec/video_encoder_verbatim.h" | |
| 10 #include "testing/gtest/include/gtest/gtest.h" | |
| 11 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
| 12 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" | |
| 13 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | |
| 14 | |
| 15 namespace webrtc { | |
| 16 | |
| 17 // Define equality operator for DesktopFrame to allow use of EXPECT_EQ(). | |
| 18 static bool operator==(const DesktopFrame& a, | |
| 19 const DesktopFrame& b) { | |
| 20 if ((a.size().equals(b.size())) && | |
| 21 (a.updated_region().Equals(b.updated_region())) && | |
| 22 (a.dpi().equals(b.dpi()))) { | |
| 23 for (int i = 0; i < a.size().height(); ++i) { | |
| 24 if (memcmp(a.data() + a.stride() * i, | |
| 25 b.data() + b.stride() * i, | |
| 26 a.size().width() * DesktopFrame::kBytesPerPixel) != 0) { | |
| 27 return false; | |
| 28 } | |
| 29 } | |
| 30 return true; | |
| 31 } | |
| 32 return false; | |
| 33 } | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 namespace remoting { | |
| 38 | |
| 39 const int64_t kMaxContentBytes = 10 * 1024 * 1024; | |
| 40 const int kWidth = 640; | |
| 41 const int kHeight = 480; | |
| 42 const int kTestFrameCount = 6; | |
| 43 | |
| 44 class VideoFrameRecorderTest : public testing::Test { | |
| 45 public: | |
| 46 VideoFrameRecorderTest(); | |
| 47 | |
| 48 virtual void SetUp() OVERRIDE; | |
| 49 virtual void TearDown() OVERRIDE; | |
| 50 | |
| 51 void CreateAndWrapEncoder(); | |
| 52 scoped_ptr<webrtc::DesktopFrame> CreateNextFrame(); | |
| 53 void CreateTestFrames(); | |
| 54 void EncodeTestFrames(); | |
| 55 void EncodeDummyFrame(); | |
| 56 void StartRecording(); | |
| 57 void VerifyTestFrames(); | |
| 58 | |
| 59 protected: | |
| 60 base::MessageLoop message_loop_; | |
| 61 | |
| 62 scoped_ptr<VideoFrameRecorder> recorder_; | |
| 63 scoped_ptr<VideoEncoder> encoder_; | |
| 64 | |
| 65 std::list<webrtc::DesktopFrame*> test_frames_; | |
| 66 int frame_count_; | |
| 67 }; | |
| 68 | |
| 69 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {} | |
| 70 | |
| 71 void VideoFrameRecorderTest::SetUp() { | |
| 72 recorder_.reset(new VideoFrameRecorder()); | |
| 73 recorder_->SetMaxContentBytes(kMaxContentBytes); | |
| 74 } | |
| 75 | |
| 76 void VideoFrameRecorderTest::TearDown() { | |
| 77 // Allow events posted to the recorder_, if still valid, to be processed. | |
| 78 base::RunLoop().RunUntilIdle(); | |
| 79 | |
| 80 // Tear down the recorder, if necessary. | |
| 81 recorder_.reset(); | |
| 82 | |
| 83 // Process any events resulting from recorder teardown. | |
| 84 base::RunLoop().RunUntilIdle(); | |
| 85 } | |
| 86 | |
| 87 void VideoFrameRecorderTest::CreateAndWrapEncoder() { | |
| 88 scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim()); | |
| 89 encoder_ = recorder_->WrapVideoEncoder(encoder.Pass()); | |
| 90 | |
| 91 // Encode a dummy frame to bind the wrapper to the TaskRunner. | |
| 92 EncodeDummyFrame(); | |
| 93 } | |
| 94 | |
| 95 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() { | |
| 96 scoped_ptr<webrtc::DesktopFrame> frame( | |
| 97 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); | |
| 98 | |
| 99 // Fill content, DPI and updated-region based on |frame_count_| so that each | |
| 100 // generated frame is different. | |
| 101 memset(frame->data(), frame_count_, frame->stride() * kHeight); | |
| 102 frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_)); | |
| 103 frame->mutable_updated_region()->SetRect( | |
| 104 webrtc::DesktopRect::MakeWH(frame_count_, frame_count_)); | |
| 105 ++frame_count_; | |
| 106 | |
| 107 return frame.Pass(); | |
| 108 } | |
| 109 | |
| 110 void VideoFrameRecorderTest::CreateTestFrames() { | |
| 111 for (int i=0; i < kTestFrameCount; ++i) { | |
| 112 test_frames_.push_back(CreateNextFrame().release()); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 void VideoFrameRecorderTest::EncodeTestFrames() { | |
| 117 std::list<webrtc::DesktopFrame*>::iterator i; | |
| 118 for (i = test_frames_.begin(); i != test_frames_.end(); ++i) { | |
| 119 scoped_ptr<VideoPacket> packet = encoder_->Encode(*(*i)); | |
| 120 | |
| 121 // Process tasks to let the recorder pick up the frame. | |
| 122 base::RunLoop().RunUntilIdle(); | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 void VideoFrameRecorderTest::EncodeDummyFrame() { | |
| 127 webrtc::BasicDesktopFrame dummy_frame(webrtc::DesktopSize(kWidth, kHeight)); | |
| 128 scoped_ptr<VideoPacket> packet = encoder_->Encode(dummy_frame); | |
| 129 base::RunLoop().RunUntilIdle(); | |
| 130 } | |
| 131 | |
| 132 void VideoFrameRecorderTest::StartRecording() { | |
| 133 // Start the recorder and pump events to let things initialize. | |
| 134 recorder_->SetEnableRecording(true); | |
| 135 base::RunLoop().RunUntilIdle(); | |
| 136 } | |
| 137 | |
| 138 void VideoFrameRecorderTest::VerifyTestFrames() { | |
| 139 // Verify that the recorded frames match the ones passed to the encoder. | |
| 140 while (!test_frames_.empty()) { | |
| 141 scoped_ptr<webrtc::DesktopFrame> recorded_frame(recorder_->NextFrame()); | |
| 142 ASSERT_TRUE(recorded_frame); | |
| 143 | |
| 144 scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front()); | |
| 145 test_frames_.pop_front(); | |
| 146 | |
| 147 EXPECT_EQ(*recorded_frame, *expected_frame); | |
| 148 } | |
| 149 | |
| 150 EXPECT_FALSE(recorder_->NextFrame()); | |
| 151 } | |
| 152 | |
| 153 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash. | |
| 154 TEST_F(VideoFrameRecorderTest, CreateDestroy) { | |
| 155 } | |
| 156 | |
| 157 // Basic test that creating, starting, stopping and destroying a | |
| 158 // VideoFrameRecorder don't end the world. | |
| 159 TEST_F(VideoFrameRecorderTest, StartStop) { | |
| 160 StartRecording(); | |
| 161 recorder_->SetEnableRecording(false); | |
| 162 } | |
| 163 | |
| 164 // Test that tearing down the VideoFrameRecorder while the VideoEncoder | |
| 165 // wrapper exists doesn't crash. | |
| 166 TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) { | |
| 167 CreateAndWrapEncoder(); | |
| 168 | |
| 169 // Start the recorder, so that the wrapper will push frames to it. | |
| 170 StartRecording(); | |
| 171 | |
| 172 // Tear down the recorder. | |
| 173 recorder_.reset(); | |
| 174 | |
| 175 // Encode a dummy frame via the wrapper to ensure we don't crash. | |
| 176 EncodeDummyFrame(); | |
| 177 } | |
| 178 | |
| 179 // Test that creating & tearing down the wrapper while the | |
| 180 // VideoFrameRecorder still exists doesn't crash. | |
| 181 TEST_F(VideoFrameRecorderTest, DestroyVideoEncoderWrapperFirst) { | |
| 182 CreateAndWrapEncoder(); | |
| 183 | |
| 184 // Start the recorder, so that the wrapper will push frames to it. | |
| 185 StartRecording(); | |
| 186 | |
| 187 // Encode a dummy frame via the wrapper to ensure we don't crash. | |
| 188 EncodeDummyFrame(); | |
| 189 | |
| 190 // Tear down the encoder wrapper. | |
| 191 encoder_.reset(); | |
| 192 | |
| 193 // Test teardown will stop the recorder and process pending events. | |
| 194 } | |
| 195 | |
| 196 // Test that when asked to encode a short sequence of frames, those frames are | |
| 197 // all recorded, in sequence. | |
| 198 TEST_F(VideoFrameRecorderTest, RecordFrames) { | |
| 199 CreateAndWrapEncoder(); | |
| 200 | |
| 201 // Start the recorder, so that the wrapper will push frames to it. | |
| 202 StartRecording(); | |
| 203 | |
| 204 // Create frames, store them and pass them to the encoder. | |
| 205 CreateTestFrames(); | |
| 206 EncodeTestFrames(); | |
| 207 | |
| 208 // Verify that the recorded frames match the ones passed to the encoder. | |
| 209 VerifyTestFrames(); | |
| 210 } | |
| 211 | |
| 212 // Test that when asked to record more frames than the maximum content bytes | |
| 213 // limit allows, the first encoded frames are dropped. | |
| 214 TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) { | |
| 215 CreateAndWrapEncoder(); | |
| 216 | |
| 217 // Configure a maximum content size sufficient for five and a half frames. | |
| 218 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | |
| 219 recorder_->SetMaxContentBytes((frame_bytes * 11) / 2); | |
| 220 | |
| 221 // Start the recorder, so that the wrapper will push frames to it. | |
| 222 StartRecording(); | |
| 223 | |
| 224 // Create frames, store them and pass them to the encoder. | |
| 225 CreateTestFrames(); | |
| 226 EncodeTestFrames(); | |
| 227 | |
| 228 // Only five of the supplied frames should have been recorded. | |
| 229 while (test_frames_.size() > 5) { | |
| 230 scoped_ptr<webrtc::DesktopFrame> frame(test_frames_.front()); | |
| 231 test_frames_.pop_front(); | |
| 232 } | |
| 233 | |
| 234 // Verify that the recorded frames match the ones passed to the encoder. | |
| 235 VerifyTestFrames(); | |
| 236 } | |
| 237 | |
| 238 // Test that when asked to record more frames than the maximum content bytes | |
| 239 // limit allows, the first encoded frames are dropped. | |
| 240 TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) { | |
| 241 CreateAndWrapEncoder(); | |
| 242 | |
| 243 // Configure a maximum content size sufficient for kTestFrameCount frames. | |
| 244 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | |
| 245 recorder_->SetMaxContentBytes(frame_bytes * kTestFrameCount); | |
| 246 | |
| 247 // Start the recorder, so that the wrapper will push frames to it. | |
| 248 StartRecording(); | |
| 249 | |
| 250 // Encode a frame, to record it, and consume it from the recorder. | |
| 251 EncodeDummyFrame(); | |
| 252 scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame(); | |
| 253 EXPECT_TRUE(frame); | |
| 254 | |
| 255 // Create frames, store them and pass them to the encoder. | |
| 256 CreateTestFrames(); | |
| 257 EncodeTestFrames(); | |
| 258 | |
| 259 // Verify that the recorded frames match the ones passed to the encoder. | |
| 260 VerifyTestFrames(); | |
| 261 } | |
| 262 | |
| 263 // Test that when asked to encode a short sequence of frames, none are recorded | |
| 264 // if recording was not enabled. | |
| 265 TEST_F(VideoFrameRecorderTest, EncodeButDontRecord) { | |
| 266 CreateAndWrapEncoder(); | |
| 267 | |
| 268 // Create frames, store them and pass them to the encoder. | |
| 269 CreateTestFrames(); | |
| 270 EncodeTestFrames(); | |
| 271 | |
| 272 // Clear the list of expected test frames, since none should be recorded. | |
| 273 test_frames_.clear(); | |
| 274 | |
| 275 // Verify that the recorded frames match the ones passed to the encoder. | |
| 276 VerifyTestFrames(); | |
| 277 } | |
| 278 | |
| 279 } // namespace remoting | |
| OLD | NEW |