| OLD | NEW | 
|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <stdint.h> | 5 #include <cstdlib> | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/bind_helpers.h" | 
| 9 #include "base/test/simple_test_tick_clock.h" | 9 #include "base/synchronization/condition_variable.h" | 
| 10 #include "base/time/tick_clock.h" | 10 #include "base/synchronization/lock.h" | 
|  | 11 #include "base/time/time.h" | 
| 11 #include "media/cast/cast_config.h" | 12 #include "media/cast/cast_config.h" | 
| 12 #include "media/cast/cast_defines.h" | 13 #include "media/cast/test/utility/standalone_cast_environment.h" | 
| 13 #include "media/cast/cast_environment.h" | 14 #include "media/cast/test/utility/video_utility.h" | 
| 14 #include "media/cast/cast_receiver.h" |  | 
| 15 #include "media/cast/test/fake_single_thread_task_runner.h" |  | 
| 16 #include "media/cast/video_receiver/video_decoder.h" | 15 #include "media/cast/video_receiver/video_decoder.h" | 
| 17 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "media/cast/video_sender/codecs/vp8/vp8_encoder.h" | 
|  | 17 #include "testing/gtest/include/gtest/gtest.h" | 
| 18 | 18 | 
| 19 namespace media { | 19 namespace media { | 
| 20 namespace cast { | 20 namespace cast { | 
| 21 | 21 | 
| 22 using testing::_; | 22 namespace { | 
| 23 | 23 | 
| 24 // Random frame size for testing. | 24 const int kWidth = 360; | 
| 25 static const int64 kStartMillisecond = INT64_C(1245); | 25 const int kHeight = 240; | 
|  | 26 const int kFrameRate = 10; | 
| 26 | 27 | 
| 27 namespace { | 28 VideoSenderConfig GetVideoSenderConfigForTest() { | 
| 28 class DecodeTestFrameCallback | 29   VideoSenderConfig config; | 
| 29     : public base::RefCountedThreadSafe<DecodeTestFrameCallback> { | 30   config.width = kWidth; | 
|  | 31   config.height = kHeight; | 
|  | 32   config.max_frame_rate = kFrameRate; | 
|  | 33   return config; | 
|  | 34 } | 
|  | 35 | 
|  | 36 }  // namespace | 
|  | 37 | 
|  | 38 class VideoDecoderTest | 
|  | 39     : public ::testing::TestWithParam<transport::VideoCodec> { | 
| 30  public: | 40  public: | 
| 31   DecodeTestFrameCallback() {} | 41   VideoDecoderTest() | 
| 32 | 42       : cast_environment_(new StandaloneCastEnvironment()), | 
| 33   void DecodeComplete(const scoped_refptr<media::VideoFrame>& decoded_frame, | 43         vp8_encoder_(GetVideoSenderConfigForTest(), 0), | 
| 34                       const base::TimeTicks& render_time) {} | 44         cond_(&lock_) { | 
|  | 45     vp8_encoder_.Initialize(); | 
|  | 46   } | 
| 35 | 47 | 
| 36  protected: | 48  protected: | 
| 37   virtual ~DecodeTestFrameCallback() {} | 49   virtual void SetUp() OVERRIDE { | 
|  | 50     VideoReceiverConfig decoder_config; | 
|  | 51     decoder_config.use_external_decoder = false; | 
|  | 52     decoder_config.codec = GetParam(); | 
|  | 53     video_decoder_.reset(new VideoDecoder(cast_environment_, decoder_config)); | 
|  | 54     CHECK_EQ(STATUS_VIDEO_INITIALIZED, video_decoder_->InitializationResult()); | 
|  | 55 | 
|  | 56     next_frame_timestamp_ = base::TimeDelta(); | 
|  | 57     last_frame_id_ = 0; | 
|  | 58     seen_a_decoded_frame_ = false; | 
|  | 59 | 
|  | 60     total_video_frames_feed_in_ = 0; | 
|  | 61     total_video_frames_decoded_ = 0; | 
|  | 62   } | 
|  | 63 | 
|  | 64   // Called from the unit test thread to create another EncodedVideoFrame and | 
|  | 65   // push it into the decoding pipeline. | 
|  | 66   void FeedMoreVideo(int num_dropped_frames) { | 
|  | 67     // Prepare a simulated EncodedVideoFrame to feed into the VideoDecoder. | 
|  | 68 | 
|  | 69     const gfx::Size frame_size(kWidth, kHeight); | 
|  | 70     const scoped_refptr<VideoFrame> video_frame = | 
|  | 71         VideoFrame::CreateFrame(VideoFrame::YV12, | 
|  | 72                                 frame_size, | 
|  | 73                                 gfx::Rect(frame_size), | 
|  | 74                                 frame_size, | 
|  | 75                                 next_frame_timestamp_); | 
|  | 76     next_frame_timestamp_ += base::TimeDelta::FromSeconds(1) / kFrameRate; | 
|  | 77     PopulateVideoFrame(video_frame, 0); | 
|  | 78 | 
|  | 79     // Encode |frame| into |encoded_frame->data|. | 
|  | 80     scoped_ptr<transport::EncodedVideoFrame> encoded_frame( | 
|  | 81         new transport::EncodedVideoFrame()); | 
|  | 82     CHECK_EQ(transport::kVp8, GetParam());  // Only support VP8 test currently. | 
|  | 83     vp8_encoder_.Encode(video_frame, encoded_frame.get()); | 
|  | 84     encoded_frame->codec = GetParam(); | 
|  | 85     encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames; | 
|  | 86     last_frame_id_ = encoded_frame->frame_id; | 
|  | 87 | 
|  | 88     { | 
|  | 89       base::AutoLock auto_lock(lock_); | 
|  | 90       ++total_video_frames_feed_in_; | 
|  | 91     } | 
|  | 92 | 
|  | 93     cast_environment_->PostTask( | 
|  | 94         CastEnvironment::MAIN, | 
|  | 95         FROM_HERE, | 
|  | 96         base::Bind(&VideoDecoder::DecodeFrame, | 
|  | 97                    base::Unretained(video_decoder_.get()), | 
|  | 98                    base::Passed(&encoded_frame), | 
|  | 99                    base::Bind(&VideoDecoderTest::OnDecodedFrame, | 
|  | 100                               base::Unretained(this), | 
|  | 101                               video_frame, | 
|  | 102                               num_dropped_frames == 0))); | 
|  | 103   } | 
|  | 104 | 
|  | 105   // Blocks the caller until all video that has been feed in has been decoded. | 
|  | 106   void WaitForAllVideoToBeDecoded() { | 
|  | 107     DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
|  | 108     base::AutoLock auto_lock(lock_); | 
|  | 109     while (total_video_frames_decoded_ < total_video_frames_feed_in_) | 
|  | 110       cond_.Wait(); | 
|  | 111     EXPECT_EQ(total_video_frames_feed_in_, total_video_frames_decoded_); | 
|  | 112   } | 
| 38 | 113 | 
| 39  private: | 114  private: | 
| 40   friend class base::RefCountedThreadSafe<DecodeTestFrameCallback>; | 115   // Called by |vp8_decoder_| to deliver each frame of decoded video. | 
|  | 116   void OnDecodedFrame(const scoped_refptr<VideoFrame>& expected_video_frame, | 
|  | 117                       bool should_be_continuous, | 
|  | 118                       const scoped_refptr<VideoFrame>& video_frame, | 
|  | 119                       bool is_continuous) { | 
|  | 120     DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 41 | 121 | 
| 42   DISALLOW_COPY_AND_ASSIGN(DecodeTestFrameCallback); | 122     // A NULL |video_frame| indicates a decode error, which we don't expect. | 
| 43 }; | 123     ASSERT_FALSE(!video_frame); | 
| 44 }  // namespace |  | 
| 45 | 124 | 
| 46 class VideoDecoderTest : public ::testing::Test { | 125     // Did the decoder detect whether frames were dropped? | 
| 47  protected: | 126     EXPECT_EQ(should_be_continuous, is_continuous); | 
| 48   VideoDecoderTest() | 127 | 
| 49       : testing_clock_(new base::SimpleTestTickClock()), | 128     // Does the video data seem to be intact? | 
| 50         task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), | 129     EXPECT_EQ(expected_video_frame->coded_size().width(), | 
| 51         cast_environment_( | 130               video_frame->coded_size().width()); | 
| 52             new CastEnvironment(scoped_ptr<base::TickClock>(testing_clock_), | 131     EXPECT_EQ(expected_video_frame->coded_size().height(), | 
| 53                                 task_runner_, | 132               video_frame->coded_size().height()); | 
| 54                                 task_runner_, | 133     EXPECT_LT(40.0, I420PSNR(expected_video_frame, video_frame)); | 
| 55                                 task_runner_)), | 134     // TODO(miu): Once we start using VideoFrame::timestamp_, check that here. | 
| 56         test_callback_(new DecodeTestFrameCallback()) { | 135 | 
| 57     // Configure to vp8. | 136     // Signal the main test thread that more video was decoded. | 
| 58     config_.codec = transport::kVp8; | 137     base::AutoLock auto_lock(lock_); | 
| 59     config_.use_external_decoder = false; | 138     ++total_video_frames_decoded_; | 
| 60     decoder_.reset(new VideoDecoder(config_, cast_environment_)); | 139     cond_.Signal(); | 
| 61     testing_clock_->Advance( |  | 
| 62         base::TimeDelta::FromMilliseconds(kStartMillisecond)); |  | 
| 63   } | 140   } | 
| 64 | 141 | 
| 65   virtual ~VideoDecoderTest() {} | 142   const scoped_refptr<StandaloneCastEnvironment> cast_environment_; | 
|  | 143   scoped_ptr<VideoDecoder> video_decoder_; | 
|  | 144   base::TimeDelta next_frame_timestamp_; | 
|  | 145   uint32 last_frame_id_; | 
|  | 146   bool seen_a_decoded_frame_; | 
| 66 | 147 | 
| 67   scoped_ptr<VideoDecoder> decoder_; | 148   Vp8Encoder vp8_encoder_; | 
| 68   VideoReceiverConfig config_; | 149 | 
| 69   base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment. | 150   base::Lock lock_; | 
| 70   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; | 151   base::ConditionVariable cond_; | 
| 71   scoped_refptr<CastEnvironment> cast_environment_; | 152   int total_video_frames_feed_in_; | 
| 72   scoped_refptr<DecodeTestFrameCallback> test_callback_; | 153   int total_video_frames_decoded_; | 
| 73 | 154 | 
| 74   DISALLOW_COPY_AND_ASSIGN(VideoDecoderTest); | 155   DISALLOW_COPY_AND_ASSIGN(VideoDecoderTest); | 
| 75 }; | 156 }; | 
| 76 | 157 | 
| 77 // TODO(pwestin): EXPECT_DEATH tests can not pass valgrind. | 158 TEST_P(VideoDecoderTest, DecodesFrames) { | 
| 78 TEST_F(VideoDecoderTest, DISABLED_SizeZero) { | 159   const int kNumFrames = 10; | 
| 79   transport::EncodedVideoFrame encoded_frame; | 160   for (int i = 0; i < kNumFrames; ++i) | 
| 80   base::TimeTicks render_time; | 161     FeedMoreVideo(0); | 
| 81   encoded_frame.codec = transport::kVp8; | 162   WaitForAllVideoToBeDecoded(); | 
| 82   EXPECT_DEATH( |  | 
| 83       decoder_->DecodeVideoFrame( |  | 
| 84           &encoded_frame, |  | 
| 85           render_time, |  | 
| 86           base::Bind(&DecodeTestFrameCallback::DecodeComplete, test_callback_)), |  | 
| 87       "Empty frame"); |  | 
| 88 } | 163 } | 
| 89 | 164 | 
| 90 // TODO(pwestin): Test decoding a real frame. | 165 TEST_P(VideoDecoderTest, RecoversFromDroppedFrames) { | 
|  | 166   const int kNumFrames = 100; | 
|  | 167   int next_drop_at = 3; | 
|  | 168   int next_num_dropped = 1; | 
|  | 169   for (int i = 0; i < kNumFrames; ++i) { | 
|  | 170     if (i == next_drop_at) { | 
|  | 171       const int num_dropped = next_num_dropped++; | 
|  | 172       next_drop_at *= 2; | 
|  | 173       i += num_dropped; | 
|  | 174       FeedMoreVideo(num_dropped); | 
|  | 175     } else { | 
|  | 176       FeedMoreVideo(0); | 
|  | 177     } | 
|  | 178   } | 
|  | 179   WaitForAllVideoToBeDecoded(); | 
|  | 180 } | 
|  | 181 | 
|  | 182 INSTANTIATE_TEST_CASE_P(VideoDecoderTestScenarios, | 
|  | 183                         VideoDecoderTest, | 
|  | 184                         ::testing::Values(transport::kVp8)); | 
| 91 | 185 | 
| 92 }  // namespace cast | 186 }  // namespace cast | 
| 93 }  // namespace media | 187 }  // namespace media | 
| OLD | NEW | 
|---|