Commit a15357a6 authored by hellner's avatar hellner Committed by Commit bot

Adds fake hardware video encoder.

Adds a fake video encode accelerator (hardware encoder) implementation that can be used for testing (on devices without hardware encoder or missing implementation) and testing the efficiency of an existing hardware encoder.

BUG=440843

Review URL: https://codereview.chromium.org/760963003

Cr-Commit-Position: refs/heads/master@{#312893}
parent 8a398d63
......@@ -20,6 +20,7 @@
#include "media/base/bitstream_buffer.h"
#include "media/base/test_data_util.h"
#include "media/filters/h264_parser.h"
#include "media/video/fake_video_encode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -101,6 +102,11 @@ const unsigned int kMinFramesForBitrateTests = 300;
// Bitrate is only forced for tests that test bitrate.
const char* g_default_in_filename = "bear_320x192_40frames.yuv";
const char* g_default_in_parameters = ":320:192:1:out.h264:200000";
// Enabled by including a --fake_encoder flag to the command line invoking the
// test.
bool g_fake_encoder = false;
// Environment to store test stream data for all test cases.
class VideoEncodeAcceleratorTestEnvironment;
VideoEncodeAcceleratorTestEnvironment* g_env;
......@@ -488,7 +494,9 @@ scoped_ptr<StreamValidator> StreamValidator::Create(
const FrameFoundCallback& frame_cb) {
scoped_ptr<StreamValidator> validator;
if (IsH264(profile)) {
if (g_fake_encoder) {
validator.reset(NULL);
} else if (IsH264(profile)) {
validator.reset(new H264Validator(frame_cb));
} else if (IsVP8(profile)) {
validator.reset(new VP8Validator(frame_cb));
......@@ -529,6 +537,7 @@ class VEAClient : public VideoEncodeAccelerator::Client {
private:
bool has_encoder() { return encoder_.get(); }
scoped_ptr<media::VideoEncodeAccelerator> CreateFakeVEA();
scoped_ptr<media::VideoEncodeAccelerator> CreateV4L2VEA();
scoped_ptr<media::VideoEncodeAccelerator> CreateVaapiVEA();
......@@ -716,7 +725,8 @@ VEAClient::VEAClient(TestStream* test_stream,
test_stream_->requested_profile,
base::Bind(&VEAClient::HandleEncodedFrame, base::Unretained(this)));
CHECK(validator_.get());
CHECK(g_fake_encoder || validator_.get());
if (save_to_file_) {
CHECK(!test_stream_->out_filename.empty());
......@@ -734,6 +744,17 @@ VEAClient::VEAClient(TestStream* test_stream,
VEAClient::~VEAClient() { CHECK(!has_encoder()); }
scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateFakeVEA() {
scoped_ptr<media::VideoEncodeAccelerator> encoder;
if (g_fake_encoder) {
encoder.reset(
new media::FakeVideoEncodeAccelerator(
scoped_refptr<base::SingleThreadTaskRunner>(
base::MessageLoopProxy::current())));
}
return encoder.Pass();
}
scoped_ptr<media::VideoEncodeAccelerator> VEAClient::CreateV4L2VEA() {
scoped_ptr<media::VideoEncodeAccelerator> encoder;
#if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
......@@ -758,6 +779,7 @@ void VEAClient::CreateEncoder() {
CHECK(!has_encoder());
scoped_ptr<media::VideoEncodeAccelerator> encoders[] = {
CreateFakeVEA(),
CreateV4L2VEA(),
CreateVaapiVEA()
};
......@@ -911,7 +933,11 @@ void VEAClient::BitstreamBufferReady(int32 bitstream_buffer_id,
const uint8* stream_ptr = static_cast<const uint8*>(shm->memory());
if (payload_size > 0) {
validator_->ProcessStreamBuffer(stream_ptr, payload_size);
if (validator_) {
validator_->ProcessStreamBuffer(stream_ptr, payload_size);
} else {
HandleEncodedFrame(key_frame);
}
if (save_to_file_) {
if (IsVP8(test_stream_->requested_profile))
......@@ -1352,6 +1378,9 @@ int main(int argc, char** argv) {
if (it->first == "num_frames_to_encode") {
std::string input(it->second.begin(), it->second.end());
CHECK(base::StringToInt(input, &content::g_num_frames_to_encode));
}
if (it->first == "fake_encoder") {
content::g_fake_encoder = true;
continue;
}
if (it->first == "run_at_fps") {
......
......@@ -226,6 +226,8 @@ component("media") {
"video/capture/win/video_capture_device_mf_win.h",
"video/capture/win/video_capture_device_win.cc",
"video/capture/win/video_capture_device_win.h",
"video/fake_video_encode_accelerator.cc",
"video/fake_video_encode_accelerator.h",
"video/h264_poc.cc",
"video/h264_poc.h",
"video/picture.cc",
......
......@@ -301,8 +301,6 @@ test("cast_unittests") {
"test/end2end_unittest.cc",
"test/fake_receiver_time_offset_estimator.cc",
"test/fake_receiver_time_offset_estimator.h",
"test/fake_video_encode_accelerator.cc",
"test/fake_video_encode_accelerator.h",
"test/utility/audio_utility_unittest.cc",
"test/utility/barcode_unittest.cc",
]
......
......@@ -123,8 +123,6 @@
'test/fake_receiver_time_offset_estimator.h',
'test/fake_single_thread_task_runner.cc',
'test/fake_single_thread_task_runner.h',
'test/fake_video_encode_accelerator.cc',
'test/fake_video_encode_accelerator.h',
'test/utility/audio_utility_unittest.cc',
'test/utility/barcode_unittest.cc',
], # source
......@@ -149,8 +147,6 @@
'test/cast_benchmarks.cc',
'test/fake_single_thread_task_runner.cc',
'test/fake_single_thread_task_runner.h',
'test/fake_video_encode_accelerator.cc',
'test/fake_video_encode_accelerator.h',
'test/utility/test_util.cc',
'test/utility/test_util.h',
], # source
......
......@@ -12,8 +12,8 @@
#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 "media/video/fake_video_encode_accelerator.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
......@@ -133,8 +133,7 @@ class ExternalVideoEncoderTest : public ::testing::Test {
task_runner_,
task_runner_);
fake_vea_ = new test::FakeVideoEncodeAccelerator(task_runner_,
&stored_bitrates_);
fake_vea_ = new media::FakeVideoEncodeAccelerator(task_runner_);
scoped_ptr<VideoEncodeAccelerator> fake_vea(fake_vea_);
VEAFactory vea_factory(task_runner_, fake_vea.Pass());
video_encoder_.reset(new ExternalVideoEncoder(
......@@ -156,8 +155,7 @@ class ExternalVideoEncoderTest : public ::testing::Test {
}
base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment.
test::FakeVideoEncodeAccelerator* fake_vea_; // Owned by video_encoder_.
std::vector<uint32> stored_bitrates_;
media::FakeVideoEncodeAccelerator* fake_vea_; // Owned by video_encoder_.
scoped_refptr<TestVideoEncoderCallback> test_video_encoder_callback_;
VideoSenderConfig video_config_;
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
......@@ -194,12 +192,12 @@ TEST_F(ExternalVideoEncoderTest, EncodePattern30fpsRunningOutOfAck) {
video_frame_, testing_clock_->NowTicks(), frame_encoded_callback));
task_runner_->RunTasks();
}
ASSERT_EQ(1u, fake_vea_->stored_bitrates().size());
EXPECT_EQ(2000u, fake_vea_->stored_bitrates()[0]);
// We need to run the task to cleanup the GPU instance.
video_encoder_.reset(NULL);
task_runner_->RunTasks();
ASSERT_EQ(1u, stored_bitrates_.size());
EXPECT_EQ(2000u, stored_bitrates_[0]);
}
TEST_F(ExternalVideoEncoderTest, StreamHeader) {
......@@ -238,9 +236,8 @@ TEST(ExternalVideoEncoderEarlyDestroyTest, DestroyBeforeVEACreatedCallback) {
task_runner,
task_runner));
std::vector<uint32> stored_bitrates;
scoped_ptr<VideoEncodeAccelerator> fake_vea(
new test::FakeVideoEncodeAccelerator(task_runner, &stored_bitrates));
new media::FakeVideoEncodeAccelerator(task_runner));
VEAFactory vea_factory(task_runner, fake_vea.Pass());
scoped_ptr<ExternalVideoEncoder> video_encoder(new ExternalVideoEncoder(
......
......@@ -18,9 +18,9 @@
#include "media/cast/sender/video_frame_factory.h"
#include "media/cast/sender/video_sender.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/default_config.h"
#include "media/cast/test/utility/video_utility.h"
#include "media/video/fake_video_encode_accelerator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -133,7 +133,8 @@ class PeerVideoSender : public VideoSender {
class VideoSenderTest : public ::testing::Test {
protected:
VideoSenderTest() {
VideoSenderTest()
: stored_bitrates_(NULL) {
testing_clock_ = new base::SimpleTestTickClock();
testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_);
......@@ -191,9 +192,9 @@ class VideoSenderTest : public ::testing::Test {
CastInitializationStatus status = STATUS_VIDEO_UNINITIALIZED;
if (external) {
test::FakeVideoEncodeAccelerator* fake_vea =
new test::FakeVideoEncodeAccelerator(
task_runner_, &stored_bitrates_);
media::FakeVideoEncodeAccelerator* fake_vea =
new media::FakeVideoEncodeAccelerator(task_runner_);
stored_bitrates_ = &fake_vea->stored_bitrates();
fake_vea->SetWillInitializationSucceed(expect_init_success);
scoped_ptr<VideoEncodeAccelerator> fake_vea_owner(fake_vea);
video_sender_.reset(
......@@ -253,7 +254,7 @@ class VideoSenderTest : public ::testing::Test {
scoped_ptr<CastTransportSenderImpl> transport_sender_;
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
scoped_ptr<PeerVideoSender> video_sender_;
std::vector<uint32> stored_bitrates_;
const std::vector<uint32>* stored_bitrates_; // Owned by |video_sender_|.
scoped_refptr<CastEnvironment> cast_environment_;
int last_pixel_value_;
base::TimeTicks first_frame_timestamp_;
......@@ -288,7 +289,7 @@ TEST_F(VideoSenderTest, ExternalEncoder) {
// Fixed bitrate is used for external encoder. Bitrate is only once
// to the encoder.
EXPECT_EQ(1u, stored_bitrates_.size());
EXPECT_EQ(1u, stored_bitrates_->size());
video_sender_.reset(NULL);
task_runner_->RunTasks();
}
......
......@@ -574,6 +574,8 @@
'video/capture/win/video_capture_device_mf_win.h',
'video/capture/win/video_capture_device_win.cc',
'video/capture/win/video_capture_device_win.h',
'video/fake_video_encode_accelerator.cc',
'video/fake_video_encode_accelerator.h',
'video/h264_poc.cc',
'video/h264_poc.h',
'video/picture.cc',
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/test/fake_video_encode_accelerator.h"
#include "media/video/fake_video_encode_accelerator.h"
#include "base/bind.h"
#include "base/location.h"
......@@ -10,23 +10,17 @@
#include "base/single_thread_task_runner.h"
namespace media {
namespace cast {
namespace test {
static const unsigned int kMinimumInputCount = 1;
static const size_t kMinimumOutputBufferSize = 123456;
FakeVideoEncodeAccelerator::FakeVideoEncodeAccelerator(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
std::vector<uint32>* stored_bitrates)
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
: task_runner_(task_runner),
stored_bitrates_(stored_bitrates),
client_(NULL),
first_(true),
will_initialization_succeed_(true),
weak_this_factory_(this) {
DCHECK(stored_bitrates_);
}
client_(NULL),
next_frame_is_first_frame_(true),
weak_this_factory_(this) {}
FakeVideoEncodeAccelerator::~FakeVideoEncodeAccelerator() {
weak_this_factory_.InvalidateWeakPtrs();
......@@ -34,22 +28,33 @@ FakeVideoEncodeAccelerator::~FakeVideoEncodeAccelerator() {
std::vector<VideoEncodeAccelerator::SupportedProfile>
FakeVideoEncodeAccelerator::GetSupportedProfiles() {
return std::vector<VideoEncodeAccelerator::SupportedProfile>();
std::vector<VideoEncodeAccelerator::SupportedProfile> profiles;
SupportedProfile profile;
profile.max_resolution.SetSize(1920, 1088);
profile.max_framerate_numerator = 30;
profile.max_framerate_denominator = 1;
profile.profile = media::H264PROFILE_MAIN;
profiles.push_back(profile);
profile.profile = media::VP8PROFILE_ANY;
profiles.push_back(profile);
return profiles;
}
bool FakeVideoEncodeAccelerator::Initialize(
media::VideoFrame::Format input_format,
VideoFrame::Format input_format,
const gfx::Size& input_visible_size,
VideoCodecProfile output_profile,
uint32 initial_bitrate,
Client* client) {
if (!will_initialization_succeed_)
if (!will_initialization_succeed_) {
return false;
client_ = client;
if (output_profile != media::VP8PROFILE_ANY &&
output_profile != media::H264PROFILE_MAIN) {
}
if (output_profile == VIDEO_CODEC_PROFILE_UNKNOWN ||
output_profile > VIDEO_CODEC_PROFILE_MAX) {
return false;
}
client_ = client;
task_runner_->PostTask(
FROM_HERE,
base::Bind(&FakeVideoEncodeAccelerator::DoRequireBitstreamBuffers,
......@@ -60,45 +65,41 @@ bool FakeVideoEncodeAccelerator::Initialize(
return true;
}
void FakeVideoEncodeAccelerator::Encode(const scoped_refptr<VideoFrame>& frame,
bool force_keyframe) {
void FakeVideoEncodeAccelerator::Encode(
const scoped_refptr<VideoFrame>& frame,
bool force_keyframe) {
DCHECK(client_);
DCHECK(!available_buffer_ids_.empty());
// Fake that we have encoded the frame; resulting in using the full output
// buffer.
int32 id = available_buffer_ids_.front();
available_buffer_ids_.pop_front();
bool is_key_fame = force_keyframe;
if (first_) {
is_key_fame = true;
first_ = false;
}
task_runner_->PostTask(
FROM_HERE,
base::Bind(&FakeVideoEncodeAccelerator::DoBitstreamBufferReady,
weak_this_factory_.GetWeakPtr(),
id,
kMinimumOutputBufferSize,
is_key_fame));
queued_frames_.push(force_keyframe);
EncodeTask();
}
void FakeVideoEncodeAccelerator::UseOutputBitstreamBuffer(
const BitstreamBuffer& buffer) {
available_buffer_ids_.push_back(buffer.id());
available_buffers_.push_back(buffer);
EncodeTask();
}
void FakeVideoEncodeAccelerator::RequestEncodingParametersChange(
uint32 bitrate,
uint32 framerate) {
stored_bitrates_->push_back(bitrate);
stored_bitrates_.push_back(bitrate);
}
void FakeVideoEncodeAccelerator::Destroy() { delete this; }
void FakeVideoEncodeAccelerator::SendDummyFrameForTesting(bool key_frame) {
DoBitstreamBufferReady(0, 23, key_frame);
task_runner_->PostTask(
FROM_HERE,
base::Bind(&FakeVideoEncodeAccelerator::DoBitstreamBufferReady,
weak_this_factory_.GetWeakPtr(),
0,
23,
key_frame));
}
void FakeVideoEncodeAccelerator::SetWillInitializationSucceed(
bool will_initialization_succeed) {
will_initialization_succeed_ = will_initialization_succeed;
}
void FakeVideoEncodeAccelerator::DoRequireBitstreamBuffers(
......@@ -109,13 +110,31 @@ void FakeVideoEncodeAccelerator::DoRequireBitstreamBuffers(
input_count, input_coded_size, output_buffer_size);
}
void FakeVideoEncodeAccelerator::EncodeTask() {
while (!queued_frames_.empty() && !available_buffers_.empty()) {
bool force_key_frame = queued_frames_.front();
queued_frames_.pop();
int32 bitstream_buffer_id = available_buffers_.front().id();
available_buffers_.pop_front();
bool key_frame = next_frame_is_first_frame_ || force_key_frame;
next_frame_is_first_frame_ = false;
task_runner_->PostTask(
FROM_HERE,
base::Bind(&FakeVideoEncodeAccelerator::DoBitstreamBufferReady,
weak_this_factory_.GetWeakPtr(),
bitstream_buffer_id,
kMinimumOutputBufferSize,
key_frame));
}
}
void FakeVideoEncodeAccelerator::DoBitstreamBufferReady(
int32 bitstream_buffer_id,
size_t payload_size,
bool key_frame) const {
client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
client_->BitstreamBufferReady(bitstream_buffer_id,
payload_size,
key_frame);
}
} // namespace test
} // namespace cast
} // namespace media
......@@ -2,78 +2,84 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_CAST_TEST_FAKE_MOCK_VIDEO_ENCODE_ACCELERATOR_H_
#define MEDIA_CAST_TEST_FAKE_MOCK_VIDEO_ENCODE_ACCELERATOR_H_
#include "media/video/video_encode_accelerator.h"
#ifndef MEDIA_VIDEO_FAKE_VIDEO_ENCODE_ACCELERATOR_H_
#define MEDIA_VIDEO_FAKE_VIDEO_ENCODE_ACCELERATOR_H_
#include <list>
#include <queue>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/media_export.h"
#include "media/video/video_encode_accelerator.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace media {
namespace cast {
namespace test {
class FakeVideoEncodeAccelerator : public VideoEncodeAccelerator {
class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator {
public:
explicit FakeVideoEncodeAccelerator(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
std::vector<uint32>* stored_bitrates);
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
~FakeVideoEncodeAccelerator() override;
std::vector<VideoEncodeAccelerator::SupportedProfile> GetSupportedProfiles()
override;
bool Initialize(media::VideoFrame::Format input_format,
bool Initialize(VideoFrame::Format input_format,
const gfx::Size& input_visible_size,
VideoCodecProfile output_profile,
uint32 initial_bitrate,
Client* client) override;
void Encode(const scoped_refptr<VideoFrame>& frame,
bool force_keyframe) override;
void UseOutputBitstreamBuffer(const BitstreamBuffer& buffer) override;
void RequestEncodingParametersChange(uint32 bitrate,
uint32 framerate) override;
void Destroy() override;
void SendDummyFrameForTesting(bool key_frame);
void SetWillInitializationSucceed(bool will_initialization_succeed) {
will_initialization_succeed_ = will_initialization_succeed;
const std::vector<uint32>& stored_bitrates() const {
return stored_bitrates_;
}
void SendDummyFrameForTesting(bool key_frame);
void SetWillInitializationSucceed(bool will_initialization_succeed);
private:
void DoRequireBitstreamBuffers(unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_buffer_size) const;
void EncodeTask();
void DoBitstreamBufferReady(int32 bitstream_buffer_id,
size_t payload_size,
bool key_frame) const;
// Our original (constructor) calling message loop used for all tasks.
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::vector<uint32>* const stored_bitrates_;
VideoEncodeAccelerator::Client* client_;
bool first_;
std::vector<uint32> stored_bitrates_;
bool will_initialization_succeed_;
std::list<int32> available_buffer_ids_;
VideoEncodeAccelerator::Client* client_;
// Keeps track of if the current frame is the first encoded frame. This
// is used to force a fake key frame for the first encoded frame.
bool next_frame_is_first_frame_;
// A queue containing the necessary data for incoming frames. The boolean
// represent whether the queued frame should force a key frame.
std::queue<bool> queued_frames_;
// A list of buffers available for putting fake encoded frames in.
std::list<BitstreamBuffer> available_buffers_;
base::WeakPtrFactory<FakeVideoEncodeAccelerator> weak_this_factory_;
DISALLOW_COPY_AND_ASSIGN(FakeVideoEncodeAccelerator);
};
} // namespace test
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_TEST_FAKE_MOCK_VIDEO_ENCODE_ACCELERATOR_H_
#endif // MEDIA_VIDEO_FAKE_VIDEO_ENCODE_ACCELERATOR_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment