OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <cstdlib> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/synchronization/condition_variable.h" | |
10 #include "base/synchronization/lock.h" | |
11 #include "base/time/time.h" | |
12 #include "media/cast/cast_config.h" | |
13 #include "media/cast/test/utility/default_config.h" | |
14 #include "media/cast/test/utility/standalone_cast_environment.h" | |
15 #include "media/cast/test/utility/video_utility.h" | |
16 #include "media/cast/video_receiver/video_decoder.h" | |
17 #include "media/cast/video_sender/codecs/vp8/vp8_encoder.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace media { | |
21 namespace cast { | |
22 | |
23 namespace { | |
24 | |
25 const int kWidth = 360; | |
26 const int kHeight = 240; | |
27 const int kFrameRate = 10; | |
28 | |
29 VideoSenderConfig GetVideoSenderConfigForTest() { | |
30 VideoSenderConfig config; | |
31 config.width = kWidth; | |
32 config.height = kHeight; | |
33 config.max_frame_rate = kFrameRate; | |
34 return config; | |
35 } | |
36 | |
37 } // namespace | |
38 | |
39 class VideoDecoderTest | |
40 : public ::testing::TestWithParam<transport::VideoCodec> { | |
41 public: | |
42 VideoDecoderTest() | |
43 : cast_environment_(new StandaloneCastEnvironment()), | |
44 vp8_encoder_(GetVideoSenderConfigForTest(), 0), | |
45 cond_(&lock_) { | |
46 vp8_encoder_.Initialize(); | |
47 } | |
48 | |
49 protected: | |
50 virtual void SetUp() OVERRIDE { | |
51 FrameReceiverConfig decoder_config = GetDefaultVideoReceiverConfig(); | |
52 decoder_config.codec.video = 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 EncodedFrame and push it | |
65 // into the decoding pipeline. | |
66 void FeedMoreVideo(int num_dropped_frames) { | |
67 // Prepare a simulated EncodedFrame 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::EncodedFrame> encoded_frame( | |
81 new transport::EncodedFrame()); | |
82 CHECK_EQ(transport::kVp8, GetParam()); // Only support VP8 test currently. | |
83 vp8_encoder_.Encode(video_frame, encoded_frame.get()); | |
84 encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames; | |
85 last_frame_id_ = encoded_frame->frame_id; | |
86 | |
87 { | |
88 base::AutoLock auto_lock(lock_); | |
89 ++total_video_frames_feed_in_; | |
90 } | |
91 | |
92 cast_environment_->PostTask( | |
93 CastEnvironment::MAIN, | |
94 FROM_HERE, | |
95 base::Bind(&VideoDecoder::DecodeFrame, | |
96 base::Unretained(video_decoder_.get()), | |
97 base::Passed(&encoded_frame), | |
98 base::Bind(&VideoDecoderTest::OnDecodedFrame, | |
99 base::Unretained(this), | |
100 video_frame, | |
101 num_dropped_frames == 0))); | |
102 } | |
103 | |
104 // Blocks the caller until all video that has been feed in has been decoded. | |
105 void WaitForAllVideoToBeDecoded() { | |
106 DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
107 base::AutoLock auto_lock(lock_); | |
108 while (total_video_frames_decoded_ < total_video_frames_feed_in_) | |
109 cond_.Wait(); | |
110 EXPECT_EQ(total_video_frames_feed_in_, total_video_frames_decoded_); | |
111 } | |
112 | |
113 private: | |
114 // Called by |vp8_decoder_| to deliver each frame of decoded video. | |
115 void OnDecodedFrame(const scoped_refptr<VideoFrame>& expected_video_frame, | |
116 bool should_be_continuous, | |
117 const scoped_refptr<VideoFrame>& video_frame, | |
118 bool is_continuous) { | |
119 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
120 | |
121 // A NULL |video_frame| indicates a decode error, which we don't expect. | |
122 ASSERT_FALSE(!video_frame); | |
123 | |
124 // Did the decoder detect whether frames were dropped? | |
125 EXPECT_EQ(should_be_continuous, is_continuous); | |
126 | |
127 // Does the video data seem to be intact? | |
128 EXPECT_EQ(expected_video_frame->coded_size().width(), | |
129 video_frame->coded_size().width()); | |
130 EXPECT_EQ(expected_video_frame->coded_size().height(), | |
131 video_frame->coded_size().height()); | |
132 EXPECT_LT(40.0, I420PSNR(expected_video_frame, video_frame)); | |
133 // TODO(miu): Once we start using VideoFrame::timestamp_, check that here. | |
134 | |
135 // Signal the main test thread that more video was decoded. | |
136 base::AutoLock auto_lock(lock_); | |
137 ++total_video_frames_decoded_; | |
138 cond_.Signal(); | |
139 } | |
140 | |
141 const scoped_refptr<StandaloneCastEnvironment> cast_environment_; | |
142 scoped_ptr<VideoDecoder> video_decoder_; | |
143 base::TimeDelta next_frame_timestamp_; | |
144 uint32 last_frame_id_; | |
145 bool seen_a_decoded_frame_; | |
146 | |
147 Vp8Encoder vp8_encoder_; | |
148 | |
149 base::Lock lock_; | |
150 base::ConditionVariable cond_; | |
151 int total_video_frames_feed_in_; | |
152 int total_video_frames_decoded_; | |
153 | |
154 DISALLOW_COPY_AND_ASSIGN(VideoDecoderTest); | |
155 }; | |
156 | |
157 TEST_P(VideoDecoderTest, DecodesFrames) { | |
158 const int kNumFrames = 10; | |
159 for (int i = 0; i < kNumFrames; ++i) | |
160 FeedMoreVideo(0); | |
161 WaitForAllVideoToBeDecoded(); | |
162 } | |
163 | |
164 TEST_P(VideoDecoderTest, RecoversFromDroppedFrames) { | |
165 const int kNumFrames = 100; | |
166 int next_drop_at = 3; | |
167 int next_num_dropped = 1; | |
168 for (int i = 0; i < kNumFrames; ++i) { | |
169 if (i == next_drop_at) { | |
170 const int num_dropped = next_num_dropped++; | |
171 next_drop_at *= 2; | |
172 i += num_dropped; | |
173 FeedMoreVideo(num_dropped); | |
174 } else { | |
175 FeedMoreVideo(0); | |
176 } | |
177 } | |
178 WaitForAllVideoToBeDecoded(); | |
179 } | |
180 | |
181 INSTANTIATE_TEST_CASE_P(VideoDecoderTestScenarios, | |
182 VideoDecoderTest, | |
183 ::testing::Values(transport::kVp8)); | |
184 | |
185 } // namespace cast | |
186 } // namespace media | |
OLD | NEW |