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