f0f5b9d440295ebe534cb6cb9a7145be5f8e6960
[platform/framework/web/crosswalk.git] / src / remoting / host / video_frame_recorder_unittest.cc
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 "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"
15
16 namespace webrtc {
17
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) {
28         return false;
29       }
30     }
31     return true;
32   }
33   return false;
34 }
35
36 } // namespace
37
38 namespace remoting {
39
40 const int64_t kMaxContentBytes = 10 * 1024 * 1024;
41 const int kWidth = 640;
42 const int kHeight = 480;
43 const int kTestFrameCount = 6;
44
45 class VideoFrameRecorderTest : public testing::Test {
46  public:
47   VideoFrameRecorderTest();
48
49   virtual void SetUp() OVERRIDE;
50   virtual void TearDown() OVERRIDE;
51
52   void CreateAndWrapEncoder();
53   scoped_ptr<webrtc::DesktopFrame> CreateNextFrame();
54   void CreateTestFrames();
55   void EncodeTestFrames();
56   void EncodeDummyFrame();
57   void StartRecording();
58   void VerifyTestFrames();
59
60  protected:
61   base::MessageLoop message_loop_;
62
63   scoped_ptr<VideoFrameRecorder> recorder_;
64   scoped_ptr<VideoEncoder> encoder_;
65
66   std::list<webrtc::DesktopFrame*> test_frames_;
67   int frame_count_;
68 };
69
70 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {}
71
72 void VideoFrameRecorderTest::SetUp() {
73   recorder_.reset(new VideoFrameRecorder());
74   recorder_->SetMaxContentBytes(kMaxContentBytes);
75 }
76
77 void VideoFrameRecorderTest::TearDown() {
78   ASSERT_TRUE(test_frames_.empty());
79
80   // Allow events posted to the recorder_, if still valid, to be processed.
81   base::RunLoop().RunUntilIdle();
82
83   // Tear down the recorder, if necessary.
84   recorder_.reset();
85
86   // Process any events resulting from recorder teardown.
87   base::RunLoop().RunUntilIdle();
88 }
89
90 void VideoFrameRecorderTest::CreateAndWrapEncoder() {
91   scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim());
92   encoder_ = recorder_->WrapVideoEncoder(encoder.Pass());
93
94   // Encode a dummy frame to bind the wrapper to the TaskRunner.
95   EncodeDummyFrame();
96 }
97
98 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() {
99   scoped_ptr<webrtc::DesktopFrame> frame(
100       new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)));
101
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_));
108   ++frame_count_;
109
110   return frame.Pass();
111 }
112
113 void VideoFrameRecorderTest::CreateTestFrames() {
114   for (int i=0; i < kTestFrameCount; ++i) {
115     test_frames_.push_back(CreateNextFrame().release());
116   }
117 }
118
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));
123
124     // Process tasks to let the recorder pick up the frame.
125     base::RunLoop().RunUntilIdle();
126   }
127 }
128
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();
133 }
134
135 void VideoFrameRecorderTest::StartRecording() {
136   // Start the recorder and pump events to let things initialize.
137   recorder_->SetEnableRecording(true);
138   base::RunLoop().RunUntilIdle();
139 }
140
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);
146
147     scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front());
148     test_frames_.pop_front();
149
150     EXPECT_EQ(*recorded_frame, *expected_frame);
151   }
152
153   EXPECT_FALSE(recorder_->NextFrame());
154 }
155
156 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash.
157 TEST_F(VideoFrameRecorderTest, CreateDestroy) {
158 }
159
160 // Basic test that creating, starting, stopping and destroying a
161 // VideoFrameRecorder don't end the world.
162 TEST_F(VideoFrameRecorderTest, StartStop) {
163   StartRecording();
164   recorder_->SetEnableRecording(false);
165 }
166
167 // Test that tearing down the VideoFrameRecorder while the VideoEncoder
168 // wrapper exists doesn't crash.
169 TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) {
170   CreateAndWrapEncoder();
171
172   // Start the recorder, so that the wrapper will push frames to it.
173   StartRecording();
174
175   // Tear down the recorder.
176   recorder_.reset();
177
178   // Encode a dummy frame via the wrapper to ensure we don't crash.
179   EncodeDummyFrame();
180 }
181
182 // Test that creating & tearing down the wrapper while the
183 // VideoFrameRecorder still exists doesn't crash.
184 TEST_F(VideoFrameRecorderTest, DestroyVideoEncoderWrapperFirst) {
185   CreateAndWrapEncoder();
186
187   // Start the recorder, so that the wrapper will push frames to it.
188   StartRecording();
189
190   // Encode a dummy frame via the wrapper to ensure we don't crash.
191   EncodeDummyFrame();
192
193   // Tear down the encoder wrapper.
194   encoder_.reset();
195
196   // Test teardown will stop the recorder and process pending events.
197 }
198
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();
203
204   // Start the recorder, so that the wrapper will push frames to it.
205   StartRecording();
206
207   // Create frames, store them and pass them to the encoder.
208   CreateTestFrames();
209   EncodeTestFrames();
210
211   // Verify that the recorded frames match the ones passed to the encoder.
212   VerifyTestFrames();
213 }
214
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();
219
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);
223
224   // Start the recorder, so that the wrapper will push frames to it.
225   StartRecording();
226
227   // Create frames, store them and pass them to the encoder.
228   CreateTestFrames();
229   EncodeTestFrames();
230
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();
235   }
236
237   // Verify that the recorded frames match the ones passed to the encoder.
238   VerifyTestFrames();
239 }
240
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();
245
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);
249
250   // Start the recorder, so that the wrapper will push frames to it.
251   StartRecording();
252
253   // Encode a frame, to record it, and consume it from the recorder.
254   EncodeDummyFrame();
255   scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame();
256   EXPECT_TRUE(frame);
257
258   // Create frames, store them and pass them to the encoder.
259   CreateTestFrames();
260   EncodeTestFrames();
261
262   // Verify that the recorded frames match the ones passed to the encoder.
263   VerifyTestFrames();
264 }
265
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();
270
271   // Create frames, store them and pass them to the encoder.
272   CreateTestFrames();
273   EncodeTestFrames();
274
275   // Clear the list of expected test frames, since none should be recorded.
276   STLDeleteElements(&test_frames_);
277
278   // Verify that the recorded frames match the ones passed to the encoder.
279   VerifyTestFrames();
280 }
281
282 }  // namespace remoting