Index: content/common/gpu/media/omx_video_decode_accelerator_unittest.cc |
diff --git a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc |
index 6a6d35ca579cd717ee421df6bb05a90a82069a64..b08d0ae2248531b8d2b0d34f8de8714022d49d2c 100644 |
--- a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc |
+++ b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc |
@@ -200,9 +200,9 @@ void RenderingHelper::Initialize( |
// Per-window/surface X11 & EGL initialization. |
for (int i = 0; i < num_windows; ++i) { |
- // Arrange X windows side by side whimsically. |
- int top_left_x = (width + 50) * i; |
- int top_left_y = 100 + (i % 2) * 250; |
+ // Arrange X windows whimsically, with some padding. |
+ int top_left_x = (width + 20) * (i % 4); |
+ int top_left_y = (height + 12) * (i % 3); |
Window x_window = XCreateWindow( |
x_display_, DefaultRootWindow(x_display_), |
top_left_x, top_left_y, width_, height_, |
@@ -421,7 +421,6 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { |
virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id); |
virtual void NotifyFlushDone(); |
virtual void NotifyResetDone(); |
- virtual void NotifyDestroyDone(); |
virtual void NotifyError(VideoDecodeAccelerator::Error error); |
// Simple getters for inspecting the state of the Client. |
@@ -432,7 +431,7 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { |
EGLDisplay egl_display() { return rendering_helper_->egl_display(); } |
EGLContext egl_context() { return rendering_helper_->egl_context(); } |
double frames_per_second(); |
- bool decoder_deleted() { return !decoder_.get(); } |
+ bool decoder_deleted() { return !decoder_; } |
private: |
typedef std::map<int, media::GLESBuffer*> PictureBufferById; |
@@ -456,7 +455,7 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { |
size_t encoded_data_next_pos_to_decode_; |
int next_bitstream_buffer_id_; |
ClientStateNotification* note_; |
- scoped_ptr<OmxVideoDecodeAccelerator> decoder_; |
+ scoped_refptr<OmxVideoDecodeAccelerator> decoder_; |
int delete_decoder_state_; |
ClientState state_; |
VideoDecodeAccelerator::Error error_; |
@@ -485,17 +484,18 @@ EglRenderingVDAClient::EglRenderingVDAClient(RenderingHelper* rendering_helper, |
} |
EglRenderingVDAClient::~EglRenderingVDAClient() { |
- CHECK(!decoder_.get()); |
+ DeleteDecoder(); // Clean up in case of expected error. |
+ CHECK(decoder_deleted()); |
STLDeleteValues(&picture_buffers_by_id_); |
SetState(CS_DESTROYED); |
} |
void EglRenderingVDAClient::CreateDecoder() { |
- CHECK(!decoder_.get()); |
- decoder_.reset(new OmxVideoDecodeAccelerator(this)); |
+ CHECK(decoder_deleted()); |
+ decoder_ = new OmxVideoDecodeAccelerator(this); |
decoder_->SetEglState(egl_display(), egl_context()); |
SetState(CS_DECODER_SET); |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
// Configure the decoder. |
@@ -514,7 +514,7 @@ void EglRenderingVDAClient::ProvidePictureBuffers( |
uint32 requested_num_of_buffers, |
const gfx::Size& dimensions, |
VideoDecodeAccelerator::MemoryType type) { |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
CHECK_EQ(type, VideoDecodeAccelerator::PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); |
std::vector<media::GLESBuffer> buffers; |
@@ -550,7 +550,7 @@ void EglRenderingVDAClient::PictureReady(const media::Picture& picture) { |
// We shouldn't be getting pictures delivered after Reset has completed. |
DCHECK_LT(state_, CS_RESET); |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
last_frame_delivered_ticks_ = base::TimeTicks::Now(); |
@@ -587,25 +587,20 @@ void EglRenderingVDAClient::NotifyEndOfBitstreamBuffer( |
} |
void EglRenderingVDAClient::NotifyFlushDone() { |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
SetState(CS_FLUSHED); |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
decoder_->Reset(); |
} |
void EglRenderingVDAClient::NotifyResetDone() { |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
SetState(CS_RESET); |
- if (!decoder_.get()) |
- return; |
- decoder_->Destroy(); |
-} |
- |
-void EglRenderingVDAClient::NotifyDestroyDone() { |
- SetState(CS_DESTROYED); |
+ if (!decoder_deleted()) |
+ DeleteDecoder(); |
} |
void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { |
@@ -622,12 +617,17 @@ static bool LookingAtNAL(const std::string& encoded, size_t pos) { |
void EglRenderingVDAClient::SetState(ClientState new_state) { |
note_->Notify(new_state); |
state_ = new_state; |
- if (new_state == delete_decoder_state_) |
+ if (new_state == delete_decoder_state_) { |
+ CHECK(!decoder_deleted()); |
DeleteDecoder(); |
+ } |
} |
void EglRenderingVDAClient::DeleteDecoder() { |
- decoder_.reset(); |
+ if (decoder_deleted()) |
+ return; |
+ decoder_->Destroy(); |
+ decoder_ = NULL; |
// Cascade through the rest of the states to simplify test code below. |
for (int i = state_ + 1; i < CS_MAX; ++i) |
SetState(static_cast<ClientState>(i)); |
@@ -651,7 +651,7 @@ void EglRenderingVDAClient::GetRangeForNextNALUs( |
} |
void EglRenderingVDAClient::DecodeNextNALUs() { |
- if (!decoder_.get()) |
+ if (decoder_deleted()) |
return; |
if (encoded_data_next_pos_to_decode_ == encoded_data_->size()) { |
decoder_->Flush(); |
@@ -680,7 +680,8 @@ void EglRenderingVDAClient::DecodeNextNALUs() { |
double EglRenderingVDAClient::frames_per_second() { |
base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_; |
- CHECK_GT(delta.InSecondsF(), 0); |
+ if (delta.InSecondsF() == 0) |
+ return 0; |
return num_decoded_frames_ / delta.InSecondsF(); |
} |
@@ -705,6 +706,10 @@ static void AssertWaitForStateOrDeleted(ClientStateNotification* note, |
<< ", instead of " << expected_state; |
} |
+// We assert the exact number of concurrent decoders we expect to succeed and |
+// that one more than that fails initialization. |
+enum { kMaxSupportedNumConcurrentDecoders = 5 }; |
+ |
// Test the most straightforward case possible: data is decoded from a single |
// chunk and rendered to the screen. |
TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { |
@@ -763,9 +768,19 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { |
ASSERT_EQ(note->Wait(), CS_DECODER_SET); |
} |
// Then wait for all the decodes to finish. |
+ bool saw_init_failure = false; |
for (size_t i = 0; i < num_concurrent_decoders; ++i) { |
ClientStateNotification* note = notes[i]; |
- ASSERT_EQ(note->Wait(), CS_INITIALIZED); |
+ ClientState state = note->Wait(); |
+ if (state != CS_INITIALIZED) { |
+ saw_init_failure = true; |
+ // We expect initialization to fail only when more than the supported |
+ // number of decoders is instantiated. Assert here that something else |
+ // didn't trigger failure. |
+ ASSERT_GT(num_concurrent_decoders, kMaxSupportedNumConcurrentDecoders); |
+ continue; |
+ } |
+ ASSERT_EQ(state, CS_INITIALIZED); |
// InitializeDone kicks off decoding inside the client, so we just need to |
// wait for Flush. |
ASSERT_NO_FATAL_FAILURE( |
@@ -777,8 +792,11 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { |
ASSERT_NO_FATAL_FAILURE( |
AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED)); |
} |
+ ASSERT_EQ(saw_init_failure, |
+ num_concurrent_decoders > kMaxSupportedNumConcurrentDecoders) |
+ << num_concurrent_decoders; |
// Finally assert that decoding went as expected. |
- for (size_t i = 0; i < num_concurrent_decoders; ++i) { |
+ for (size_t i = 0; i < num_concurrent_decoders && !saw_init_failure; ++i) { |
// We can only make performance/correctness assertions if the decoder was |
// allowed to finish. |
if (delete_decoder_state < CS_FLUSHED) |
@@ -813,10 +831,8 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { |
rendering_thread.Stop(); |
}; |
-// TODO(fischman): Remove DISABLED_ prefix when ~OVDA can tear down OMX |
-// synchronously (http://crosbug.com/p/4869). |
INSTANTIATE_TEST_CASE_P( |
- DISABLED_TearDownTiming, OmxVideoDecodeAcceleratorTest, |
+ TearDownTiming, OmxVideoDecodeAcceleratorTest, |
::testing::Values( |
MakeTuple(1, 1, CS_DECODER_SET), MakeTuple(1, 1, CS_INITIALIZED), |
MakeTuple(1, 1, CS_FLUSHED), MakeTuple(1, 1, CS_RESET), |
@@ -824,7 +840,7 @@ INSTANTIATE_TEST_CASE_P( |
MakeTuple(1, 1, static_cast<ClientState>(-10)), |
MakeTuple(1, 1, static_cast<ClientState>(-100)))); |
-// TODO(fischman): using 2nd param of 16 and higher below breaks decode - visual |
+// TODO(fischman): using 1st param of 16 and higher below breaks decode - visual |
// artifacts are introduced as well as spurious frames are delivered (more |
// pictures are returned than NALUs are fed to the decoder). Increase the "15" |
// below when http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 |
@@ -832,10 +848,19 @@ INSTANTIATE_TEST_CASE_P( |
INSTANTIATE_TEST_CASE_P( |
DecodeVariations, OmxVideoDecodeAcceleratorTest, |
::testing::Values( |
- MakeTuple(1, 1, CS_DESTROYED), MakeTuple(1, 3, CS_DESTROYED), |
- MakeTuple(2, 1, CS_DESTROYED), MakeTuple(3, 1, CS_DESTROYED), |
- MakeTuple(5, 1, CS_DESTROYED), MakeTuple(8, 1, CS_DESTROYED), |
- MakeTuple(15, 1, CS_DESTROYED))); |
+ MakeTuple(1, 1, CS_RESET), MakeTuple(1, 3, CS_RESET), |
+ MakeTuple(2, 1, CS_RESET), MakeTuple(3, 1, CS_RESET), |
+ MakeTuple(5, 1, CS_RESET), MakeTuple(8, 1, CS_RESET), |
+ MakeTuple(15, 1, CS_RESET))); |
+ |
+// Find out how many concurrent decoders can go before we exhaust system |
+// resources. |
+INSTANTIATE_TEST_CASE_P( |
+ ResourceExhaustion, OmxVideoDecodeAcceleratorTest, |
+ ::testing::Values( |
+ // +0 hack below to promote enum to int. |
+ MakeTuple(1, kMaxSupportedNumConcurrentDecoders + 0, CS_RESET), |
+ MakeTuple(1, kMaxSupportedNumConcurrentDecoders + 1, CS_RESET))); |
// TODO(fischman, vrk): add more tests! In particular: |
// - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. |