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

Unified Diff: media/gpu/video_encode_accelerator_unittest.cc

Issue 2525563005: VEA unittest: add a test case for cache line-alignment (Closed)
Patch Set: VEA unittest: add a test case for cache line-alignment Created 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/gpu/video_encode_accelerator_unittest.cc
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 4e0dd6ad8ec14bcdf064266d6eb131e9d8a9b3d5..81bb8954270e13f814cab8b405a48e6dd1be53be 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -203,6 +203,8 @@ class AlignedAllocator : public std::allocator<T> {
return std::numeric_limits<size_t>::max() / sizeof(T);
}
};
+typedef std::vector<char, AlignedAllocator<char, kPlatformBufferAlignment>>
+ AlignedCharVector;
struct TestStream {
TestStream()
@@ -225,8 +227,7 @@ struct TestStream {
// A vector used to prepare aligned input buffers of |in_filename|. This
// makes sure starting addresses of YUV planes are aligned to
// kPlatformBufferAlignment bytes.
- std::vector<char, AlignedAllocator<char, kPlatformBufferAlignment>>
- aligned_in_file_data;
+ AlignedCharVector aligned_in_file_data;
// Byte size of a frame of |aligned_in_file_data|.
size_t aligned_buffer_size;
@@ -874,7 +875,40 @@ void VideoFrameQualityValidator::VerifyOutputFrame(
<< "difference = " << difference << " > decode similarity threshold";
}
-class VEAClient : public VideoEncodeAccelerator::Client {
+// Base class for all VEA Clients in this file
+class VEAClientBase : public VideoEncodeAccelerator::Client {
+ public:
+ ~VEAClientBase() {
+ LOG(INFO) << "VEAClientBase destructor";
wuchengli 2016/11/30 04:23:40 This log is not very useful. Remove.
hywu1 2016/11/30 07:06:24 Done.
+ LOG_ASSERT(!has_encoder());
+ }
+ void NotifyError(VideoEncodeAccelerator::Error error) override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ SetState(CS_ERROR);
+ }
+
+ protected:
+ VEAClientBase(ClientStateNotification<ClientState>* note)
+ : note_(note), next_output_buffer_id_(0) {}
+
+ bool has_encoder() { return encoder_.get(); }
+
+ virtual void SetState(ClientState new_state) = 0;
+
+ std::unique_ptr<VideoEncodeAccelerator> encoder_;
+
+ // Used to notify another thread about the state. VEAClientBase does not own
+ // this.
+ ClientStateNotification<ClientState>* note_;
+
+ // All methods of this class should be run on the same thread.
+ base::ThreadChecker thread_checker_;
+
+ ScopedVector<base::SharedMemory> output_shms_;
+ int32_t next_output_buffer_id_;
+};
+
+class VEAClient : public VEAClientBase {
public:
VEAClient(TestStream* test_stream,
ClientStateNotification<ClientState>* note,
@@ -886,7 +920,6 @@ class VEAClient : public VideoEncodeAccelerator::Client {
bool mid_stream_framerate_switch,
bool verify_output,
bool verify_output_timestamp);
- ~VEAClient() override;
void CreateEncoder();
void DestroyEncoder();
@@ -901,19 +934,17 @@ class VEAClient : public VideoEncodeAccelerator::Client {
size_t payload_size,
bool key_frame,
base::TimeDelta timestamp) override;
- void NotifyError(VideoEncodeAccelerator::Error error) override;
private:
void BitstreamBufferReadyOnMainThread(int32_t bitstream_buffer_id,
size_t payload_size,
bool key_frame,
base::TimeDelta timestamp);
- bool has_encoder() { return encoder_.get(); }
// Return the number of encoded frames per second.
double frames_per_second();
- void SetState(ClientState new_state);
+ void SetState(ClientState new_state) override;
// Set current stream parameters to given |bitrate| at |framerate|.
void SetStreamParameters(unsigned int bitrate, unsigned int framerate);
@@ -978,13 +1009,9 @@ class VEAClient : public VideoEncodeAccelerator::Client {
void VerifyOutputTimestamp(base::TimeDelta timestamp);
ClientState state_;
- std::unique_ptr<VideoEncodeAccelerator> encoder_;
TestStream* test_stream_;
- // Used to notify another thread about the state. VEAClient does not own this.
- ClientStateNotification<ClientState>* note_;
-
// Ids assigned to VideoFrames.
std::set<int32_t> inputs_at_client_;
int32_t next_input_id_;
@@ -999,9 +1026,7 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// Ids for output BitstreamBuffers.
typedef std::map<int32_t, base::SharedMemory*> IdToSHM;
- ScopedVector<base::SharedMemory> output_shms_;
IdToSHM output_buffers_at_client_;
- int32_t next_output_buffer_id_;
// Current offset into input stream.
off_t pos_in_input_stream_;
@@ -1069,9 +1094,6 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// The time when the last encoded frame is ready.
base::TimeTicks last_frame_ready_time_;
- // All methods of this class should be run on the same thread.
- base::ThreadChecker thread_checker_;
-
// Requested bitrate in bits per second.
unsigned int requested_bitrate_;
@@ -1122,11 +1144,10 @@ VEAClient::VEAClient(TestStream* test_stream,
bool mid_stream_framerate_switch,
bool verify_output,
bool verify_output_timestamp)
- : state_(CS_CREATED),
+ : VEAClientBase(note),
+ state_(CS_CREATED),
test_stream_(test_stream),
- note_(note),
next_input_id_(0),
- next_output_buffer_id_(0),
pos_in_input_stream_(0),
num_required_input_buffers_(0),
output_buffer_size_(0),
@@ -1180,10 +1201,6 @@ VEAClient::VEAClient(TestStream* test_stream,
thread_checker_.DetachFromThread();
}
-VEAClient::~VEAClient() {
- LOG_ASSERT(!has_encoder());
-}
-
void VEAClient::CreateEncoder() {
DCHECK(thread_checker_.CalledOnValidThread());
LOG_ASSERT(!has_encoder());
@@ -1404,11 +1421,6 @@ void VEAClient::BitstreamBufferReady(int32_t bitstream_buffer_id,
payload_size, key_frame, timestamp));
}
-void VEAClient::NotifyError(VideoEncodeAccelerator::Error error) {
- DCHECK(thread_checker_.CalledOnValidThread());
- SetState(CS_ERROR);
-}
-
void VEAClient::BitstreamBufferReadyOnMainThread(int32_t bitstream_buffer_id,
size_t payload_size,
bool key_frame,
@@ -1759,12 +1771,9 @@ void VEAClient::WriteIvfFrameHeader(int frame_index, size_t frame_size) {
reinterpret_cast<char*>(&header), sizeof(header)));
}
-// This client is only used to make sure the encoder does not return an encoded
-// frame before getting any input.
-class VEANoInputClient : public VideoEncodeAccelerator::Client {
+// Base class for simple VEA Clients
+class SimpleVEAClientBase : public VEAClientBase {
public:
- explicit VEANoInputClient(ClientStateNotification<ClientState>* note);
- ~VEANoInputClient() override;
void CreateEncoder();
void DestroyEncoder();
@@ -1772,70 +1781,53 @@ class VEANoInputClient : public VideoEncodeAccelerator::Client {
void RequireBitstreamBuffers(unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_buffer_size) override;
- void BitstreamBufferReady(int32_t bitstream_buffer_id,
- size_t payload_size,
- bool key_frame,
- base::TimeDelta timestamp) override;
- void NotifyError(VideoEncodeAccelerator::Error error) override;
- private:
- bool has_encoder() { return encoder_.get(); }
+ protected:
+ SimpleVEAClientBase(ClientStateNotification<ClientState>* note,
+ const int width,
+ const int height);
- void SetState(ClientState new_state);
+ void SetState(ClientState new_state) override;
// Provide the encoder with a new output buffer.
void FeedEncoderWithOutput(base::SharedMemory* shm, size_t output_size);
- std::unique_ptr<VideoEncodeAccelerator> encoder_;
-
- // Used to notify another thread about the state. VEAClient does not own this.
- ClientStateNotification<ClientState>* note_;
-
- // All methods of this class should be run on the same thread.
- base::ThreadChecker thread_checker_;
-
- // Ids for output BitstreamBuffers.
- ScopedVector<base::SharedMemory> output_shms_;
- int32_t next_output_buffer_id_;
-
- // The timer used to monitor the encoder doesn't return an output buffer in
- // a period of time.
- std::unique_ptr<base::Timer> timer_;
+ const int width_;
+ const int height_;
+ const int bitrate_;
+ const int fps_;
};
-VEANoInputClient::VEANoInputClient(ClientStateNotification<ClientState>* note)
- : note_(note), next_output_buffer_id_(0) {
+SimpleVEAClientBase::SimpleVEAClientBase(
+ ClientStateNotification<ClientState>* note,
+ const int width,
+ const int height)
+ : VEAClientBase(note),
+ width_(width),
+ height_(height),
+ bitrate_(200000),
+ fps_(30) {
thread_checker_.DetachFromThread();
}
-VEANoInputClient::~VEANoInputClient() {
- LOG_ASSERT(!has_encoder());
-}
-
-void VEANoInputClient::CreateEncoder() {
+void SimpleVEAClientBase::CreateEncoder() {
DCHECK(thread_checker_.CalledOnValidThread());
LOG_ASSERT(!has_encoder());
LOG_ASSERT(g_env->test_streams_.size());
- const int kDefaultWidth = 320;
- const int kDefaultHeight = 240;
- const int kDefaultBitrate = 200000;
- const int kDefaultFps = 30;
-
std::unique_ptr<VideoEncodeAccelerator> encoders[] = {
CreateFakeVEA(), CreateV4L2VEA(), CreateVaapiVEA(), CreateVTVEA(),
CreateMFVEA()};
- // The test case is no input. Use default visible size, bitrate, and fps.
- gfx::Size visible_size(kDefaultWidth, kDefaultHeight);
+ gfx::Size visible_size(width_, height_);
for (auto& encoder : encoders) {
if (!encoder)
continue;
encoder_ = std::move(encoder);
if (encoder_->Initialize(kInputFormat, visible_size,
g_env->test_streams_[0]->requested_profile,
- kDefaultBitrate, this)) {
- encoder_->RequestEncodingParametersChange(kDefaultBitrate, kDefaultFps);
+ bitrate_, this)) {
+ encoder_->RequestEncodingParametersChange(bitrate_, fps_);
SetState(CS_INITIALIZED);
return;
}
@@ -1845,16 +1837,20 @@ void VEANoInputClient::CreateEncoder() {
SetState(CS_ERROR);
}
-void VEANoInputClient::DestroyEncoder() {
+void SimpleVEAClientBase::DestroyEncoder() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!has_encoder())
return;
// Clear the objects that should be destroyed on the same thread as creation.
encoder_.reset();
- timer_.reset();
}
-void VEANoInputClient::RequireBitstreamBuffers(
+void SimpleVEAClientBase::SetState(ClientState new_state) {
+ DVLOG(4) << "Changing state to " << new_state;
+ note_->Notify(new_state);
+}
+
+void SimpleVEAClientBase::RequireBitstreamBuffers(
unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_size) {
@@ -1868,6 +1864,59 @@ void VEANoInputClient::RequireBitstreamBuffers(
output_shms_.push_back(shm);
FeedEncoderWithOutput(shm, output_size);
}
+}
+
+void SimpleVEAClientBase::FeedEncoderWithOutput(base::SharedMemory* shm,
+ size_t output_size) {
+ if (!has_encoder())
+ return;
+
+ base::SharedMemoryHandle dup_handle;
+ LOG_ASSERT(shm->ShareToProcess(base::GetCurrentProcessHandle(), &dup_handle));
+
+ BitstreamBuffer bitstream_buffer(next_output_buffer_id_++, dup_handle,
+ output_size);
+ encoder_->UseOutputBitstreamBuffer(bitstream_buffer);
+}
+
+// This client is only used to make sure the encoder does not return an encoded
+// frame before getting any input.
+class VEANoInputClient : public SimpleVEAClientBase {
+ public:
+ explicit VEANoInputClient(ClientStateNotification<ClientState>* note);
+ void DestroyEncoder();
+
+ // VideoDecodeAccelerator::Client implementation.
+ void RequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) override;
+ void BitstreamBufferReady(int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame,
+ base::TimeDelta timestamp) override;
+
+ private:
+ // The timer used to monitor the encoder doesn't return an output buffer in
+ // a period of time.
+ std::unique_ptr<base::Timer> timer_;
+};
+
+VEANoInputClient::VEANoInputClient(ClientStateNotification<ClientState>* note)
+ : SimpleVEAClientBase(note, 320, 240) {}
+
+void VEANoInputClient::DestroyEncoder() {
+ SimpleVEAClientBase::DestroyEncoder();
+ // Clear the objects that should be destroyed on the same thread as creation.
+ timer_.reset();
+}
+
+void VEANoInputClient::RequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_size) {
+ SimpleVEAClientBase::RequireBitstreamBuffers(input_count, input_coded_size,
+ output_size);
+
// Timer is used to make sure there is no output frame in 100ms.
timer_.reset(new base::Timer(FROM_HERE,
base::TimeDelta::FromMilliseconds(100),
@@ -1885,27 +1934,79 @@ void VEANoInputClient::BitstreamBufferReady(int32_t bitstream_buffer_id,
SetState(CS_ERROR);
}
-void VEANoInputClient::NotifyError(VideoEncodeAccelerator::Error error) {
- DCHECK(thread_checker_.CalledOnValidThread());
- SetState(CS_ERROR);
+// This client is only used to test input frame with the size of U and V planes
+// unaligned to cache line.
+// To have both width and height divisible by 16 but not 32 will make the size
+// of U/V plane (width * height / 4) unaligned to 128-byte cache line.
+class VEACacheLineUnalignedInputClient : public SimpleVEAClientBase {
+ public:
+ explicit VEACacheLineUnalignedInputClient(
+ ClientStateNotification<ClientState>* note);
+
+ // VideoDecodeAccelerator::Client implementation.
+ void RequireBitstreamBuffers(unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) override;
+ void BitstreamBufferReady(int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame,
+ base::TimeDelta timestamp) override;
+
+ private:
+ // Feed the encoder with one input frame.
+ void FeedEncoderWithOneInput(const gfx::Size& input_coded_size);
+};
+
+VEACacheLineUnalignedInputClient::VEACacheLineUnalignedInputClient(
+ ClientStateNotification<ClientState>* note)
+ : SimpleVEAClientBase(note, 368, 368) {
+} // 368 is divisible by 16 but not 32
+
+void VEACacheLineUnalignedInputClient::RequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_size) {
+ SimpleVEAClientBase::RequireBitstreamBuffers(input_count, input_coded_size,
+ output_size);
+
+ FeedEncoderWithOneInput(input_coded_size);
}
-void VEANoInputClient::SetState(ClientState new_state) {
- DVLOG(4) << "Changing state to " << new_state;
- note_->Notify(new_state);
+void VEACacheLineUnalignedInputClient::BitstreamBufferReady(
+ int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame,
+ base::TimeDelta timestamp) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // It's enough to encode just one frame. If plane size is not aligned,
+ // VideoEncodeAccelerator::Encode will fail.
+ SetState(CS_FINISHED);
}
-void VEANoInputClient::FeedEncoderWithOutput(base::SharedMemory* shm,
- size_t output_size) {
+void VEACacheLineUnalignedInputClient::FeedEncoderWithOneInput(
+ const gfx::Size& input_coded_size) {
if (!has_encoder())
return;
- base::SharedMemoryHandle dup_handle;
- LOG_ASSERT(shm->ShareToProcess(base::GetCurrentProcessHandle(), &dup_handle));
+ AlignedCharVector aligned_plane[] = {
+ AlignedCharVector(
+ VideoFrame::PlaneSize(kInputFormat, 0, input_coded_size).GetArea()),
+ AlignedCharVector(
+ VideoFrame::PlaneSize(kInputFormat, 1, input_coded_size).GetArea()),
+ AlignedCharVector(
+ VideoFrame::PlaneSize(kInputFormat, 2, input_coded_size).GetArea())};
+ uint8_t* frame_data_y = reinterpret_cast<uint8_t*>(&aligned_plane[0][0]);
+ uint8_t* frame_data_u = reinterpret_cast<uint8_t*>(&aligned_plane[1][0]);
+ uint8_t* frame_data_v = reinterpret_cast<uint8_t*>(&aligned_plane[2][0]);
- BitstreamBuffer bitstream_buffer(next_output_buffer_id_++, dup_handle,
- output_size);
- encoder_->UseOutputBitstreamBuffer(bitstream_buffer);
+ scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData(
+ kInputFormat, input_coded_size, gfx::Rect(input_coded_size),
+ input_coded_size, input_coded_size.width(), input_coded_size.width() / 2,
+ input_coded_size.width() / 2, frame_data_y, frame_data_u, frame_data_v,
+ base::TimeDelta().FromMilliseconds(base::Time::kMillisecondsPerSecond /
+ fps_));
+
+ encoder_->Encode(video_frame, false);
}
// Test parameters:
@@ -1991,6 +2092,51 @@ TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) {
encoder_thread.Stop();
}
+// Test parameters:
+// - Test type
+// 0: No input test
+// 1: Cache line-unaligned test
+class VideoEncodeAcceleratorSimpleTest : public ::testing::TestWithParam<int> {
+};
+
+template <class TestClient>
+void SimpleTestFunc() {
+ std::unique_ptr<ClientStateNotification<ClientState>> note(
+ new ClientStateNotification<ClientState>());
+ std::unique_ptr<TestClient> client(new TestClient(note.get()));
+ base::Thread encoder_thread("EncoderThread");
+ ASSERT_TRUE(encoder_thread.Start());
+
+ encoder_thread.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TestClient::CreateEncoder, base::Unretained(client.get())));
+
+ // Encoder must pass through states in this order.
+ enum ClientState state_transitions[] = {CS_INITIALIZED, CS_ENCODING,
+ CS_FINISHED};
+
+ for (const auto& state : state_transitions) {
+ EXPECT_EQ(state, note->Wait());
+ }
+
+ encoder_thread.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TestClient::DestroyEncoder, base::Unretained(client.get())));
+
+ // This ensures all tasks have finished.
+ encoder_thread.Stop();
+}
+
+TEST_P(VideoEncodeAcceleratorSimpleTest, TestSimpleEncode) {
+ const int test_type = GetParam();
+ ASSERT_GT(2, test_type) << "Invalid test type=" << test_type;
wuchengli 2016/11/30 04:23:41 s/ASSERT_GT/ASSERT_GE/
hywu1 2016/11/30 07:06:24 Changed to ASSERT_LT
+
+ if (test_type == 0)
+ SimpleTestFunc<VEANoInputClient>();
+ else if (test_type == 1)
+ SimpleTestFunc<VEACacheLineUnalignedInputClient>();
+}
+
#if defined(OS_CHROMEOS)
INSTANTIATE_TEST_CASE_P(
SimpleEncode,
@@ -2049,32 +2195,13 @@ INSTANTIATE_TEST_CASE_P(
::testing::Values(
std::make_tuple(1, false, 0, false, false, false, false, false, true)));
-TEST(VEANoInputTest, CheckOutput) {
- std::unique_ptr<ClientStateNotification<ClientState>> note(
- new ClientStateNotification<ClientState>());
- std::unique_ptr<VEANoInputClient> client(new VEANoInputClient(note.get()));
- base::Thread encoder_thread("EncoderThread");
- ASSERT_TRUE(encoder_thread.Start());
-
- encoder_thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(&VEANoInputClient::CreateEncoder,
- base::Unretained(client.get())));
-
- // Encoder must pass through states in this order.
- enum ClientState state_transitions[] = {CS_INITIALIZED, CS_ENCODING,
- CS_FINISHED};
-
- for (const auto& state : state_transitions) {
- ASSERT_EQ(state, note->Wait());
- }
-
- encoder_thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(&VEANoInputClient::DestroyEncoder,
- base::Unretained(client.get())));
+INSTANTIATE_TEST_CASE_P(NoInputTest,
+ VideoEncodeAcceleratorSimpleTest,
+ ::testing::Values(0));
- // This ensures all tasks have finished.
- encoder_thread.Stop();
-}
+INSTANTIATE_TEST_CASE_P(CacheLineUnalignedInputTest,
+ VideoEncodeAcceleratorSimpleTest,
+ ::testing::Values(1));
#elif defined(OS_MACOSX) || defined(OS_WIN)
INSTANTIATE_TEST_CASE_P(
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698