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.
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/power_monitor/power_monitor.h"
11 #include "base/test/launcher/unit_test_launcher.h"
12 #include "base/test/power_monitor_test_base.h"
13 #include "base/test/simple_test_tick_clock.h"
14 #include "base/test/test_suite.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/media.h"
17 #include "media/base/media_switches.h"
18 #include "media/cast/sender/h264_vt_encoder.h"
19 #include "media/cast/sender/video_frame_factory.h"
20 #include "media/cast/test/utility/default_config.h"
21 #include "media/cast/test/utility/video_utility.h"
22 #include "media/ffmpeg/ffmpeg_common.h"
23 #include "media/filters/ffmpeg_glue.h"
24 #include "media/filters/ffmpeg_video_decoder.h"
25 #include "testing/gtest/include/gtest/gtest.h"
29 const int kVideoWidth
= 1280;
30 const int kVideoHeight
= 720;
32 class MediaTestSuite
: public base::TestSuite
{
34 MediaTestSuite(int argc
, char** argv
) : TestSuite(argc
, argv
) {}
35 ~MediaTestSuite() final
{}
38 void Initialize() final
;
41 void MediaTestSuite::Initialize() {
42 base::TestSuite::Initialize();
43 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
44 command_line
->AppendSwitch(switches::kEnableInbandTextTracks
);
45 media::InitializeMediaLibrary();
50 int main(int argc
, char** argv
) {
52 base::AtExitManager at_exit_manager
;
53 CHECK(VideoToolboxGlue::Get())
54 << "VideoToolbox is not available. Requires OS X 10.8 or iOS 8.0.";
56 MediaTestSuite
test_suite(argc
, argv
);
57 return base::LaunchUnitTests(
59 base::Bind(&MediaTestSuite::Run
, base::Unretained(&test_suite
)));
65 // See comment in end2end_unittest.cc for details on this value.
66 const double kVideoAcceptedPSNR
= 38.0;
68 void SaveDecoderInitResult(bool* out_result
, bool in_result
) {
69 *out_result
= in_result
;
72 void SaveOperationalStatus(OperationalStatus
* out_status
,
73 OperationalStatus in_status
) {
74 *out_status
= in_status
;
77 class MetadataRecorder
: public base::RefCountedThreadSafe
<MetadataRecorder
> {
79 MetadataRecorder() : count_frames_delivered_(0) {}
81 int count_frames_delivered() const { return count_frames_delivered_
; }
83 void PushExpectation(uint32 expected_frame_id
,
84 uint32 expected_last_referenced_frame_id
,
85 uint32 expected_rtp_timestamp
,
86 const base::TimeTicks
& expected_reference_time
) {
87 expectations_
.push(Expectation
{expected_frame_id
,
88 expected_last_referenced_frame_id
,
89 expected_rtp_timestamp
,
90 expected_reference_time
});
93 void CompareFrameWithExpected(scoped_ptr
<SenderEncodedFrame
> encoded_frame
) {
94 ASSERT_LT(0u, expectations_
.size());
95 auto e
= expectations_
.front();
97 if (e
.expected_frame_id
!= e
.expected_last_referenced_frame_id
) {
98 EXPECT_EQ(EncodedFrame::DEPENDENT
, encoded_frame
->dependency
);
100 EXPECT_EQ(EncodedFrame::KEY
, encoded_frame
->dependency
);
102 EXPECT_EQ(e
.expected_frame_id
, encoded_frame
->frame_id
);
103 EXPECT_EQ(e
.expected_last_referenced_frame_id
,
104 encoded_frame
->referenced_frame_id
)
105 << "frame id: " << e
.expected_frame_id
;
106 EXPECT_EQ(e
.expected_rtp_timestamp
, encoded_frame
->rtp_timestamp
);
107 EXPECT_EQ(e
.expected_reference_time
, encoded_frame
->reference_time
);
108 EXPECT_FALSE(encoded_frame
->data
.empty());
109 ++count_frames_delivered_
;
113 friend class base::RefCountedThreadSafe
<MetadataRecorder
>;
114 virtual ~MetadataRecorder() {}
116 int count_frames_delivered_
;
119 uint32 expected_frame_id
;
120 uint32 expected_last_referenced_frame_id
;
121 uint32 expected_rtp_timestamp
;
122 base::TimeTicks expected_reference_time
;
124 std::queue
<Expectation
> expectations_
;
126 DISALLOW_COPY_AND_ASSIGN(MetadataRecorder
);
129 class EndToEndFrameChecker
130 : public base::RefCountedThreadSafe
<EndToEndFrameChecker
> {
132 explicit EndToEndFrameChecker(const VideoDecoderConfig
& config
)
133 : decoder_(base::MessageLoop::current()->task_runner()),
134 count_frames_checked_(0) {
135 bool decoder_init_result
;
137 config
, false, base::Bind(&SaveDecoderInitResult
, &decoder_init_result
),
138 base::Bind(&EndToEndFrameChecker::CompareFrameWithExpected
,
139 base::Unretained(this)));
140 base::MessageLoop::current()->RunUntilIdle();
141 EXPECT_TRUE(decoder_init_result
);
144 void PushExpectation(const scoped_refptr
<VideoFrame
>& frame
) {
145 expectations_
.push(frame
);
148 void EncodeDone(scoped_ptr
<SenderEncodedFrame
> encoded_frame
) {
149 auto buffer
= DecoderBuffer::CopyFrom(encoded_frame
->bytes(),
150 encoded_frame
->data
.size());
151 decoder_
.Decode(buffer
, base::Bind(&EndToEndFrameChecker::DecodeDone
,
152 base::Unretained(this)));
155 void CompareFrameWithExpected(const scoped_refptr
<VideoFrame
>& frame
) {
156 ASSERT_LT(0u, expectations_
.size());
157 auto& e
= expectations_
.front();
159 EXPECT_LE(kVideoAcceptedPSNR
, I420PSNR(e
, frame
));
160 ++count_frames_checked_
;
163 void DecodeDone(VideoDecoder::Status status
) {
164 EXPECT_EQ(VideoDecoder::kOk
, status
);
167 int count_frames_checked() const { return count_frames_checked_
; }
170 friend class base::RefCountedThreadSafe
<EndToEndFrameChecker
>;
171 virtual ~EndToEndFrameChecker() {}
173 FFmpegVideoDecoder decoder_
;
174 std::queue
<scoped_refptr
<VideoFrame
>> expectations_
;
175 int count_frames_checked_
;
177 DISALLOW_COPY_AND_ASSIGN(EndToEndFrameChecker
);
180 void CreateFrameAndMemsetPlane(VideoFrameFactory
* const video_frame_factory
) {
181 const scoped_refptr
<media::VideoFrame
> video_frame
=
182 video_frame_factory
->MaybeCreateFrame(
183 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta());
184 ASSERT_TRUE(video_frame
.get());
185 auto cv_pixel_buffer
= video_frame
->cv_pixel_buffer();
186 ASSERT_TRUE(cv_pixel_buffer
);
187 CVPixelBufferLockBaseAddress(cv_pixel_buffer
, 0);
188 auto ptr
= CVPixelBufferGetBaseAddressOfPlane(cv_pixel_buffer
, 0);
190 memset(ptr
, 0xfe, CVPixelBufferGetBytesPerRowOfPlane(cv_pixel_buffer
, 0) *
191 CVPixelBufferGetHeightOfPlane(cv_pixel_buffer
, 0));
192 CVPixelBufferUnlockBaseAddress(cv_pixel_buffer
, 0);
195 void NoopFrameEncodedCallback(
196 scoped_ptr
<media::cast::SenderEncodedFrame
> /*encoded_frame*/) {
199 class TestPowerSource
: public base::PowerMonitorSource
{
201 void GenerateSuspendEvent() {
202 ProcessPowerEvent(SUSPEND_EVENT
);
203 base::MessageLoop::current()->RunUntilIdle();
205 void GenerateResumeEvent() {
206 ProcessPowerEvent(RESUME_EVENT
);
207 base::MessageLoop::current()->RunUntilIdle();
211 bool IsOnBatteryPowerImpl() final
{ return false; }
214 class H264VideoToolboxEncoderTest
: public ::testing::Test
{
216 H264VideoToolboxEncoderTest() = default;
219 clock_
= new base::SimpleTestTickClock();
220 clock_
->Advance(base::TimeTicks::Now() - base::TimeTicks());
222 power_source_
= new TestPowerSource();
223 power_monitor_
.reset(
224 new base::PowerMonitor(scoped_ptr
<TestPowerSource
>(power_source_
)));
226 cast_environment_
= new CastEnvironment(
227 scoped_ptr
<base::TickClock
>(clock_
).Pass(),
228 message_loop_
.task_runner(), message_loop_
.task_runner(),
229 message_loop_
.task_runner());
230 encoder_
.reset(new H264VideoToolboxEncoder(
231 cast_environment_
, video_sender_config_
,
232 base::Bind(&SaveOperationalStatus
, &operational_status_
)));
233 message_loop_
.RunUntilIdle();
234 EXPECT_EQ(STATUS_INITIALIZED
, operational_status_
);
237 void TearDown() final
{
239 message_loop_
.RunUntilIdle();
240 power_monitor_
.reset();
243 void AdvanceClockAndVideoFrameTimestamp() {
244 clock_
->Advance(base::TimeDelta::FromMilliseconds(33));
245 frame_
->set_timestamp(frame_
->timestamp() +
246 base::TimeDelta::FromMilliseconds(33));
249 static void SetUpTestCase() {
250 // Reusable test data.
251 video_sender_config_
= GetDefaultVideoSenderConfig();
252 video_sender_config_
.codec
= CODEC_VIDEO_H264
;
253 const gfx::Size
size(kVideoWidth
, kVideoHeight
);
254 frame_
= media::VideoFrame::CreateFrame(
255 PIXEL_FORMAT_I420
, size
, gfx::Rect(size
), size
, base::TimeDelta());
256 PopulateVideoFrame(frame_
.get(), 123);
259 static void TearDownTestCase() { frame_
= nullptr; }
261 static scoped_refptr
<media::VideoFrame
> frame_
;
262 static VideoSenderConfig video_sender_config_
;
264 base::SimpleTestTickClock
* clock_
; // Owned by CastEnvironment.
265 base::MessageLoop message_loop_
;
266 scoped_refptr
<CastEnvironment
> cast_environment_
;
267 scoped_ptr
<VideoEncoder
> encoder_
;
268 OperationalStatus operational_status_
;
269 TestPowerSource
* power_source_
; // Owned by the power monitor.
270 scoped_ptr
<base::PowerMonitor
> power_monitor_
;
273 DISALLOW_COPY_AND_ASSIGN(H264VideoToolboxEncoderTest
);
277 scoped_refptr
<media::VideoFrame
> H264VideoToolboxEncoderTest::frame_
;
278 VideoSenderConfig
H264VideoToolboxEncoderTest::video_sender_config_
;
280 TEST_F(H264VideoToolboxEncoderTest
, CheckFrameMetadataSequence
) {
281 scoped_refptr
<MetadataRecorder
> metadata_recorder(new MetadataRecorder());
282 VideoEncoder::FrameEncodedCallback cb
= base::Bind(
283 &MetadataRecorder::CompareFrameWithExpected
, metadata_recorder
.get());
285 metadata_recorder
->PushExpectation(
286 0, 0, TimeDeltaToRtpDelta(frame_
->timestamp(), kVideoFrequency
),
288 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
289 message_loop_
.RunUntilIdle();
291 for (uint32 frame_id
= 1; frame_id
< 10; ++frame_id
) {
292 AdvanceClockAndVideoFrameTimestamp();
293 metadata_recorder
->PushExpectation(
294 frame_id
, frame_id
- 1,
295 TimeDeltaToRtpDelta(frame_
->timestamp(), kVideoFrequency
),
297 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
301 message_loop_
.RunUntilIdle();
303 EXPECT_EQ(10, metadata_recorder
->count_frames_delivered());
306 #if defined(USE_PROPRIETARY_CODECS)
307 TEST_F(H264VideoToolboxEncoderTest
, CheckFramesAreDecodable
) {
308 VideoDecoderConfig
config(kCodecH264
, H264PROFILE_MAIN
, frame_
->format(),
309 COLOR_SPACE_UNSPECIFIED
, frame_
->coded_size(),
310 frame_
->visible_rect(), frame_
->natural_size(),
312 scoped_refptr
<EndToEndFrameChecker
> checker(new EndToEndFrameChecker(config
));
314 VideoEncoder::FrameEncodedCallback cb
=
315 base::Bind(&EndToEndFrameChecker::EncodeDone
, checker
.get());
316 for (uint32 frame_id
= 0; frame_id
< 6; ++frame_id
) {
317 checker
->PushExpectation(frame_
);
318 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
319 AdvanceClockAndVideoFrameTimestamp();
323 message_loop_
.RunUntilIdle();
325 EXPECT_EQ(5, checker
->count_frames_checked());
329 TEST_F(H264VideoToolboxEncoderTest
, CheckVideoFrameFactory
) {
330 auto video_frame_factory
= encoder_
->CreateVideoFrameFactory();
331 ASSERT_TRUE(video_frame_factory
.get());
332 // The first call to |MaybeCreateFrame| will return null but post a task to
333 // the encoder to initialize for the specified frame size. We then drain the
334 // message loop. After that, the encoder should have initialized and we
335 // request a frame again.
336 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
337 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
338 message_loop_
.RunUntilIdle();
339 CreateFrameAndMemsetPlane(video_frame_factory
.get());
342 TEST_F(H264VideoToolboxEncoderTest
, CheckPowerMonitoring
) {
343 // Encode a frame, suspend, encode a frame, resume, encode a frame.
345 VideoEncoder::FrameEncodedCallback cb
= base::Bind(&NoopFrameEncodedCallback
);
346 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
347 power_source_
->GenerateSuspendEvent();
348 EXPECT_FALSE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
349 power_source_
->GenerateResumeEvent();
350 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
353 TEST_F(H264VideoToolboxEncoderTest
, CheckPowerMonitoringNoInitialFrame
) {
354 // Suspend, encode a frame, resume, encode a frame.
356 VideoEncoder::FrameEncodedCallback cb
= base::Bind(&NoopFrameEncodedCallback
);
357 power_source_
->GenerateSuspendEvent();
358 EXPECT_FALSE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
359 power_source_
->GenerateResumeEvent();
360 EXPECT_TRUE(encoder_
->EncodeVideoFrame(frame_
, clock_
->NowTicks(), cb
));
363 TEST_F(H264VideoToolboxEncoderTest
, CheckPowerMonitoringVideoFrameFactory
) {
364 VideoEncoder::FrameEncodedCallback cb
= base::Bind(&NoopFrameEncodedCallback
);
365 auto video_frame_factory
= encoder_
->CreateVideoFrameFactory();
366 ASSERT_TRUE(video_frame_factory
.get());
368 // The first call to |MaybeCreateFrame| will return null but post a task to
369 // the encoder to initialize for the specified frame size. We then drain the
370 // message loop. After that, the encoder should have initialized and we
371 // request a frame again.
372 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
373 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
374 message_loop_
.RunUntilIdle();
375 CreateFrameAndMemsetPlane(video_frame_factory
.get());
377 // After a power suspension, the factory should not produce frames.
378 power_source_
->GenerateSuspendEvent();
380 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
381 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
382 message_loop_
.RunUntilIdle();
383 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
384 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
386 // After a power resume event, the factory should produce frames right away
387 // because the encoder re-initializes on its own.
388 power_source_
->GenerateResumeEvent();
389 CreateFrameAndMemsetPlane(video_frame_factory
.get());
392 TEST_F(H264VideoToolboxEncoderTest
,
393 CheckPowerMonitoringVideoFrameFactoryNoInitialFrame
) {
394 VideoEncoder::FrameEncodedCallback cb
= base::Bind(&NoopFrameEncodedCallback
);
395 auto video_frame_factory
= encoder_
->CreateVideoFrameFactory();
396 ASSERT_TRUE(video_frame_factory
.get());
398 // After a power suspension, the factory should not produce frames.
399 power_source_
->GenerateSuspendEvent();
401 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
402 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
403 message_loop_
.RunUntilIdle();
404 ASSERT_FALSE(video_frame_factory
->MaybeCreateFrame(
405 gfx::Size(kVideoWidth
, kVideoHeight
), base::TimeDelta()));
407 // After a power resume event, the factory should produce frames right away
408 // because the encoder re-initializes on its own.
409 power_source_
->GenerateResumeEvent();
410 CreateFrameAndMemsetPlane(video_frame_factory
.get());