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

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: address comments 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..ce4984db5ee82412fe1213eef96f3e571f2cd95f 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -438,6 +438,51 @@ static void ParseAndReadTestStreamData(const base::FilePath::StringType& data,
}
}
+static std::unique_ptr<VideoEncodeAccelerator> CreateFakeVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+ if (g_fake_encoder) {
+ encoder.reset(new FakeVideoEncodeAccelerator(
+ scoped_refptr<base::SingleThreadTaskRunner>(
+ base::ThreadTaskRunnerHandle::Get())));
+ }
+ return encoder;
+}
+
+static std::unique_ptr<VideoEncodeAccelerator> 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;
+}
+
+static std::unique_ptr<VideoEncodeAccelerator> CreateVaapiVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
+ encoder.reset(new VaapiVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
+static std::unique_ptr<VideoEncodeAccelerator> CreateVTVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_MACOSX)
+ encoder.reset(new VTVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
+static std::unique_ptr<VideoEncodeAccelerator> CreateMFVEA() {
+ std::unique_ptr<VideoEncodeAccelerator> encoder;
+#if defined(OS_WIN)
+ MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization();
+ encoder.reset(new MediaFoundationVideoEncodeAccelerator());
+#endif
+ return encoder;
+}
+
// Basic test environment shared across multiple test cases. We only need to
// setup it once for all test cases.
// It helps
@@ -861,12 +906,6 @@ class VEAClient : public VideoEncodeAccelerator::Client {
// 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|.
@@ -1118,51 +1157,6 @@ 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() {
DCHECK(thread_checker_.CalledOnValidThread());
LOG_ASSERT(!has_encoder());
@@ -1676,6 +1670,148 @@ 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
wuchengli 2016/11/07 04:25:17 s/test crbug.com/641600 to//
henryhsu 2016/11/07 04:29:55 Done.
+// does not return an encoded frame before getting any input.
+class VEANoInputClient : public VideoEncodeAccelerator::Client {
+ public:
+ explicit VEANoInputClient(ClientStateNotification<ClientState>* note);
+ ~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:
+ 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);
+
+ ClientState state_;
+ 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_;
+};
+
+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());
+
+ const int kDefaultWidth = 320;
+ const int kDefaultHeight = 200;
wuchengli 2016/11/07 04:25:17 s/200/240/
henryhsu 2016/11/07 04:29:55 Done.
+ 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, VP8PROFILE_ANY,
+ 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);
+ }
wuchengli 2016/11/07 04:25:17 add a comment to explain. something like "// Make
henryhsu 2016/11/07 04:29:55 Done.
+ 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 " << state_ << "->" << new_state;
+ note_->Notify(new_state);
+ state_ = new_state;
wuchengli 2016/11/07 04:25:17 Remove state_ because it's not used.
henryhsu 2016/11/07 04:29:55 Done.
+}
+
+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
@@ -1744,10 +1880,9 @@ TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) {
// encoders are created/destroyed, is a single GPU Process ChildThread.
// Moreover, we can't have proper multithreading on X11, so this could cause
// hard to debug issues there, if there were multiple "ChildThreads".
- for (size_t state_no = 0; state_no < arraysize(state_transitions);
- ++state_no) {
+ for (const auto& state : state_transitions) {
for (size_t i = 0; i < num_concurrent_encoders; i++)
- ASSERT_EQ(notes[i]->Wait(), state_transitions[state_no]);
+ ASSERT_EQ(notes[i]->Wait(), state);
}
for (size_t i = 0; i < num_concurrent_encoders; ++i) {
@@ -1818,6 +1953,33 @@ 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())));
+
+ // All encoders 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(note->Wait(), state);
+ }
+
+ 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