// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "media/base/video_frame.h" #include "media/cast/cast_defines.h" #include "media/cast/cast_environment.h" #include "media/cast/sender/external_video_encoder.h" #include "media/cast/test/fake_single_thread_task_runner.h" #include "media/cast/test/fake_video_encode_accelerator.h" #include "media/cast/test/utility/video_utility.h" #include "testing/gmock/include/gmock/gmock.h" namespace media { namespace cast { using testing::_; namespace { void CreateVideoEncodeAccelerator( const scoped_refptr& task_runner, scoped_ptr fake_vea, const ReceiveVideoEncodeAcceleratorCallback& callback) { callback.Run(task_runner, fake_vea.Pass()); } void CreateSharedMemory( size_t size, const ReceiveVideoEncodeMemoryCallback& callback) { scoped_ptr shm(new base::SharedMemory()); if (!shm->CreateAndMapAnonymous(size)) { NOTREACHED(); return; } callback.Run(shm.Pass()); } class TestVideoEncoderCallback : public base::RefCountedThreadSafe { public: TestVideoEncoderCallback() {} void SetExpectedResult(uint32 expected_frame_id, uint32 expected_last_referenced_frame_id, const base::TimeTicks& expected_capture_time) { expected_frame_id_ = expected_frame_id; expected_last_referenced_frame_id_ = expected_last_referenced_frame_id; expected_capture_time_ = expected_capture_time; } void DeliverEncodedVideoFrame( scoped_ptr encoded_frame) { if (expected_frame_id_ == expected_last_referenced_frame_id_) { EXPECT_EQ(EncodedFrame::KEY, encoded_frame->dependency); } else { EXPECT_EQ(EncodedFrame::DEPENDENT, encoded_frame->dependency); } EXPECT_EQ(expected_frame_id_, encoded_frame->frame_id); EXPECT_EQ(expected_last_referenced_frame_id_, encoded_frame->referenced_frame_id); EXPECT_EQ(expected_capture_time_, encoded_frame->reference_time); } protected: virtual ~TestVideoEncoderCallback() {} private: friend class base::RefCountedThreadSafe; bool expected_key_frame_; uint32 expected_frame_id_; uint32 expected_last_referenced_frame_id_; base::TimeTicks expected_capture_time_; DISALLOW_COPY_AND_ASSIGN(TestVideoEncoderCallback); }; } // namespace class ExternalVideoEncoderTest : public ::testing::Test { protected: ExternalVideoEncoderTest() : test_video_encoder_callback_(new TestVideoEncoderCallback()) { video_config_.ssrc = 1; video_config_.incoming_feedback_ssrc = 2; video_config_.rtp_payload_type = 127; video_config_.use_external_encoder = true; video_config_.width = 320; video_config_.height = 240; video_config_.max_bitrate = 5000000; video_config_.min_bitrate = 1000000; video_config_.start_bitrate = 2000000; video_config_.max_qp = 56; video_config_.min_qp = 0; video_config_.max_frame_rate = 30; video_config_.max_number_of_video_buffers_used = 3; video_config_.codec = CODEC_VIDEO_VP8; gfx::Size size(video_config_.width, video_config_.height); video_frame_ = media::VideoFrame::CreateFrame( VideoFrame::I420, size, gfx::Rect(size), size, base::TimeDelta()); PopulateVideoFrame(video_frame_, 123); testing_clock_ = new base::SimpleTestTickClock(); task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_); cast_environment_ = new CastEnvironment(scoped_ptr(testing_clock_).Pass(), task_runner_, task_runner_, task_runner_); fake_vea_ = new test::FakeVideoEncodeAccelerator(task_runner_); scoped_ptr fake_vea(fake_vea_); video_encoder_.reset( new ExternalVideoEncoder(cast_environment_, video_config_, base::Bind(&CreateVideoEncodeAccelerator, task_runner_, base::Passed(&fake_vea)), base::Bind(&CreateSharedMemory))); } virtual ~ExternalVideoEncoderTest() {} base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. test::FakeVideoEncodeAccelerator* fake_vea_; // Owned by video_encoder_. scoped_refptr test_video_encoder_callback_; VideoSenderConfig video_config_; scoped_refptr task_runner_; scoped_ptr video_encoder_; scoped_refptr video_frame_; scoped_refptr cast_environment_; DISALLOW_COPY_AND_ASSIGN(ExternalVideoEncoderTest); }; TEST_F(ExternalVideoEncoderTest, EncodePattern30fpsRunningOutOfAck) { task_runner_->RunTasks(); // Run the initializer on the correct thread. VideoEncoder::FrameEncodedCallback frame_encoded_callback = base::Bind(&TestVideoEncoderCallback::DeliverEncodedVideoFrame, test_video_encoder_callback_.get()); base::TimeTicks capture_time; capture_time += base::TimeDelta::FromMilliseconds(33); test_video_encoder_callback_->SetExpectedResult(0, 0, capture_time); EXPECT_TRUE(video_encoder_->EncodeVideoFrame( video_frame_, capture_time, frame_encoded_callback)); task_runner_->RunTasks(); for (int i = 0; i < 6; ++i) { capture_time += base::TimeDelta::FromMilliseconds(33); test_video_encoder_callback_->SetExpectedResult(i + 1, i, capture_time); EXPECT_TRUE(video_encoder_->EncodeVideoFrame( video_frame_, capture_time, frame_encoded_callback)); task_runner_->RunTasks(); } // We need to run the task to cleanup the GPU instance. video_encoder_.reset(NULL); task_runner_->RunTasks(); } TEST_F(ExternalVideoEncoderTest, StreamHeader) { task_runner_->RunTasks(); // Run the initializer on the correct thread. VideoEncoder::FrameEncodedCallback frame_encoded_callback = base::Bind(&TestVideoEncoderCallback::DeliverEncodedVideoFrame, test_video_encoder_callback_.get()); // Force the FakeVideoEncodeAccelerator to return a dummy non-key frame first. fake_vea_->SendDummyFrameForTesting(false); // Verify the first returned bitstream buffer is still a key frame. base::TimeTicks capture_time; capture_time += base::TimeDelta::FromMilliseconds(33); test_video_encoder_callback_->SetExpectedResult(0, 0, capture_time); EXPECT_TRUE(video_encoder_->EncodeVideoFrame( video_frame_, capture_time, frame_encoded_callback)); task_runner_->RunTasks(); // We need to run the task to cleanup the GPU instance. video_encoder_.reset(NULL); task_runner_->RunTasks(); } } // namespace cast } // namespace media