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.
5 #include "remoting/host/video_frame_recorder.h"
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"
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()))) {
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) {
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
;
51 class VideoFrameRecorderTest
: public testing::Test
{
53 VideoFrameRecorderTest();
55 void SetUp() override
;
56 void TearDown() override
;
58 // Creates a new VideoEncoder, wraps it using |recorder_|, and stores the
59 // newly wrapped encoder in |encoder_|.
60 void CreateAndWrapEncoder();
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();
67 // Calls CreateNextFrame() to create kTextFrameCount test frames, and stores
68 // them to |test_frames_|.
69 void CreateTestFrames();
71 // Passes the frames in |test_frames_| to |encoder_|, in order, to encode.
72 void EncodeTestFrames();
74 // Creates a frame and passes it to |encoder_| without adding it to
76 void EncodeDummyFrame();
78 // Configures |recorder_| to start recording, and pumps events to ensure that
79 // |encoder_| is ready to record frames.
80 void StartRecording();
82 // Reads frames from |recorder_| and compares them to the |test_frames_|.
83 void VerifyTestFrames();
86 typedef std::list
<webrtc::DesktopFrame
*> DesktopFrames
;
88 base::MessageLoop message_loop_
;
90 scoped_ptr
<VideoFrameRecorder
> recorder_
;
91 scoped_ptr
<VideoEncoder
> encoder_
;
93 DesktopFrames test_frames_
;
96 DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderTest
);
99 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {}
101 void VideoFrameRecorderTest::SetUp() {
102 const int64_t kMaxContentBytes
= 10 * 1024 * 1024;
103 recorder_
.reset(new VideoFrameRecorder());
104 recorder_
->SetMaxContentBytes(kMaxContentBytes
);
107 void VideoFrameRecorderTest::TearDown() {
108 ASSERT_TRUE(test_frames_
.empty());
110 // Allow events posted to the recorder_, if still valid, to be processed.
111 base::RunLoop().RunUntilIdle();
113 // Tear down the recorder, if necessary.
116 // Process any events resulting from recorder teardown.
117 base::RunLoop().RunUntilIdle();
120 void VideoFrameRecorderTest::CreateAndWrapEncoder() {
121 scoped_ptr
<VideoEncoder
> encoder(new VideoEncoderVerbatim());
122 encoder_
= recorder_
->WrapVideoEncoder(encoder
.Pass());
124 // Encode a dummy frame to bind the wrapper to the TaskRunner.
128 scoped_ptr
<webrtc::DesktopFrame
> VideoFrameRecorderTest::CreateNextFrame() {
129 scoped_ptr
<webrtc::DesktopFrame
> frame(
130 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kFrameWidth
,
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_
));
144 void VideoFrameRecorderTest::CreateTestFrames() {
145 for (size_t i
= 0; i
< kTestFrameCount
; ++i
) {
146 test_frames_
.push_back(CreateNextFrame().release());
150 void VideoFrameRecorderTest::EncodeTestFrames() {
151 for (DesktopFrames::iterator i
= test_frames_
.begin();
152 i
!= test_frames_
.end(); ++i
) {
153 ASSERT_TRUE(encoder_
->Encode(**i
));
155 // Process tasks to let the recorder pick up the frame.
156 base::RunLoop().RunUntilIdle();
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();
167 void VideoFrameRecorderTest::StartRecording() {
168 // Start the recorder and pump events to let things initialize.
169 recorder_
->SetEnableRecording(true);
170 base::RunLoop().RunUntilIdle();
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
);
179 scoped_ptr
<webrtc::DesktopFrame
> expected_frame(test_frames_
.front());
180 test_frames_
.pop_front();
182 EXPECT_EQ(*recorded_frame
, *expected_frame
);
185 EXPECT_FALSE(recorder_
->NextFrame());
188 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash.
189 TEST_F(VideoFrameRecorderTest
, CreateDestroy
) {
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
) {
196 recorder_
->SetEnableRecording(false);
199 // Test that tearing down the VideoFrameRecorder while the VideoEncoder
200 // wrapper exists doesn't crash.
201 TEST_F(VideoFrameRecorderTest
, DestroyVideoFrameRecorderFirst
) {
202 CreateAndWrapEncoder();
204 // Start the recorder, so that the wrapper will push frames to it.
207 // Tear down the recorder.
210 // Encode a dummy frame via the wrapper to ensure we don't crash.
214 // Test that creating & tearing down the wrapper while the
215 // VideoFrameRecorder still exists doesn't crash.
216 TEST_F(VideoFrameRecorderTest
, DestroyVideoEncoderWrapperFirst
) {
217 CreateAndWrapEncoder();
219 // Start the recorder, so that the wrapper will push frames to it.
222 // Encode a dummy frame via the wrapper to ensure we don't crash.
225 // Tear down the encoder wrapper.
228 // Test teardown will stop the recorder and process pending events.
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();
236 // Start the recorder, so that the wrapper will push frames to it.
239 // Create frames, store them and pass them to the encoder.
243 // Verify that the recorded frames match the ones passed to the encoder.
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();
252 // Configure a maximum content size sufficient for five and a half frames.
253 recorder_
->SetMaxContentBytes((kTestFrameBytes
* 11) / 2);
255 // Start the recorder, so that the wrapper will push frames to it.
258 // Create frames, store them and pass them to the encoder.
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();
268 // Verify that the recorded frames match the ones passed to the encoder.
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();
277 // Configure a maximum content size sufficient for kTestFrameCount frames.
278 recorder_
->SetMaxContentBytes(kTestFrameBytes
* kTestFrameCount
);
280 // Start the recorder, so that the wrapper will push frames to it.
283 // Encode a frame, to record it, and consume it from the recorder.
285 scoped_ptr
<webrtc::DesktopFrame
> frame
= recorder_
->NextFrame();
288 // Create frames, store them and pass them to the encoder.
292 // Verify that the recorded frames match the ones passed to the encoder.
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();
301 // Create frames, store them and pass them to the encoder.
305 // Clear the list of expected test frames, since none should be recorded.
306 STLDeleteElements(&test_frames_
);
308 // Verify that the recorded frames match the ones passed to the encoder.
312 } // namespace remoting