Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(354)

Side by Side Diff: media/cast/sender/h264_vt_encoder_unittest.cc

Issue 450693006: VideoToolbox encoder for cast senders. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unit test link error. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <queue>
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/test/launcher/unit_test_launcher.h"
11 #include "base/test/simple_test_tick_clock.h"
12 #include "base/test/test_suite.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/media.h"
15 #include "media/base/media_switches.h"
16 #include "media/cast/sender/h264_vt_encoder.h"
17 #include "media/cast/sender/video_frame_factory.h"
18 #include "media/cast/test/utility/default_config.h"
19 #include "media/cast/test/utility/video_utility.h"
20 #include "media/ffmpeg/ffmpeg_common.h"
21 #include "media/filters/ffmpeg_glue.h"
22 #include "media/filters/ffmpeg_video_decoder.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace {
26
27 class MediaTestSuite : public base::TestSuite {
28 public:
29 MediaTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
30 ~MediaTestSuite() override {}
31
32 protected:
33 void Initialize() override;
34 };
35
36 void MediaTestSuite::Initialize() {
37 base::TestSuite::Initialize();
38 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
39 command_line->AppendSwitch(switches::kEnableInbandTextTracks);
40 media::InitializeMediaLibraryForTesting();
41 }
42
43 } // namespace
44
45 int main(int argc, char** argv) {
46 {
47 base::AtExitManager at_exit_manager;
48 CHECK(VideoToolboxGlue::Get())
49 << "VideoToolbox is not available. Requires OS X 10.8 or iOS 8.0.";
50 }
51 MediaTestSuite test_suite(argc, argv);
52 return base::LaunchUnitTests(
53 argc, argv,
54 base::Bind(&MediaTestSuite::Run, base::Unretained(&test_suite)));
55 }
56
57 namespace media {
58 namespace cast {
59
60 // See comment in end2end_unittest.cc for details on this value.
61 const double kVideoAcceptedPSNR = 38.0;
62
63 void SavePipelineStatus(PipelineStatus* out_status, PipelineStatus in_status) {
64 *out_status = in_status;
65 }
66
67 void SaveInitializationStatus(CastInitializationStatus* out_status,
68 CastInitializationStatus in_status) {
69 *out_status = in_status;
70 }
71
72 class MetadataRecorder : public base::RefCountedThreadSafe<MetadataRecorder> {
73 public:
74 MetadataRecorder() : count_frames_delivered_(0) {}
75
76 int count_frames_delivered() const { return count_frames_delivered_; }
77
78 void PushExpectation(uint32 expected_frame_id,
79 uint32 expected_last_referenced_frame_id,
80 uint32 expected_rtp_timestamp,
81 const base::TimeTicks& expected_reference_time) {
82 expectations_.push(Expectation{expected_frame_id,
83 expected_last_referenced_frame_id,
84 expected_rtp_timestamp,
85 expected_reference_time});
86 }
87
88 void Check(scoped_ptr<EncodedFrame> encoded_frame) {
miu 2014/11/20 23:16:56 naming nit: How about CompareFrameWithExpected()?
jfroy 2014/11/20 23:38:30 Sure.
89 EXPECT_LT(0u, expectations_.size());
miu 2014/11/20 23:16:55 This should be ASSERT_LT() to cause an early retur
90 auto e = expectations_.front();
91 expectations_.pop();
92 if (e.expected_frame_id != e.expected_last_referenced_frame_id) {
93 EXPECT_EQ(EncodedFrame::DEPENDENT, encoded_frame->dependency);
94 } else {
95 EXPECT_EQ(EncodedFrame::KEY, encoded_frame->dependency);
96 }
97 EXPECT_EQ(e.expected_frame_id, encoded_frame->frame_id);
98 EXPECT_EQ(e.expected_last_referenced_frame_id,
99 encoded_frame->referenced_frame_id)
100 << "frame id: " << e.expected_frame_id;
101 EXPECT_EQ(e.expected_rtp_timestamp, encoded_frame->rtp_timestamp);
102 EXPECT_EQ(e.expected_reference_time, encoded_frame->reference_time);
103 EXPECT_FALSE(encoded_frame->data.empty());
104 ++count_frames_delivered_;
105 }
106
107 private:
108 friend class base::RefCountedThreadSafe<MetadataRecorder>;
109 virtual ~MetadataRecorder() {}
110
111 int count_frames_delivered_;
112
113 struct Expectation {
114 uint32 expected_frame_id;
115 uint32 expected_last_referenced_frame_id;
116 uint32 expected_rtp_timestamp;
117 base::TimeTicks expected_reference_time;
118 };
119 std::queue<Expectation> expectations_;
120
121 DISALLOW_COPY_AND_ASSIGN(MetadataRecorder);
122 };
123
124 class EndToEndFrameChecker
125 : public base::RefCountedThreadSafe<EndToEndFrameChecker> {
126 public:
127 explicit EndToEndFrameChecker(const VideoDecoderConfig& config)
128 : count_frames_checked_(0) {
129 auto message_loop = base::MessageLoop::current();
130 decoder_.reset(new FFmpegVideoDecoder(message_loop->task_runner()));
131 PipelineStatus pipeline_status;
132 decoder_->Initialize(
133 config, false, base::Bind(&SavePipelineStatus, &pipeline_status),
134 base::Bind(&EndToEndFrameChecker::Check, base::Unretained(this)));
135 message_loop->RunUntilIdle();
136 EXPECT_EQ(PIPELINE_OK, pipeline_status);
137 }
138
139 void PushExpectation(const scoped_refptr<VideoFrame>& frame) {
140 expectations_.push(frame);
141 }
142
143 void EncodeDone(scoped_ptr<EncodedFrame> encoded_frame) {
144 auto buffer = DecoderBuffer::CopyFrom(encoded_frame->bytes(),
145 encoded_frame->data.size());
146 decoder_->Decode(buffer, base::Bind(&EndToEndFrameChecker::DecodeDone,
147 base::Unretained(this)));
148 }
149
150 void Check(const scoped_refptr<VideoFrame>& frame) {
miu 2014/11/20 23:16:56 naming and use of ASSERT_LT() here too
151 EXPECT_LT(0u, expectations_.size());
152 auto& e = expectations_.front();
153 expectations_.pop();
154 EXPECT_LE(kVideoAcceptedPSNR, I420PSNR(e, frame));
155 ++count_frames_checked_;
156 }
157
158 void DecodeDone(VideoDecoder::Status status) {
159 EXPECT_EQ(VideoDecoder::kOk, status);
160 }
161
162 int count_frames_checked() const { return count_frames_checked_; }
163
164 private:
165 friend class base::RefCountedThreadSafe<EndToEndFrameChecker>;
166 virtual ~EndToEndFrameChecker() {}
167
168 scoped_ptr<FFmpegVideoDecoder> decoder_;
miu 2014/11/20 23:16:56 nit: Don't need pointer-to-FFmpegVideoDecoder. Ju
169 std::queue<scoped_refptr<VideoFrame>> expectations_;
170 int count_frames_checked_;
171
172 DISALLOW_COPY_AND_ASSIGN(EndToEndFrameChecker);
173 };
174
175 void CreateFrameAndMemsetPlane(VideoFrameFactory* const video_frame_factory) {
176 auto video_frame = video_frame_factory->CreateFrame(base::TimeDelta());
177 ASSERT_TRUE(video_frame.get());
178 auto cv_pixel_buffer = video_frame->cv_pixel_buffer();
179 ASSERT_TRUE(cv_pixel_buffer);
180 CVPixelBufferLockBaseAddress(cv_pixel_buffer, 0);
181 auto ptr = CVPixelBufferGetBaseAddressOfPlane(cv_pixel_buffer, 0);
182 ASSERT_TRUE(ptr);
183 memset(ptr, 0xfe, CVPixelBufferGetBytesPerRowOfPlane(cv_pixel_buffer, 0) *
184 CVPixelBufferGetHeightOfPlane(cv_pixel_buffer, 0));
185 CVPixelBufferUnlockBaseAddress(cv_pixel_buffer, 0);
186 }
187
188 class H264VideoToolboxEncoderTest : public ::testing::Test {
189 protected:
190 H264VideoToolboxEncoderTest() {
191 cast_initialization_status_ = STATUS_VIDEO_UNINITIALIZED;
192 frame_->set_timestamp(base::TimeDelta());
193 }
194
195 virtual ~H264VideoToolboxEncoderTest() {}
196
197 void SetUp() override {
198 clock_ = new base::SimpleTestTickClock();
199 clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
200
201 cast_environment_ = new CastEnvironment(
202 scoped_ptr<base::TickClock>(clock_).Pass(),
203 message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
204 message_loop_.message_loop_proxy());
205 encoder_.reset(new H264VideoToolboxEncoder(
206 cast_environment_, video_sender_config_,
207 base::Bind(&SaveInitializationStatus, &cast_initialization_status_)));
208 message_loop_.RunUntilIdle();
209 EXPECT_EQ(STATUS_VIDEO_INITIALIZED, cast_initialization_status_);
210 }
211
212 void TearDown() override {
213 encoder_.reset();
214 message_loop_.RunUntilIdle();
215 }
216
217 void AdvanceClockAndVideoFrameTimestamp() {
218 clock_->Advance(base::TimeDelta::FromMilliseconds(33));
219 frame_->set_timestamp(frame_->timestamp() +
220 base::TimeDelta::FromMilliseconds(33));
221 }
222
223 static void SetUpTestCase() {
224 // Reusable test data.
225 video_sender_config_ = GetDefaultVideoSenderConfig();
226 video_sender_config_.codec = CODEC_VIDEO_H264;
227 gfx::Size size(video_sender_config_.width, video_sender_config_.height);
228 frame_ = media::VideoFrame::CreateFrame(
229 VideoFrame::I420, size, gfx::Rect(size), size, base::TimeDelta());
230 PopulateVideoFrame(frame_.get(), 123);
231 }
232
233 static void TearDownTestCase() { frame_ = nullptr; }
234
235 static scoped_refptr<media::VideoFrame> frame_;
236 static VideoSenderConfig video_sender_config_;
237
238 base::SimpleTestTickClock* clock_; // Owned by CastEnvironment.
239 base::MessageLoop message_loop_;
240 scoped_ptr<VideoEncoder> encoder_;
241 scoped_refptr<CastEnvironment> cast_environment_;
miu 2014/11/20 23:16:55 nit: It might not matter, but swap this line with
jfroy 2014/11/20 23:38:30 It did not matter because of encoder_.reset(); in
242 CastInitializationStatus cast_initialization_status_;
243
244 private:
245 DISALLOW_COPY_AND_ASSIGN(H264VideoToolboxEncoderTest);
246 };
247
248 // static
249 scoped_refptr<media::VideoFrame> H264VideoToolboxEncoderTest::frame_;
250 VideoSenderConfig H264VideoToolboxEncoderTest::video_sender_config_;
251
252 TEST_F(H264VideoToolboxEncoderTest, CheckFrameMetadataSequence) {
253 scoped_refptr<MetadataRecorder> metadata_recorder(new MetadataRecorder());
254 VideoEncoder::FrameEncodedCallback cb =
255 base::Bind(&MetadataRecorder::Check, metadata_recorder.get());
256
257 metadata_recorder->PushExpectation(
258 0, 0, TimeDeltaToRtpDelta(frame_->timestamp(), kVideoFrequency),
259 clock_->NowTicks());
260 EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
261 message_loop_.RunUntilIdle();
262
263 for (uint32 frame_id = 1; frame_id < 10; ++frame_id) {
264 AdvanceClockAndVideoFrameTimestamp();
265 metadata_recorder->PushExpectation(
266 frame_id, frame_id - 1,
267 TimeDeltaToRtpDelta(frame_->timestamp(), kVideoFrequency),
268 clock_->NowTicks());
269 EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
270 }
271
272 encoder_.reset();
273 message_loop_.RunUntilIdle();
274
275 EXPECT_EQ(10, metadata_recorder->count_frames_delivered());
276 }
277
278 #if defined(USE_PROPRIETARY_CODECS)
279 TEST_F(H264VideoToolboxEncoderTest, CheckFramesAreDecodable) {
280 VideoDecoderConfig config(kCodecH264, H264PROFILE_MAIN, frame_->format(),
281 frame_->coded_size(), frame_->visible_rect(),
282 frame_->natural_size(), nullptr, 0, false);
283 scoped_refptr<EndToEndFrameChecker> checker(new EndToEndFrameChecker(config));
284
285 VideoEncoder::FrameEncodedCallback cb =
286 base::Bind(&EndToEndFrameChecker::EncodeDone, checker.get());
287 for (uint32 frame_id = 0; frame_id < 6; ++frame_id) {
288 checker->PushExpectation(frame_);
289 EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
290 AdvanceClockAndVideoFrameTimestamp();
291 }
292
293 encoder_.reset();
294 message_loop_.RunUntilIdle();
295
296 EXPECT_EQ(5, checker->count_frames_checked());
297 }
298 #endif
299
300 TEST_F(H264VideoToolboxEncoderTest, CheckVideoFrameFactory) {
301 auto video_frame_factory = encoder_->CreateVideoFrameFactory();
302 ASSERT_TRUE(video_frame_factory.get());
303 CreateFrameAndMemsetPlane(video_frame_factory.get());
304 encoder_.reset();
305 message_loop_.RunUntilIdle();
306 CreateFrameAndMemsetPlane(video_frame_factory.get());
307 }
308
309 } // namespace cast
310 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698