Home | History | Annotate | Download | only in host
      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