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..5d9e52bee69af436fea4a9dad9578cd56ed22aae 100644 |
--- a/media/gpu/video_encode_accelerator_unittest.cc |
+++ b/media/gpu/video_encode_accelerator_unittest.cc |
@@ -1762,9 +1762,161 @@ void VEAClient::WriteIvfFrameHeader(int frame_index, size_t frame_size) { |
// 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 { |
wuchengli
2016/11/23 14:43:33
There are some boilerplate code in every VEAXxxCli
hywu1
2016/11/24 06:01:29
Done.
|
+ public: |
Owen Lin
2016/11/24 03:00:52
Did you change the code here on purpose?
I think
hywu1
2016/11/24 06:01:29
Done.
|
+ explicit VEANoInputClient(ClientStateNotification<ClientState>* note); |
+ ~VEANoInputClient() override; |
+ void CreateEncoder(); |
+ 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; |
+ void NotifyError(VideoEncodeAccelerator::Error error) override; |
+ |
+ private: |
+ bool has_encoder() { return encoder_.get(); } |
+ |
+ void SetState(ClientState new_state); |
+ |
+ // 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. |
wuchengli
2016/11/23 14:43:33
Please run git cl format to check the style.
hywu1
2016/11/24 06:01:29
Done.
|
+ 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_; |
+}; |
+ |
+VEANoInputClient::VEANoInputClient(ClientStateNotification<ClientState>* note) |
+ : note_(note), next_output_buffer_id_(0) { |
+ thread_checker_.DetachFromThread(); |
+ } |
+ |
+VEANoInputClient::~VEANoInputClient() { |
+ LOG_ASSERT(!has_encoder()); |
+} |
+ |
+void VEANoInputClient::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); |
+ 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); |
+ SetState(CS_INITIALIZED); |
+ return; |
+ } |
+ } |
+ encoder_.reset(); |
+ LOG(ERROR) << "VideoEncodeAccelerator::Initialize() failed"; |
+ SetState(CS_ERROR); |
+} |
+ |
+void VEANoInputClient::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( |
+ unsigned int input_count, |
+ const gfx::Size& input_coded_size, |
+ size_t output_size) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ SetState(CS_ENCODING); |
+ ASSERT_GT(output_size, 0UL); |
+ |
+ for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { |
+ base::SharedMemory* shm = new base::SharedMemory(); |
+ LOG_ASSERT(shm->CreateAndMapAnonymous(output_size)); |
+ output_shms_.push_back(shm); |
+ FeedEncoderWithOutput(shm, 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), |
+ base::Bind(&VEANoInputClient::SetState, |
+ base::Unretained(this), CS_FINISHED), |
+ false)); |
+ timer_->Reset(); |
+} |
+ |
+void VEANoInputClient::BitstreamBufferReady(int32_t bitstream_buffer_id, |
+ size_t payload_size, |
+ bool key_frame, |
+ base::TimeDelta timestamp) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ SetState(CS_ERROR); |
+} |
+ |
+void VEANoInputClient::NotifyError(VideoEncodeAccelerator::Error error) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ SetState(CS_ERROR); |
+} |
+ |
+void VEANoInputClient::SetState(ClientState new_state) { |
+ DVLOG(4) << "Changing state to " << new_state; |
+ note_->Notify(new_state); |
+} |
+ |
+void VEANoInputClient::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 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 VideoEncodeAccelerator::Client { |
public: |
- explicit VEANoInputClient(ClientStateNotification<ClientState>* note); |
- ~VEANoInputClient() override; |
+ explicit VEACacheLineUnalignedInputClient( |
+ ClientStateNotification<ClientState>* note); |
+ ~VEACacheLineUnalignedInputClient() override; |
void CreateEncoder(); |
void DestroyEncoder(); |
@@ -1786,6 +1938,9 @@ class VEANoInputClient : public VideoEncodeAccelerator::Client { |
// Provide the encoder with a new output buffer. |
void FeedEncoderWithOutput(base::SharedMemory* shm, size_t output_size); |
+ // Feed the encoder with one input frame. |
+ void FeedEncoderWithOneInput(const gfx::Size& input_coded_size); |
+ |
std::unique_ptr<VideoEncodeAccelerator> encoder_; |
// Used to notify another thread about the state. VEAClient does not own this. |
@@ -1798,44 +1953,44 @@ class VEANoInputClient : public VideoEncodeAccelerator::Client { |
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 default_width_; |
+ const int default_height_; |
+ const int default_bitrate_; |
+ const int default_fps_; |
}; |
-VEANoInputClient::VEANoInputClient(ClientStateNotification<ClientState>* note) |
- : note_(note), next_output_buffer_id_(0) { |
+VEACacheLineUnalignedInputClient::VEACacheLineUnalignedInputClient( |
+ ClientStateNotification<ClientState>* note) |
+ : note_(note), |
+ next_output_buffer_id_(0), |
+ default_width_(368), // divisible by 16 but not 32 |
+ default_height_(368), // divisible by 16 but not 32 |
+ default_bitrate_(200000), |
+ default_fps_(30) { |
thread_checker_.DetachFromThread(); |
} |
-VEANoInputClient::~VEANoInputClient() { |
+VEACacheLineUnalignedInputClient::~VEACacheLineUnalignedInputClient() { |
LOG_ASSERT(!has_encoder()); |
} |
-void VEANoInputClient::CreateEncoder() { |
+void VEACacheLineUnalignedInputClient::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(default_width_, default_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); |
+ default_bitrate_, this)) { |
+ encoder_->RequestEncodingParametersChange(default_bitrate_, default_fps_); |
SetState(CS_INITIALIZED); |
return; |
} |
@@ -1845,16 +2000,15 @@ void VEANoInputClient::CreateEncoder() { |
SetState(CS_ERROR); |
} |
-void VEANoInputClient::DestroyEncoder() { |
+void VEACacheLineUnalignedInputClient::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 VEACacheLineUnalignedInputClient::RequireBitstreamBuffers( |
unsigned int input_count, |
const gfx::Size& input_coded_size, |
size_t output_size) { |
@@ -1868,35 +2022,33 @@ void VEANoInputClient::RequireBitstreamBuffers( |
output_shms_.push_back(shm); |
FeedEncoderWithOutput(shm, 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), |
- base::Bind(&VEANoInputClient::SetState, |
- base::Unretained(this), CS_FINISHED), |
- false)); |
- timer_->Reset(); |
+ FeedEncoderWithOneInput(input_coded_size); |
} |
-void VEANoInputClient::BitstreamBufferReady(int32_t bitstream_buffer_id, |
- size_t payload_size, |
- bool key_frame, |
- base::TimeDelta timestamp) { |
+void VEACacheLineUnalignedInputClient::BitstreamBufferReady( |
+ int32_t bitstream_buffer_id, |
+ size_t payload_size, |
+ bool key_frame, |
+ base::TimeDelta timestamp) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- SetState(CS_ERROR); |
+ // It's enough to encode just one frame |
+ SetState(CS_FINISHED); |
} |
-void VEANoInputClient::NotifyError(VideoEncodeAccelerator::Error error) { |
+void VEACacheLineUnalignedInputClient::NotifyError( |
+ VideoEncodeAccelerator::Error error) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
SetState(CS_ERROR); |
} |
-void VEANoInputClient::SetState(ClientState new_state) { |
+void VEACacheLineUnalignedInputClient::SetState(ClientState new_state) { |
DVLOG(4) << "Changing state to " << new_state; |
note_->Notify(new_state); |
} |
-void VEANoInputClient::FeedEncoderWithOutput(base::SharedMemory* shm, |
- size_t output_size) { |
+void VEACacheLineUnalignedInputClient::FeedEncoderWithOutput( |
+ base::SharedMemory* shm, |
+ size_t output_size) { |
if (!has_encoder()) |
return; |
@@ -1908,6 +2060,32 @@ void VEANoInputClient::FeedEncoderWithOutput(base::SharedMemory* shm, |
encoder_->UseOutputBitstreamBuffer(bitstream_buffer); |
} |
+void VEACacheLineUnalignedInputClient::FeedEncoderWithOneInput( |
+ const gfx::Size& input_coded_size) { |
+ if (!has_encoder()) |
+ return; |
+ |
+ std::vector<char, AlignedAllocator<char, kPlatformBufferAlignment>> |
+ aligned_in_file_data(VideoFrame::AllocationSize(PIXEL_FORMAT_I420, |
+ input_coded_size)); |
+ |
+ uint8_t* frame_data_y = reinterpret_cast<uint8_t*>(&aligned_in_file_data[0]); |
+ uint8_t* frame_data_u = frame_data_y + |
+ VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, input_coded_size).GetArea(); |
+ uint8_t* frame_data_v = frame_data_u + |
+ VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 1, input_coded_size).GetArea(); |
+ |
+ scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData( |
+ PIXEL_FORMAT_I420, 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 / default_fps_)); |
+ |
+ encoder_->Encode(video_frame, false); |
+} |
+ |
// Test parameters: |
// - Number of concurrent encoders. The value takes effect when there is only |
// one input stream; otherwise, one encoder per input stream will be |
@@ -2076,6 +2254,41 @@ TEST(VEANoInputTest, CheckOutput) { |
encoder_thread.Stop(); |
} |
+TEST(VEACacheLineUnalignedInputTest, CheckOutput) { |
+ std::unique_ptr<ClientStateNotification<ClientState>> note( |
+ new ClientStateNotification<ClientState>()); |
+ std::unique_ptr<VEACacheLineUnalignedInputClient> client( |
+ new VEACacheLineUnalignedInputClient(note.get())); |
+ base::Thread encoder_thread("EncoderThread"); |
+ ASSERT_TRUE(encoder_thread.Start()); |
+ |
+ encoder_thread.task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&VEACacheLineUnalignedInputClient::CreateEncoder, |
+ base::Unretained(client.get()))); |
+ |
+ // Encoder must pass through states in this order. |
+ enum ClientState state_transitions[] = {CS_INITIALIZED, CS_ENCODING, |
+ CS_FINISHED}; |
+ |
+ ClientState expected_state, wait_state; |
+ for (const auto& state : state_transitions) { |
+ expected_state = state; |
+ wait_state = note->Wait(); |
+ if (expected_state != wait_state) { |
+ break; |
+ } |
+ } |
+ |
+ encoder_thread.task_runner()->PostTask( |
+ FROM_HERE, base::Bind(&VEACacheLineUnalignedInputClient::DestroyEncoder, |
+ base::Unretained(client.get()))); |
+ |
+ // This ensures all tasks have finished. |
+ encoder_thread.Stop(); |
+ |
+ ASSERT_EQ(expected_state, wait_state); |
+} |
+ |
#elif defined(OS_MACOSX) || defined(OS_WIN) |
INSTANTIATE_TEST_CASE_P( |
SimpleEncode, |