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

Unified Diff: media/gpu/video_encode_accelerator_unittest.cc

Issue 2472923002: Add a test case to make sure no output before getting any input (Closed)
Patch Set: 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 45da3ff52968fed7391297723afc9de12f694273..68d6a43ac09b6b2a3fc507786818a59b2383e3f9 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -829,7 +829,86 @@ void VideoFrameQualityValidator::VerifyOutputFrame(
<< "difference = " << difference << " > decode similarity threshold";
}
-class VEAClient : public VideoEncodeAccelerator::Client {
+class VEAClientBase : public VideoEncodeAccelerator::Client {
+ public:
+ VEAClientBase();
+ ~VEAClientBase() override;
+
+ // VideoDecodeAccelerator::Client implementation.
+ virtual void RequireBitstreamBuffers(unsigned int input_count,
Owen Lin 2016/11/04 03:38:50 There is no need to list these pure virtual functi
henryhsu 2016/11/04 04:15:17 Done.
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) = 0;
+ virtual void BitstreamBufferReady(int32_t bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame,
+ base::TimeDelta timestamp) = 0;
+ virtual void NotifyError(VideoEncodeAccelerator::Error error) = 0;
+
+ protected:
+ bool has_encoder() { return encoder_.get(); }
+
+ std::unique_ptr<VideoEncodeAccelerator> CreateFakeVEA();
Owen Lin 2016/11/04 03:38:50 Why these functions need to be a member of VEAClie
henryhsu 2016/11/04 04:15:17 Hmm...If so, then we don't have VEAClientBase clas
+ std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA();
+ std::unique_ptr<VideoEncodeAccelerator> CreateVaapiVEA();
+ std::unique_ptr<VideoEncodeAccelerator> CreateVTVEA();
+ std::unique_ptr<VideoEncodeAccelerator> CreateMFVEA();
+
+ std::unique_ptr<VideoEncodeAccelerator> encoder_;
+};
+
+VEAClientBase::VEAClientBase() {
Owen Lin 2016/11/04 03:38:51 Please run gl cl format to check style issue.
henryhsu 2016/11/04 04:15:17 Done.
+}
+
+VEAClientBase::~VEAClientBase() {
+ LOG_ASSERT(!has_encoder());
+}
+
+std::unique_ptr<VideoEncodeAccelerator> VEAClientBase::CreateFakeVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+ if (g_fake_encoder) {
+ encoder.reset(new FakeVideoEncodeAccelerator(
+ scoped_refptr<base::SingleThreadTaskRunner>(
+ base::ThreadTaskRunnerHandle::Get())));
+ }
+ return encoder;
+}
+
+std::unique_ptr<VideoEncodeAccelerator> VEAClientBase::CreateV4L2VEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+ scoped_refptr<V4L2Device> device = V4L2Device::Create();
+ if (device)
+ encoder.reset(new V4L2VideoEncodeAccelerator(device));
+#endif
+ return encoder;
+}
+
+std::unique_ptr<VideoEncodeAccelerator> VEAClientBase::CreateVaapiVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ encoder.reset(new VaapiVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
+std::unique_ptr<VideoEncodeAccelerator> VEAClientBase::CreateVTVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_MACOSX)
+ encoder.reset(new VTVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
+std::unique_ptr<VideoEncodeAccelerator> VEAClientBase::CreateMFVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_WIN)
+ MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization();
+ encoder.reset(new MediaFoundationVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
+class VEAClient : public VEAClientBase {
public:
VEAClient(TestStream* test_stream,
ClientStateNotification<ClientState>* note,
@@ -856,17 +935,9 @@ class VEAClient : public VideoEncodeAccelerator::Client {
void NotifyError(VideoEncodeAccelerator::Error error) override;
private:
- bool has_encoder() { return encoder_.get(); }
-
// Return the number of encoded frames per second.
double frames_per_second();
- std::unique_ptr<VideoEncodeAccelerator> CreateFakeVEA();
- std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA();
- std::unique_ptr<VideoEncodeAccelerator> CreateVaapiVEA();
- std::unique_ptr<VideoEncodeAccelerator> CreateVTVEA();
- std::unique_ptr<VideoEncodeAccelerator> CreateMFVEA();
-
void SetState(ClientState new_state);
// Set current stream parameters to given |bitrate| at |framerate|.
@@ -932,7 +1003,6 @@ class VEAClient : public VideoEncodeAccelerator::Client {
void VerifyOutputTimestamp(base::TimeDelta timestamp);
ClientState state_;
- std::unique_ptr<VideoEncodeAccelerator> encoder_;
TestStream* test_stream_;
@@ -1115,52 +1185,6 @@ VEAClient::VEAClient(TestStream* test_stream,
}
VEAClient::~VEAClient() {
- LOG_ASSERT(!has_encoder());
-}
-
-std::unique_ptr<VideoEncodeAccelerator> VEAClient::CreateFakeVEA() {
- std::unique_ptr<VideoEncodeAccelerator> encoder;
- if (g_fake_encoder) {
- encoder.reset(new FakeVideoEncodeAccelerator(
- scoped_refptr<base::SingleThreadTaskRunner>(
- base::ThreadTaskRunnerHandle::Get())));
- }
- return encoder;
-}
-
-std::unique_ptr<VideoEncodeAccelerator> VEAClient::CreateV4L2VEA() {
- std::unique_ptr<VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
- scoped_refptr<V4L2Device> device = V4L2Device::Create();
- if (device)
- encoder.reset(new V4L2VideoEncodeAccelerator(device));
-#endif
- return encoder;
-}
-
-std::unique_ptr<VideoEncodeAccelerator> VEAClient::CreateVaapiVEA() {
- std::unique_ptr<VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
- encoder.reset(new VaapiVideoEncodeAccelerator());
-#endif
- return encoder;
-}
-
-std::unique_ptr<VideoEncodeAccelerator> VEAClient::CreateVTVEA() {
- std::unique_ptr<VideoEncodeAccelerator> encoder;
-#if defined(OS_MACOSX)
- encoder.reset(new VTVideoEncodeAccelerator());
-#endif
- return encoder;
-}
-
-std::unique_ptr<VideoEncodeAccelerator> VEAClient::CreateMFVEA() {
- std::unique_ptr<VideoEncodeAccelerator> encoder;
-#if defined(OS_WIN)
- MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization();
- encoder.reset(new MediaFoundationVideoEncodeAccelerator());
-#endif
- return encoder;
}
void VEAClient::CreateEncoder() {
@@ -1676,6 +1700,144 @@ void VEAClient::WriteIvfFrameHeader(int frame_index, size_t frame_size) {
reinterpret_cast<char*>(&header), sizeof(header)));
}
+// This client is only used to test crbug.com/641600 to make sure the encoder
+// does not return an encoded frame before getting any input.
+class VEANoInputClient : public VEAClientBase {
+ public:
+ VEANoInputClient(ClientStateNotification<ClientState>* note);
Owen Lin 2016/11/04 03:38:50 explicit
henryhsu 2016/11/04 04:15:17 Done.
+ ~VEANoInputClient() = default;
+ 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:
+ void SetState(ClientState new_state);
+
+ // Provide the encoder with a new output buffer.
+ void FeedEncoderWithOutput(base::SharedMemory* shm, size_t output_size);
+
+ ClientState state_;
+
+ // 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_;
+};
+
+VEANoInputClient::VEANoInputClient(ClientStateNotification<ClientState>* note)
+ : state_(CS_CREATED),
+ note_(note),
+ next_output_buffer_id_(0) {
+}
+
+void VEANoInputClient::CreateEncoder() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ LOG_ASSERT(!has_encoder());
+
+ 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(320, 200);
Owen Lin 2016/11/04 03:38:51 How about making them static const variable.
henryhsu 2016/11/04 04:15:17 Done.
+ for (size_t i = 0; i < arraysize(encoders); ++i) {
Owen Lin 2016/11/04 03:38:51 for (const auto& encoder : encoders) { }
henryhsu 2016/11/04 04:15:17 Done.
+ if (!encoders[i])
+ continue;
+ encoder_ = std::move(encoders[i]);
+ if (encoder_->Initialize(kInputFormat, visible_size,
+ VP8PROFILE_ANY,
+ 200000, this)) {
+ encoder_->RequestEncodingParametersChange(200000, 30);
+ 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_.reset(new base::Timer(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(100),
Owen Lin 2016/11/04 03:38:51 Why 100 ms?
henryhsu 2016/11/04 04:15:17 frame rate is usually 30. 100 ms is about 3 frames
Owen Lin 2016/11/04 07:24:26 Acknowledged.
+ 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 " << state_ << "->" << new_state;
+ note_->Notify(new_state);
+ state_ = 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);
+}
+
// 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
@@ -1818,6 +1980,37 @@ 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;
+ std::unique_ptr<VEANoInputClient> client;
+ base::Thread encoder_thread("EncoderThread");
+ ASSERT_TRUE(encoder_thread.Start());
+
+ // Create encoder.
+ note.reset(new ClientStateNotification<ClientState>());
Owen Lin 2016/11/04 03:38:51 why not merge the line with declaration.
henryhsu 2016/11/04 04:15:17 Done.
+ client.reset(new VEANoInputClient(note.get()));
+
+ encoder_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VEANoInputClient::CreateEncoder,
+ base::Unretained(client.get())));
+
+ // All encoders must pass through states in this order.
+ enum ClientState state_transitions[] = {
+ CS_INITIALIZED, CS_ENCODING, CS_FINISHED};
+
+ for (size_t state_no = 0; state_no < arraysize(state_transitions);
Owen Lin 2016/11/04 03:38:51 can we use range based for loop here as well.
henryhsu 2016/11/04 04:15:17 Done.
+ ++state_no) {
+ ASSERT_EQ(note->Wait(), state_transitions[state_no]);
+ }
+
+ encoder_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VEANoInputClient::DestroyEncoder,
+ base::Unretained(client.get())));
+
+ // This ensures all tasks have finished.
+ encoder_thread.Stop();
+}
+
#elif defined(OS_MACOSX) || defined(OS_WIN)
INSTANTIATE_TEST_CASE_P(
SimpleEncode,
« 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