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 "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
13 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
18 // Define equality operator for DesktopFrame to allow use of EXPECT_EQ().
19 static bool operator==(const DesktopFrame
& a
,
20 const DesktopFrame
& b
) {
21 if ((a
.size().equals(b
.size())) &&
22 (a
.updated_region().Equals(b
.updated_region())) &&
23 (a
.dpi().equals(b
.dpi()))) {
24 for (int i
= 0; i
< a
.size().height(); ++i
) {
25 if (memcmp(a
.data() + a
.stride() * i
,
26 b
.data() + b
.stride() * i
,
27 a
.size().width() * DesktopFrame::kBytesPerPixel
) != 0) {
40 const int64_t kMaxContentBytes
= 10 * 1024 * 1024;
41 const int kWidth
= 640;
42 const int kHeight
= 480;
43 const int kTestFrameCount
= 6;
45 class VideoFrameRecorderTest
: public testing::Test
{
47 VideoFrameRecorderTest();
49 virtual void SetUp() OVERRIDE
;
50 virtual void TearDown() OVERRIDE
;
52 void CreateAndWrapEncoder();
53 scoped_ptr
<webrtc::DesktopFrame
> CreateNextFrame();
54 void CreateTestFrames();
55 void EncodeTestFrames();
56 void EncodeDummyFrame();
57 void StartRecording();
58 void VerifyTestFrames();
61 base::MessageLoop message_loop_
;
63 scoped_ptr
<VideoFrameRecorder
> recorder_
;
64 scoped_ptr
<VideoEncoder
> encoder_
;
66 std::list
<webrtc::DesktopFrame
*> test_frames_
;
70 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {}
72 void VideoFrameRecorderTest::SetUp() {
73 recorder_
.reset(new VideoFrameRecorder());
74 recorder_
->SetMaxContentBytes(kMaxContentBytes
);
77 void VideoFrameRecorderTest::TearDown() {
78 ASSERT_TRUE(test_frames_
.empty());
80 // Allow events posted to the recorder_, if still valid, to be processed.
81 base::RunLoop().RunUntilIdle();
83 // Tear down the recorder, if necessary.
86 // Process any events resulting from recorder teardown.
87 base::RunLoop().RunUntilIdle();
90 void VideoFrameRecorderTest::CreateAndWrapEncoder() {
91 scoped_ptr
<VideoEncoder
> encoder(new VideoEncoderVerbatim());
92 encoder_
= recorder_
->WrapVideoEncoder(encoder
.Pass());
94 // Encode a dummy frame to bind the wrapper to the TaskRunner.
98 scoped_ptr
<webrtc::DesktopFrame
> VideoFrameRecorderTest::CreateNextFrame() {
99 scoped_ptr
<webrtc::DesktopFrame
> frame(
100 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth
, kHeight
)));
102 // Fill content, DPI and updated-region based on |frame_count_| so that each
103 // generated frame is different.
104 memset(frame
->data(), frame_count_
, frame
->stride() * kHeight
);
105 frame
->set_dpi(webrtc::DesktopVector(frame_count_
, frame_count_
));
106 frame
->mutable_updated_region()->SetRect(
107 webrtc::DesktopRect::MakeWH(frame_count_
, frame_count_
));
113 void VideoFrameRecorderTest::CreateTestFrames() {
114 for (int i
=0; i
< kTestFrameCount
; ++i
) {
115 test_frames_
.push_back(CreateNextFrame().release());
119 void VideoFrameRecorderTest::EncodeTestFrames() {
120 std::list
<webrtc::DesktopFrame
*>::iterator i
;
121 for (i
= test_frames_
.begin(); i
!= test_frames_
.end(); ++i
) {
122 scoped_ptr
<VideoPacket
> packet
= encoder_
->Encode(*(*i
));
124 // Process tasks to let the recorder pick up the frame.
125 base::RunLoop().RunUntilIdle();
129 void VideoFrameRecorderTest::EncodeDummyFrame() {
130 webrtc::BasicDesktopFrame
dummy_frame(webrtc::DesktopSize(kWidth
, kHeight
));
131 scoped_ptr
<VideoPacket
> packet
= encoder_
->Encode(dummy_frame
);
132 base::RunLoop().RunUntilIdle();
135 void VideoFrameRecorderTest::StartRecording() {
136 // Start the recorder and pump events to let things initialize.
137 recorder_
->SetEnableRecording(true);
138 base::RunLoop().RunUntilIdle();
141 void VideoFrameRecorderTest::VerifyTestFrames() {
142 // Verify that the recorded frames match the ones passed to the encoder.
143 while (!test_frames_
.empty()) {
144 scoped_ptr
<webrtc::DesktopFrame
> recorded_frame(recorder_
->NextFrame());
145 ASSERT_TRUE(recorded_frame
);
147 scoped_ptr
<webrtc::DesktopFrame
> expected_frame(test_frames_
.front());
148 test_frames_
.pop_front();
150 EXPECT_EQ(*recorded_frame
, *expected_frame
);
153 EXPECT_FALSE(recorder_
->NextFrame());
156 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash.
157 TEST_F(VideoFrameRecorderTest
, CreateDestroy
) {
160 // Basic test that creating, starting, stopping and destroying a
161 // VideoFrameRecorder don't end the world.
162 TEST_F(VideoFrameRecorderTest
, StartStop
) {
164 recorder_
->SetEnableRecording(false);
167 // Test that tearing down the VideoFrameRecorder while the VideoEncoder
168 // wrapper exists doesn't crash.
169 TEST_F(VideoFrameRecorderTest
, DestroyVideoFrameRecorderFirst
) {
170 CreateAndWrapEncoder();
172 // Start the recorder, so that the wrapper will push frames to it.
175 // Tear down the recorder.
178 // Encode a dummy frame via the wrapper to ensure we don't crash.
182 // Test that creating & tearing down the wrapper while the
183 // VideoFrameRecorder still exists doesn't crash.
184 TEST_F(VideoFrameRecorderTest
, DestroyVideoEncoderWrapperFirst
) {
185 CreateAndWrapEncoder();
187 // Start the recorder, so that the wrapper will push frames to it.
190 // Encode a dummy frame via the wrapper to ensure we don't crash.
193 // Tear down the encoder wrapper.
196 // Test teardown will stop the recorder and process pending events.
199 // Test that when asked to encode a short sequence of frames, those frames are
200 // all recorded, in sequence.
201 TEST_F(VideoFrameRecorderTest
, RecordFrames
) {
202 CreateAndWrapEncoder();
204 // Start the recorder, so that the wrapper will push frames to it.
207 // Create frames, store them and pass them to the encoder.
211 // Verify that the recorded frames match the ones passed to the encoder.
215 // Test that when asked to record more frames than the maximum content bytes
216 // limit allows, the first encoded frames are dropped.
217 TEST_F(VideoFrameRecorderTest
, MaxContentBytesEnforced
) {
218 CreateAndWrapEncoder();
220 // Configure a maximum content size sufficient for five and a half frames.
221 int64 frame_bytes
= kWidth
* kHeight
* webrtc::DesktopFrame::kBytesPerPixel
;
222 recorder_
->SetMaxContentBytes((frame_bytes
* 11) / 2);
224 // Start the recorder, so that the wrapper will push frames to it.
227 // Create frames, store them and pass them to the encoder.
231 // Only five of the supplied frames should have been recorded.
232 while (test_frames_
.size() > 5) {
233 scoped_ptr
<webrtc::DesktopFrame
> frame(test_frames_
.front());
234 test_frames_
.pop_front();
237 // Verify that the recorded frames match the ones passed to the encoder.
241 // Test that when asked to record more frames than the maximum content bytes
242 // limit allows, the first encoded frames are dropped.
243 TEST_F(VideoFrameRecorderTest
, ContentBytesUpdatedByNextFrame
) {
244 CreateAndWrapEncoder();
246 // Configure a maximum content size sufficient for kTestFrameCount frames.
247 int64 frame_bytes
= kWidth
* kHeight
* webrtc::DesktopFrame::kBytesPerPixel
;
248 recorder_
->SetMaxContentBytes(frame_bytes
* kTestFrameCount
);
250 // Start the recorder, so that the wrapper will push frames to it.
253 // Encode a frame, to record it, and consume it from the recorder.
255 scoped_ptr
<webrtc::DesktopFrame
> frame
= recorder_
->NextFrame();
258 // Create frames, store them and pass them to the encoder.
262 // Verify that the recorded frames match the ones passed to the encoder.
266 // Test that when asked to encode a short sequence of frames, none are recorded
267 // if recording was not enabled.
268 TEST_F(VideoFrameRecorderTest
, EncodeButDontRecord
) {
269 CreateAndWrapEncoder();
271 // Create frames, store them and pass them to the encoder.
275 // Clear the list of expected test frames, since none should be recorded.
276 STLDeleteElements(&test_frames_
);
278 // Verify that the recorded frames match the ones passed to the encoder.
282 } // namespace remoting