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