| Index: media/cast/video_receiver/video_decoder_unittest.cc | 
| diff --git a/media/cast/video_receiver/video_decoder_unittest.cc b/media/cast/video_receiver/video_decoder_unittest.cc | 
| index 44de8809f88d10e5d1d499990e3866f62a52eb68..aa6b7ac058c9df3605d49685df77f676e43f1795 100644 | 
| --- a/media/cast/video_receiver/video_decoder_unittest.cc | 
| +++ b/media/cast/video_receiver/video_decoder_unittest.cc | 
| @@ -2,92 +2,186 @@ | 
| // Use of this source code is governed by a BSD-style license that can be | 
| // found in the LICENSE file. | 
|  | 
| -#include <stdint.h> | 
| +#include <cstdlib> | 
|  | 
| #include "base/bind.h" | 
| -#include "base/memory/scoped_ptr.h" | 
| -#include "base/test/simple_test_tick_clock.h" | 
| -#include "base/time/tick_clock.h" | 
| +#include "base/bind_helpers.h" | 
| +#include "base/synchronization/condition_variable.h" | 
| +#include "base/synchronization/lock.h" | 
| +#include "base/time/time.h" | 
| #include "media/cast/cast_config.h" | 
| -#include "media/cast/cast_defines.h" | 
| -#include "media/cast/cast_environment.h" | 
| -#include "media/cast/cast_receiver.h" | 
| -#include "media/cast/test/fake_single_thread_task_runner.h" | 
| +#include "media/cast/test/utility/standalone_cast_environment.h" | 
| +#include "media/cast/test/utility/video_utility.h" | 
| #include "media/cast/video_receiver/video_decoder.h" | 
| -#include "testing/gmock/include/gmock/gmock.h" | 
| +#include "media/cast/video_sender/codecs/vp8/vp8_encoder.h" | 
| +#include "testing/gtest/include/gtest/gtest.h" | 
|  | 
| namespace media { | 
| namespace cast { | 
|  | 
| -using testing::_; | 
| +namespace { | 
|  | 
| -// Random frame size for testing. | 
| -static const int64 kStartMillisecond = INT64_C(1245); | 
| +const int kWidth = 360; | 
| +const int kHeight = 240; | 
| +const int kFrameRate = 10; | 
|  | 
| -namespace { | 
| -class DecodeTestFrameCallback | 
| -    : public base::RefCountedThreadSafe<DecodeTestFrameCallback> { | 
| - public: | 
| -  DecodeTestFrameCallback() {} | 
| +VideoSenderConfig GetVideoSenderConfigForTest() { | 
| +  VideoSenderConfig config; | 
| +  config.width = kWidth; | 
| +  config.height = kHeight; | 
| +  config.max_frame_rate = kFrameRate; | 
| +  return config; | 
| +} | 
|  | 
| -  void DecodeComplete(const scoped_refptr<media::VideoFrame>& decoded_frame, | 
| -                      const base::TimeTicks& render_time) {} | 
| +}  // namespace | 
| + | 
| +class VideoDecoderTest | 
| +    : public ::testing::TestWithParam<transport::VideoCodec> { | 
| + public: | 
| +  VideoDecoderTest() | 
| +      : cast_environment_(new StandaloneCastEnvironment()), | 
| +        vp8_encoder_(GetVideoSenderConfigForTest(), 0), | 
| +        cond_(&lock_) { | 
| +    vp8_encoder_.Initialize(); | 
| +  } | 
|  | 
| protected: | 
| -  virtual ~DecodeTestFrameCallback() {} | 
| +  virtual void SetUp() OVERRIDE { | 
| +    VideoReceiverConfig decoder_config; | 
| +    decoder_config.use_external_decoder = false; | 
| +    decoder_config.codec = GetParam(); | 
| +    video_decoder_.reset(new VideoDecoder(cast_environment_, decoder_config)); | 
| +    CHECK_EQ(STATUS_VIDEO_INITIALIZED, video_decoder_->InitializationResult()); | 
| + | 
| +    next_frame_timestamp_ = base::TimeDelta(); | 
| +    last_frame_id_ = 0; | 
| +    seen_a_decoded_frame_ = false; | 
| + | 
| +    total_video_frames_feed_in_ = 0; | 
| +    total_video_frames_decoded_ = 0; | 
| +  } | 
|  | 
| - private: | 
| -  friend class base::RefCountedThreadSafe<DecodeTestFrameCallback>; | 
| +  // Called from the unit test thread to create another EncodedVideoFrame and | 
| +  // push it into the decoding pipeline. | 
| +  void FeedMoreVideo(int num_dropped_frames) { | 
| +    // Prepare a simulated EncodedVideoFrame to feed into the VideoDecoder. | 
| + | 
| +    const gfx::Size frame_size(kWidth, kHeight); | 
| +    const scoped_refptr<VideoFrame> video_frame = | 
| +        VideoFrame::CreateFrame(VideoFrame::YV12, | 
| +                                frame_size, | 
| +                                gfx::Rect(frame_size), | 
| +                                frame_size, | 
| +                                next_frame_timestamp_); | 
| +    next_frame_timestamp_ += base::TimeDelta::FromSeconds(1) / kFrameRate; | 
| +    PopulateVideoFrame(video_frame, 0); | 
| + | 
| +    // Encode |frame| into |encoded_frame->data|. | 
| +    scoped_ptr<transport::EncodedVideoFrame> encoded_frame( | 
| +        new transport::EncodedVideoFrame()); | 
| +    CHECK_EQ(transport::kVp8, GetParam());  // Only support VP8 test currently. | 
| +    vp8_encoder_.Encode(video_frame, encoded_frame.get()); | 
| +    encoded_frame->codec = GetParam(); | 
| +    encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames; | 
| +    last_frame_id_ = encoded_frame->frame_id; | 
| + | 
| +    { | 
| +      base::AutoLock auto_lock(lock_); | 
| +      ++total_video_frames_feed_in_; | 
| +    } | 
| + | 
| +    cast_environment_->PostTask( | 
| +        CastEnvironment::MAIN, | 
| +        FROM_HERE, | 
| +        base::Bind(&VideoDecoder::DecodeFrame, | 
| +                   base::Unretained(video_decoder_.get()), | 
| +                   base::Passed(&encoded_frame), | 
| +                   base::Bind(&VideoDecoderTest::OnDecodedFrame, | 
| +                              base::Unretained(this), | 
| +                              video_frame, | 
| +                              num_dropped_frames == 0))); | 
| +  } | 
|  | 
| -  DISALLOW_COPY_AND_ASSIGN(DecodeTestFrameCallback); | 
| -}; | 
| -}  // namespace | 
| +  // Blocks the caller until all video that has been feed in has been decoded. | 
| +  void WaitForAllVideoToBeDecoded() { | 
| +    DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| +    base::AutoLock auto_lock(lock_); | 
| +    while (total_video_frames_decoded_ < total_video_frames_feed_in_) | 
| +      cond_.Wait(); | 
| +    EXPECT_EQ(total_video_frames_feed_in_, total_video_frames_decoded_); | 
| +  } | 
|  | 
| -class VideoDecoderTest : public ::testing::Test { | 
| - protected: | 
| -  VideoDecoderTest() | 
| -      : testing_clock_(new base::SimpleTestTickClock()), | 
| -        task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), | 
| -        cast_environment_( | 
| -            new CastEnvironment(scoped_ptr<base::TickClock>(testing_clock_), | 
| -                                task_runner_, | 
| -                                task_runner_, | 
| -                                task_runner_)), | 
| -        test_callback_(new DecodeTestFrameCallback()) { | 
| -    // Configure to vp8. | 
| -    config_.codec = transport::kVp8; | 
| -    config_.use_external_decoder = false; | 
| -    decoder_.reset(new VideoDecoder(config_, cast_environment_)); | 
| -    testing_clock_->Advance( | 
| -        base::TimeDelta::FromMilliseconds(kStartMillisecond)); | 
| + private: | 
| +  // Called by |vp8_decoder_| to deliver each frame of decoded video. | 
| +  void OnDecodedFrame(const scoped_refptr<VideoFrame>& expected_video_frame, | 
| +                      bool should_be_continuous, | 
| +                      const scoped_refptr<VideoFrame>& video_frame, | 
| +                      bool is_continuous) { | 
| +    DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| + | 
| +    // A NULL |video_frame| indicates a decode error, which we don't expect. | 
| +    ASSERT_FALSE(!video_frame); | 
| + | 
| +    // Did the decoder detect whether frames were dropped? | 
| +    EXPECT_EQ(should_be_continuous, is_continuous); | 
| + | 
| +    // Does the video data seem to be intact? | 
| +    EXPECT_EQ(expected_video_frame->coded_size().width(), | 
| +              video_frame->coded_size().width()); | 
| +    EXPECT_EQ(expected_video_frame->coded_size().height(), | 
| +              video_frame->coded_size().height()); | 
| +    EXPECT_LT(40.0, I420PSNR(expected_video_frame, video_frame)); | 
| +    // TODO(miu): Once we start using VideoFrame::timestamp_, check that here. | 
| + | 
| +    // Signal the main test thread that more video was decoded. | 
| +    base::AutoLock auto_lock(lock_); | 
| +    ++total_video_frames_decoded_; | 
| +    cond_.Signal(); | 
| } | 
|  | 
| -  virtual ~VideoDecoderTest() {} | 
| +  const scoped_refptr<StandaloneCastEnvironment> cast_environment_; | 
| +  scoped_ptr<VideoDecoder> video_decoder_; | 
| +  base::TimeDelta next_frame_timestamp_; | 
| +  uint32 last_frame_id_; | 
| +  bool seen_a_decoded_frame_; | 
| + | 
| +  Vp8Encoder vp8_encoder_; | 
|  | 
| -  scoped_ptr<VideoDecoder> decoder_; | 
| -  VideoReceiverConfig config_; | 
| -  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment. | 
| -  scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; | 
| -  scoped_refptr<CastEnvironment> cast_environment_; | 
| -  scoped_refptr<DecodeTestFrameCallback> test_callback_; | 
| +  base::Lock lock_; | 
| +  base::ConditionVariable cond_; | 
| +  int total_video_frames_feed_in_; | 
| +  int total_video_frames_decoded_; | 
|  | 
| DISALLOW_COPY_AND_ASSIGN(VideoDecoderTest); | 
| }; | 
|  | 
| -// TODO(pwestin): EXPECT_DEATH tests can not pass valgrind. | 
| -TEST_F(VideoDecoderTest, DISABLED_SizeZero) { | 
| -  transport::EncodedVideoFrame encoded_frame; | 
| -  base::TimeTicks render_time; | 
| -  encoded_frame.codec = transport::kVp8; | 
| -  EXPECT_DEATH( | 
| -      decoder_->DecodeVideoFrame( | 
| -          &encoded_frame, | 
| -          render_time, | 
| -          base::Bind(&DecodeTestFrameCallback::DecodeComplete, test_callback_)), | 
| -      "Empty frame"); | 
| +TEST_P(VideoDecoderTest, DecodesFrames) { | 
| +  const int kNumFrames = 10; | 
| +  for (int i = 0; i < kNumFrames; ++i) | 
| +    FeedMoreVideo(0); | 
| +  WaitForAllVideoToBeDecoded(); | 
| +} | 
| + | 
| +TEST_P(VideoDecoderTest, RecoversFromDroppedFrames) { | 
| +  const int kNumFrames = 100; | 
| +  int next_drop_at = 3; | 
| +  int next_num_dropped = 1; | 
| +  for (int i = 0; i < kNumFrames; ++i) { | 
| +    if (i == next_drop_at) { | 
| +      const int num_dropped = next_num_dropped++; | 
| +      next_drop_at *= 2; | 
| +      i += num_dropped; | 
| +      FeedMoreVideo(num_dropped); | 
| +    } else { | 
| +      FeedMoreVideo(0); | 
| +    } | 
| +  } | 
| +  WaitForAllVideoToBeDecoded(); | 
| } | 
|  | 
| -// TODO(pwestin): Test decoding a real frame. | 
| +INSTANTIATE_TEST_CASE_P(VideoDecoderTestScenarios, | 
| +                        VideoDecoderTest, | 
| +                        ::testing::Values(transport::kVp8)); | 
|  | 
| }  // namespace cast | 
| }  // namespace media | 
|  |