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

Side by Side Diff: content/common/gpu/omx_video_decode_accelerator_unittest.cc

Issue 7046031: OmxVideoDecodeAcceleratorTest improvements: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 6 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/common/gpu/omx_video_decode_accelerator.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // The bulk of this file is support code; sorry about that. Here's an overview 5 // The bulk of this file is support code; sorry about that. Here's an overview
6 // to hopefully help readers of this code: 6 // to hopefully help readers of this code:
7 // - RenderingHelper is charged with interacting with X11, EGL, and GLES2. 7 // - RenderingHelper is charged with interacting with X11, EGL, and GLES2.
8 // - ClientState is an enum for the state of the decode client used by the test. 8 // - ClientState is an enum for the state of the decode client used by the test.
9 // - ClientStateNotification is a barrier abstraction that allows the test code 9 // - ClientStateNotification is a barrier abstraction that allows the test code
10 // to be written sequentially and wait for the decode client to see certain 10 // to be written sequentially and wait for the decode client to see certain
11 // state transitions. 11 // state transitions.
12 // - EglRenderingVDAClient is a VideoDecodeAccelerator::Client implementation 12 // - EglRenderingVDAClient is a VideoDecodeAccelerator::Client implementation
13 // - Finally actual TEST cases are at the bottom of this file, using the above 13 // - Finally actual TEST cases are at the bottom of this file, using the above
14 // infrastructure. 14 // infrastructure.
15 15
16 #include <fcntl.h>
17 #include <math.h>
18 #include <sys/stat.h>
16 #include <sys/types.h> 19 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 20
20 // Include gtest.h out of order because <X11/X.h> #define's Bool & None, which 21 // Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
21 // gtest uses as struct names (inside a namespace). This means that 22 // gtest uses as struct names (inside a namespace). This means that
22 // #include'ing gtest after anything that pulls in X.h fails to compile. 23 // #include'ing gtest after anything that pulls in X.h fails to compile.
23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
24 25
25 #include "base/at_exit.h" 26 #include "base/at_exit.h"
26 #include "base/file_util.h" 27 #include "base/file_util.h"
27 #include "base/stl_util-inl.h" 28 #include "base/stl_util-inl.h"
28 #include "base/stringize_macros.h" 29 #include "base/stringize_macros.h"
(...skipping 12 matching lines...) Expand all
41 using media::VideoDecodeAccelerator; 42 using media::VideoDecodeAccelerator;
42 43
43 namespace { 44 namespace {
44 45
45 // General-purpose constants for this test. 46 // General-purpose constants for this test.
46 enum { 47 enum {
47 kFrameWidth = 320, 48 kFrameWidth = 320,
48 kFrameHeight = 240, 49 kFrameHeight = 240,
49 }; 50 };
50 51
51 // Helper for managing X11, EGL, and GLES2 resources. Because GL state is 52 // Helper for managing X11, EGL, and GLES2 resources. Xlib is not thread-safe,
52 // thread-specific, all the methods of this class (except for ctor/dtor) CHECK 53 // and GL state is thread-specific, so all the methods of this class (except for
53 // for being run on a single thread. 54 // ctor/dtor) ensure they're being run on a single thread.
54 // 55 //
55 // TODO(fischman): consider moving this into media/ if we can de-dup some of the 56 // TODO(fischman): consider moving this into media/ if we can de-dup some of the
56 // code that ends up getting copy/pasted all over the place (esp. the GL setup 57 // code that ends up getting copy/pasted all over the place (esp. the GL setup
57 // code). 58 // code).
58 class RenderingHelper { 59 class RenderingHelper {
59 public: 60 public:
60 explicit RenderingHelper(); 61 explicit RenderingHelper();
61 ~RenderingHelper(); 62 ~RenderingHelper();
62 63
63 // Initialize all structures to prepare to render to a window of the specified 64 // Initialize all structures to prepare to render to one or more windows of
64 // dimensions. CHECK-fails if any initialization step fails. After this 65 // the specified dimensions. CHECK-fails if any initialization step fails.
65 // returns, texture creation and rendering (swaps) can be requested. 66 // After this returns, texture creation and rendering can be requested. This
66 // This method can be called multiple times, in which case all 67 // method can be called multiple times, in which case all previously-acquired
67 // previously-acquired resources and initializations are discarded. 68 // resources and initializations are discarded. If |suppress_swap_to_display|
68 void Initialize(int width, int height, base::WaitableEvent* done); 69 // then all the usual work is done, except for the final swap of the EGL
70 // surface to the display. This cuts test times over 50% so is worth doing
71 // when testing non-rendering-related aspects.
72 void Initialize(bool suppress_swap_to_display, int num_windows,
73 int width, int height, base::WaitableEvent* done);
69 74
70 // Undo the effects of Initialize() and signal |*done|. 75 // Undo the effects of Initialize() and signal |*done|.
71 void UnInitialize(base::WaitableEvent* done); 76 void UnInitialize(base::WaitableEvent* done);
72 77
73 // Return a newly-created GLES2 texture id. 78 // Return a newly-created GLES2 texture id rendering to a specific window, and
74 GLuint CreateTexture(); 79 // signal |*done|.
80 void CreateTexture(int window_id, GLuint* texture_id,
81 base::WaitableEvent* done);
75 82
76 // Render |texture_id| to the screen. 83 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|).
77 void RenderTexture(GLuint texture_id); 84 void RenderTexture(GLuint texture_id);
78 85
79 EGLDisplay egl_display() { return egl_display_; } 86 EGLDisplay egl_display() { return egl_display_; }
80 EGLContext egl_context() { return egl_context_; } 87 EGLContext egl_context() { return egl_context_; }
81 88
82 private: 89 private:
90 // Zero-out internal state. Helper for ctor & UnInitialize().
91 void Clear();
92
93 bool suppress_swap_to_display_;
83 int width_; 94 int width_;
84 int height_; 95 int height_;
85 Display* x_display_; 96 Display* x_display_;
86 Window x_window_; 97 std::vector<Window> x_windows_;
87 EGLDisplay egl_display_; 98 EGLDisplay egl_display_;
88 EGLContext egl_context_; 99 EGLContext egl_context_;
89 EGLSurface egl_surface_; 100 std::vector<EGLSurface> egl_surfaces_;
90 // Since GL carries per-thread state, we ensure all operations are carried out 101 std::map<GLuint, int> texture_id_to_surface_index_;
91 // on the same thread by remembering where we were Initialized. 102 // We ensure all operations are carried out on the same thread by remembering
103 // where we were Initialized.
92 MessageLoop* message_loop_; 104 MessageLoop* message_loop_;
93 }; 105 };
94 106
95 RenderingHelper::RenderingHelper() { 107 RenderingHelper::RenderingHelper() {
96 memset(this, 0, sizeof(this)); 108 Clear();
97 } 109 }
98 110
99 RenderingHelper::~RenderingHelper() { 111 RenderingHelper::~RenderingHelper() {
100 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor."; 112 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
101 } 113 }
102 114
115 void RenderingHelper::Clear() {
116 suppress_swap_to_display_ = false;
117 width_ = 0;
118 height_ = 0;
119 x_display_ = NULL;
120 x_windows_.clear();
121 egl_display_ = EGL_NO_DISPLAY;
122 egl_context_ = EGL_NO_CONTEXT;
123 egl_surfaces_.clear();
124 texture_id_to_surface_index_.clear();
125 message_loop_ = NULL;
126 }
127
103 // Helper for Shader creation. 128 // Helper for Shader creation.
104 static void CreateShader( 129 static void CreateShader(
105 GLuint program, GLenum type, const char* source, int size) { 130 GLuint program, GLenum type, const char* source, int size) {
106 GLuint shader = glCreateShader(type); 131 GLuint shader = glCreateShader(type);
107 glShaderSource(shader, 1, &source, &size); 132 glShaderSource(shader, 1, &source, &size);
108 glCompileShader(shader); 133 glCompileShader(shader);
109 int result = GL_FALSE; 134 int result = GL_FALSE;
110 glGetShaderiv(shader, GL_COMPILE_STATUS, &result); 135 glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
111 if (!result) { 136 if (!result) {
112 char log[4096]; 137 char log[4096];
113 glGetShaderInfoLog(shader, arraysize(log), NULL, log); 138 glGetShaderInfoLog(shader, arraysize(log), NULL, log);
114 LOG(FATAL) << log; 139 LOG(FATAL) << log;
115 } 140 }
116 glAttachShader(program, shader); 141 glAttachShader(program, shader);
117 glDeleteShader(shader); 142 glDeleteShader(shader);
118 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 143 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
119 } 144 }
120 145
121 void RenderingHelper::Initialize( 146 void RenderingHelper::Initialize(
122 int width, int height, base::WaitableEvent* done) { 147 bool suppress_swap_to_display,
148 int num_windows,
149 int width, int height,
150 base::WaitableEvent* done) {
123 // Use width_ != 0 as a proxy for the class having already been 151 // Use width_ != 0 as a proxy for the class having already been
124 // Initialize()'d, and UnInitialize() before continuing. 152 // Initialize()'d, and UnInitialize() before continuing.
125 if (width_) { 153 if (width_) {
126 base::WaitableEvent done(false, false); 154 base::WaitableEvent done(false, false);
127 UnInitialize(&done); 155 UnInitialize(&done);
128 done.Wait(); 156 done.Wait();
129 } 157 }
130 158
159 suppress_swap_to_display_ = suppress_swap_to_display;
131 CHECK_GT(width, 0); 160 CHECK_GT(width, 0);
132 CHECK_GT(height, 0); 161 CHECK_GT(height, 0);
133 width_ = width; 162 width_ = width;
134 height_ = height; 163 height_ = height;
135 message_loop_ = MessageLoop::current(); 164 message_loop_ = MessageLoop::current();
136 165
137 // X11 initialization. 166 // Per-display X11 & EGL initialization.
138 CHECK(x_display_ = XOpenDisplay(NULL)); 167 CHECK(x_display_ = XOpenDisplay(NULL));
139 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_)); 168 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
140 XSetWindowAttributes window_attributes; 169 XSetWindowAttributes window_attributes;
141 window_attributes.background_pixel = 170 window_attributes.background_pixel =
142 BlackPixel(x_display_, DefaultScreen(x_display_)); 171 BlackPixel(x_display_, DefaultScreen(x_display_));
143 window_attributes.override_redirect = true; 172 window_attributes.override_redirect = true;
144 x_window_ = XCreateWindow(
145 x_display_, DefaultRootWindow(x_display_),
146 100, 100, /* x/y of top-left corner */
147 width_, height_,
148 0 /* border width */,
149 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
150 (CWBackPixel | CWOverrideRedirect), &window_attributes);
151 XStoreName(x_display_, x_window_, "OmxVideoDecodeAcceleratorTest");
152 XSelectInput(x_display_, x_window_, ExposureMask);
153 XMapWindow(x_display_, x_window_);
154 173
155 // EGL initialization.
156 egl_display_ = eglGetDisplay(x_display_); 174 egl_display_ = eglGetDisplay(x_display_);
157 EGLint major; 175 EGLint major;
158 EGLint minor; 176 EGLint minor;
159 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError(); 177 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
160 EGLint rgba8888[] = { 178 static EGLint rgba8888[] = {
161 EGL_RED_SIZE, 8, 179 EGL_RED_SIZE, 8,
162 EGL_GREEN_SIZE, 8, 180 EGL_GREEN_SIZE, 8,
163 EGL_BLUE_SIZE, 8, 181 EGL_BLUE_SIZE, 8,
164 EGL_ALPHA_SIZE, 8, 182 EGL_ALPHA_SIZE, 8,
165 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 183 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
166 EGL_NONE, 184 EGL_NONE,
167 }; 185 };
168
169 EGLConfig egl_config; 186 EGLConfig egl_config;
170 int num_configs; 187 int num_configs;
171 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) 188 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
172 << eglGetError(); 189 << eglGetError();
173 CHECK_GE(num_configs, 1); 190 CHECK_GE(num_configs, 1);
174 egl_surface_ = 191 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
175 eglCreateWindowSurface(egl_display_, egl_config, x_window_, NULL);
176 CHECK_NE(egl_surface_, EGL_NO_SURFACE);
177 EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
178 egl_context_ = eglCreateContext( 192 egl_context_ = eglCreateContext(
179 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); 193 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
180 CHECK(eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_)) 194 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();
181 << eglGetError(); 195
196 // Per-window/surface X11 & EGL initialization.
197 for (int i = 0; i < num_windows; ++i) {
198 // Arrange X windows side by side whimsically.
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 :)
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Done.
199 int top_left_x = (width + 50) * i;
200 int top_left_y = 100 + (i % 2) * 250;
201 Window x_window = XCreateWindow(
202 x_display_, DefaultRootWindow(x_display_),
203 top_left_x, top_left_y, width_, height_,
204 0 /* border width */,
205 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
206 (CWBackPixel | CWOverrideRedirect), &window_attributes);
207 x_windows_.push_back(x_window);
208 XStoreName(x_display_, x_window, "OmxVideoDecodeAcceleratorTest");
209 XSelectInput(x_display_, x_window, ExposureMask);
210 XMapWindow(x_display_, x_window);
211
212 EGLSurface egl_surface =
213 eglCreateWindowSurface(egl_display_, egl_config, x_window, NULL);
214 egl_surfaces_.push_back(egl_surface);
215 CHECK_NE(egl_surface, EGL_NO_SURFACE);
216 CHECK(eglMakeCurrent(egl_display_, egl_surface, egl_surface, egl_context_))
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 What's the reason for this eglMakeCurrent call her
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Without it the shaders fail to compile, presumably
217 << eglGetError();
218 }
182 219
183 // GLES2 initialization. Note: This is pretty much copy/pasted from 220 // GLES2 initialization. Note: This is pretty much copy/pasted from
184 // media/tools/player_x11/gles_video_renderer.cc, with some simplification 221 // media/tools/player_x11/gles_video_renderer.cc, with some simplification
185 // applied. 222 // applied.
186 static const float kVertices[] = 223 static const float kVertices[] =
187 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; 224 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
188 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, }; 225 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
189 static const char kVertexShader[] = STRINGIZE( 226 static const char kVertexShader[] = STRINGIZE(
190 varying vec2 interp_tc; 227 varying vec2 interp_tc;
191 attribute vec4 in_pos; 228 attribute vec4 in_pos;
192 attribute vec2 in_tc; 229 attribute vec2 in_tc;
193 void main() { 230 void main() {
194 interp_tc = in_tc; 231 interp_tc = in_tc;
195 gl_Position = in_pos; 232 gl_Position = in_pos;
196 } 233 }
197 ); 234 );
198 static const char kFragmentShaderEgl[] = STRINGIZE( 235 static const char kFragmentShaderEgl[] = STRINGIZE(
199 precision mediump float; 236 precision mediump float;
200 varying vec2 interp_tc; 237 varying vec2 interp_tc;
201 uniform sampler2D tex; 238 uniform sampler2D tex;
202 void main() { 239 void main() {
203 gl_FragColor = texture2D(tex, interp_tc); 240 gl_FragColor = texture2D(tex, interp_tc);
204 } 241 }
205 ); 242 );
206 GLuint program = glCreateProgram(); 243 GLuint program = glCreateProgram();
207 CreateShader(program, GL_VERTEX_SHADER, kVertexShader, sizeof(kVertexShader)); 244 CreateShader(program, GL_VERTEX_SHADER,
245 kVertexShader, arraysize(kVertexShader));
208 CreateShader(program, GL_FRAGMENT_SHADER, 246 CreateShader(program, GL_FRAGMENT_SHADER,
209 kFragmentShaderEgl, sizeof(kFragmentShaderEgl)); 247 kFragmentShaderEgl, arraysize(kFragmentShaderEgl));
210 glLinkProgram(program); 248 glLinkProgram(program);
211 int result = GL_FALSE; 249 int result = GL_FALSE;
212 glGetProgramiv(program, GL_LINK_STATUS, &result); 250 glGetProgramiv(program, GL_LINK_STATUS, &result);
213 if (!result) { 251 if (!result) {
214 char log[4096]; 252 char log[4096];
215 glGetShaderInfoLog(program, arraysize(log), NULL, log); 253 glGetShaderInfoLog(program, arraysize(log), NULL, log);
216 LOG(FATAL) << log; 254 LOG(FATAL) << log;
217 } 255 }
218 glUseProgram(program); 256 glUseProgram(program);
219 glDeleteProgram(program); 257 glDeleteProgram(program);
220 258
221 glUniform1i(glGetUniformLocation(program, "tex"), 0); 259 glUniform1i(glGetUniformLocation(program, "tex"), 0);
222 int pos_location = glGetAttribLocation(program, "in_pos"); 260 int pos_location = glGetAttribLocation(program, "in_pos");
223 glEnableVertexAttribArray(pos_location); 261 glEnableVertexAttribArray(pos_location);
224 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); 262 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
225 int tc_location = glGetAttribLocation(program, "in_tc"); 263 int tc_location = glGetAttribLocation(program, "in_tc");
226 glEnableVertexAttribArray(tc_location); 264 glEnableVertexAttribArray(tc_location);
227 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, 265 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
228 kTextureCoordsEgl); 266 kTextureCoordsEgl);
267
229 done->Signal(); 268 done->Signal();
230 } 269 }
231 270
232 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { 271 void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
233 CHECK_EQ(MessageLoop::current(), message_loop_); 272 CHECK_EQ(MessageLoop::current(), message_loop_);
234 // Destroy resources acquired in Initialize, in reverse-acquisition order. 273 // Destroy resources acquired in Initialize, in reverse-acquisition order.
235 CHECK(eglMakeCurrent( 274 CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
236 egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 275 EGL_NO_CONTEXT)) << eglGetError();
237 CHECK(eglDestroyContext(egl_display_, egl_context_)); 276 CHECK(eglDestroyContext(egl_display_, egl_context_));
238 CHECK(eglDestroySurface(egl_display_, egl_surface_)); 277 for (size_t i = 0; i < egl_surfaces_.size(); ++i)
278 CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
239 CHECK(eglTerminate(egl_display_)); 279 CHECK(eglTerminate(egl_display_));
240 CHECK(XUnmapWindow(x_display_, x_window_)); 280 for (size_t i = 0; i < x_windows_.size(); ++i) {
241 CHECK(XDestroyWindow(x_display_, x_window_)); 281 CHECK(XUnmapWindow(x_display_, x_windows_[i]));
282 CHECK(XDestroyWindow(x_display_, x_windows_[i]));
283 }
242 // Mimic newly-created object. 284 // Mimic newly-created object.
243 memset(this, 0, sizeof(this)); 285 Clear();
244 done->Signal(); 286 done->Signal();
245 } 287 }
246 288
247 GLuint RenderingHelper::CreateTexture() { 289 void RenderingHelper::CreateTexture(int window_id, GLuint* texture_id,
248 CHECK_EQ(MessageLoop::current(), message_loop_); 290 base::WaitableEvent* done) {
249 GLuint texture_id; 291 if (MessageLoop::current() != message_loop_) {
250 glGenTextures(1, &texture_id); 292 message_loop_->PostTask(
251 glBindTexture(GL_TEXTURE_2D, texture_id); 293 FROM_HERE,
294 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this),
295 window_id, texture_id, done));
296 return;
297 }
298 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
299 egl_surfaces_[window_id], egl_context_))
300 << eglGetError();
301 glGenTextures(1, texture_id);
302 glBindTexture(GL_TEXTURE_2D, *texture_id);
252 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, 303 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA,
253 GL_UNSIGNED_BYTE, NULL); 304 GL_UNSIGNED_BYTE, NULL);
254 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
255 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
256 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 307 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
257 return texture_id; 308 CHECK(texture_id_to_surface_index_.insert(
309 std::make_pair(*texture_id, window_id)).second);
310 done->Signal();
258 } 311 }
259 312
260 void RenderingHelper::RenderTexture(GLuint texture_id) { 313 void RenderingHelper::RenderTexture(GLuint texture_id) {
261 CHECK_EQ(MessageLoop::current(), message_loop_); 314 CHECK_EQ(MessageLoop::current(), message_loop_);
262 glActiveTexture(GL_TEXTURE0); 315 glActiveTexture(GL_TEXTURE0);
263 glBindTexture(GL_TEXTURE_2D, texture_id); 316 glBindTexture(GL_TEXTURE_2D, texture_id);
264 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 317 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
265 DCHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 318 DCHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
266 eglSwapBuffers(egl_display_, egl_surface_); 319 DCHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
320 if (!suppress_swap_to_display_) {
321 int window_id = texture_id_to_surface_index_[texture_id];
322 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
323 egl_surfaces_[window_id], egl_context_))
324 << eglGetError();
325 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]);
326 }
267 DCHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); 327 DCHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
268 } 328 }
269 329
270 // State of the EglRenderingVDAClient below. 330 // State of the EglRenderingVDAClient below.
271 enum ClientState { 331 enum ClientState {
272 CS_CREATED, 332 CS_CREATED,
273 CS_DECODER_SET, 333 CS_DECODER_SET,
274 CS_INITIALIZED, 334 CS_INITIALIZED,
275 CS_FLUSHED, 335 CS_FLUSHED,
276 CS_DONE, 336 CS_DONE,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 pending_states_for_notification_.pop(); 375 pending_states_for_notification_.pop();
316 return ret; 376 return ret;
317 } 377 }
318 378
319 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by 379 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by
320 // the TESTs below. 380 // the TESTs below.
321 class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { 381 class EglRenderingVDAClient : public VideoDecodeAccelerator::Client {
322 public: 382 public:
323 // Doesn't take ownership of |note| or |encoded_data|, which must outlive 383 // Doesn't take ownership of |note| or |encoded_data|, which must outlive
324 // |*this|. 384 // |*this|.
325 EglRenderingVDAClient(ClientStateNotification* note, 385 EglRenderingVDAClient(RenderingHelper* rendering_helper,
326 std::string* encoded_data); 386 int rendering_window_id,
387 ClientStateNotification* note,
388 std::string* encoded_data,
389 int num_NALs_per_decode,
390 bool suppress_swap_to_display);
327 virtual ~EglRenderingVDAClient(); 391 virtual ~EglRenderingVDAClient();
328 392
329 // VideoDecodeAccelerator::Client implementation. 393 // VideoDecodeAccelerator::Client implementation.
330 // The heart of the Client. 394 // The heart of the Client.
331 virtual void ProvidePictureBuffers( 395 virtual void ProvidePictureBuffers(
332 uint32 requested_num_of_buffers, 396 uint32 requested_num_of_buffers,
333 const gfx::Size& dimensions, 397 const gfx::Size& dimensions,
334 VideoDecodeAccelerator::MemoryType type); 398 VideoDecodeAccelerator::MemoryType type);
335 virtual void DismissPictureBuffer(int32 picture_buffer_id); 399 virtual void DismissPictureBuffer(int32 picture_buffer_id);
336 virtual void PictureReady(const media::Picture& picture); 400 virtual void PictureReady(const media::Picture& picture);
337 // Simple state changes. 401 // Simple state changes.
338 virtual void NotifyInitializeDone(); 402 virtual void NotifyInitializeDone();
339 virtual void NotifyEndOfStream(); 403 virtual void NotifyEndOfStream();
340 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id); 404 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id);
341 virtual void NotifyFlushDone(); 405 virtual void NotifyFlushDone();
342 virtual void NotifyAbortDone(); 406 virtual void NotifyAbortDone();
343 virtual void NotifyError(VideoDecodeAccelerator::Error error); 407 virtual void NotifyError(VideoDecodeAccelerator::Error error);
344 408
345 // Doesn't take ownership of |decoder|, which must outlive |*this|. 409 // Doesn't take ownership of |decoder|, which must outlive |*this|.
346 void SetDecoder(VideoDecodeAccelerator* decoder); 410 void SetDecoder(VideoDecodeAccelerator* decoder);
347 411
348 // Simple getters for inspecting the state of the Client. 412 // Simple getters for inspecting the state of the Client.
349 ClientState state() { return state_; } 413 ClientState state() { return state_; }
350 VideoDecodeAccelerator::Error error() { return error_; } 414 VideoDecodeAccelerator::Error error() { return error_; }
351 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } 415 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
352 int num_decoded_frames() { return num_decoded_frames_; } 416 int num_decoded_frames() { return num_decoded_frames_; }
353 MessageLoop* message_loop() { return thread_.message_loop(); } 417 EGLDisplay egl_display() { return rendering_helper_->egl_display(); }
354 EGLDisplay egl_display() { return rendering_helper_.egl_display(); } 418 EGLContext egl_context() { return rendering_helper_->egl_context(); }
355 EGLContext egl_context() { return rendering_helper_.egl_context(); } 419 double frames_per_second();
356 420
357 private: 421 private:
358 void SetState(ClientState new_state) { 422 void SetState(ClientState new_state) {
359 note_->Notify(new_state); 423 note_->Notify(new_state);
360 state_ = new_state; 424 state_ = new_state;
361 } 425 }
362 426
363 // Request decode of the next NALU in the encoded data. 427 // Compute & return in |*end_pos| the end position for the next batch of NALs
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 teeny tiny nit: should all these NALs be NALUs?
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Done.
364 void DecodeNextNALU(); 428 // to ship to the decoder (based on |start_pos| & |num_NALs_per_decode_|).
429 void GetRangeForNextNALs(size_t start_pos, size_t* end_pos);
365 430
431 // Request decode of the next batch of NALUs in the encoded data.
432 void DecodeNextNALUs();
433
434 RenderingHelper* rendering_helper_;
435 int rendering_window_id_;
366 const std::string* encoded_data_; 436 const std::string* encoded_data_;
437 const int num_NALs_per_decode_;
367 size_t encoded_data_next_pos_to_decode_; 438 size_t encoded_data_next_pos_to_decode_;
368 int next_bitstream_buffer_id_; 439 int next_bitstream_buffer_id_;
369 ClientStateNotification* note_; 440 ClientStateNotification* note_;
370 VideoDecodeAccelerator* decoder_; 441 VideoDecodeAccelerator* decoder_;
371 ClientState state_; 442 ClientState state_;
372 VideoDecodeAccelerator::Error error_; 443 VideoDecodeAccelerator::Error error_;
373 int num_decoded_frames_; 444 int num_decoded_frames_;
374 int num_done_bitstream_buffers_; 445 int num_done_bitstream_buffers_;
375 std::map<int, media::GLESBuffer*> picture_buffers_by_id_; 446 std::map<int, media::GLESBuffer*> picture_buffers_by_id_;
376 // Required for Thread to work. Not used otherwise. 447 base::TimeTicks initialize_done_ticks_;
377 base::ShadowingAtExitManager at_exit_manager_; 448 base::TimeTicks last_frame_delivered_ticks_;
378 base::Thread thread_;
379 RenderingHelper rendering_helper_;
380 }; 449 };
381 450
382 EglRenderingVDAClient::EglRenderingVDAClient(ClientStateNotification* note, 451 EglRenderingVDAClient::EglRenderingVDAClient(RenderingHelper* rendering_helper,
383 std::string* encoded_data) 452 int rendering_window_id,
384 : encoded_data_(encoded_data), encoded_data_next_pos_to_decode_(0), 453 ClientStateNotification* note,
385 next_bitstream_buffer_id_(0), note_(note), decoder_(NULL), 454 std::string* encoded_data,
386 state_(CS_CREATED), 455 int num_NALs_per_decode,
456 bool suppress_swap_to_display)
457 : rendering_helper_(rendering_helper),
458 rendering_window_id_(rendering_window_id),
459 encoded_data_(encoded_data), num_NALs_per_decode_(num_NALs_per_decode),
460 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0),
461 note_(note), decoder_(NULL), state_(CS_CREATED),
387 error_(VideoDecodeAccelerator::VIDEODECODERERROR_NONE), 462 error_(VideoDecodeAccelerator::VIDEODECODERERROR_NONE),
388 num_decoded_frames_(0), num_done_bitstream_buffers_(0), 463 num_decoded_frames_(0), num_done_bitstream_buffers_(0) {
389 thread_("EglRenderingVDAClientThread") { 464 CHECK_GT(num_NALs_per_decode, 0);
390 CHECK(thread_.Start());
391 base::WaitableEvent done(false, false);
392 message_loop()->PostTask(
393 FROM_HERE,
394 base::Bind(&RenderingHelper::Initialize,
395 base::Unretained(&rendering_helper_),
396 static_cast<int>(kFrameWidth), static_cast<int>(kFrameHeight),
397 &done));
398 done.Wait();
399 } 465 }
400 466
401 EglRenderingVDAClient::~EglRenderingVDAClient() { 467 EglRenderingVDAClient::~EglRenderingVDAClient() {
402 base::WaitableEvent done(false, false);
403 message_loop()->PostTask(
404 FROM_HERE,
405 base::Bind(&RenderingHelper::UnInitialize,
406 base::Unretained(&rendering_helper_),
407 &done));
408 done.Wait();
409 thread_.Stop();
410 STLDeleteValues(&picture_buffers_by_id_); 468 STLDeleteValues(&picture_buffers_by_id_);
411 SetState(CS_DESTROYED); 469 SetState(CS_DESTROYED);
412 } 470 }
413 471
414 void EglRenderingVDAClient::ProvidePictureBuffers( 472 void EglRenderingVDAClient::ProvidePictureBuffers(
415 uint32 requested_num_of_buffers, 473 uint32 requested_num_of_buffers,
416 const gfx::Size& dimensions, 474 const gfx::Size& dimensions,
417 VideoDecodeAccelerator::MemoryType type) { 475 VideoDecodeAccelerator::MemoryType type) {
418 CHECK_EQ(message_loop(), MessageLoop::current());
419 CHECK_EQ(type, VideoDecodeAccelerator::PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); 476 CHECK_EQ(type, VideoDecodeAccelerator::PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE);
420 std::vector<media::GLESBuffer> buffers; 477 std::vector<media::GLESBuffer> buffers;
421 CHECK_EQ(dimensions.width(), kFrameWidth); 478 CHECK_EQ(dimensions.width(), kFrameWidth);
422 CHECK_EQ(dimensions.height(), kFrameHeight); 479 CHECK_EQ(dimensions.height(), kFrameHeight);
423 480
424 for (uint32 i = 0; i < requested_num_of_buffers; ++i) { 481 for (uint32 i = 0; i < requested_num_of_buffers; ++i) {
425 uint32 id = picture_buffers_by_id_.size(); 482 uint32 id = picture_buffers_by_id_.size();
426 GLuint texture_id = rendering_helper_.CreateTexture(); 483 GLuint texture_id;
484 base::WaitableEvent done(false, false);
485 rendering_helper_->CreateTexture(rendering_window_id_, &texture_id, &done);
486 done.Wait();
427 // TODO(fischman): context_id is always 0. Can it be removed from the API? 487 // TODO(fischman): context_id is always 0. Can it be removed from the API?
428 // (since it's always inferrable from context). 488 // (since it's always inferrable from context).
429 media::GLESBuffer* buffer = 489 media::GLESBuffer* buffer =
430 new media::GLESBuffer(id, dimensions, texture_id, 0 /* context_id */); 490 new media::GLESBuffer(id, dimensions, texture_id, 0 /* context_id */);
431 CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second); 491 CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
432 buffers.push_back(*buffer); 492 buffers.push_back(*buffer);
433 } 493 }
434 decoder_->AssignGLESBuffers(buffers); 494 decoder_->AssignGLESBuffers(buffers);
435 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 495 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
436 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); 496 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
437 } 497 }
438 498
439 void EglRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { 499 void EglRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 Didn't catch this before, but I think you also hav
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Done.
440 CHECK_EQ(message_loop(), MessageLoop::current());
441 delete picture_buffers_by_id_[picture_buffer_id]; 500 delete picture_buffers_by_id_[picture_buffer_id];
442 CHECK_EQ(1U, picture_buffers_by_id_.erase(picture_buffer_id)); 501 CHECK_EQ(1U, picture_buffers_by_id_.erase(picture_buffer_id));
443 } 502 }
444 503
445 void EglRenderingVDAClient::PictureReady(const media::Picture& picture) { 504 void EglRenderingVDAClient::PictureReady(const media::Picture& picture) {
446 CHECK_EQ(message_loop(), MessageLoop::current()); 505 last_frame_delivered_ticks_ = base::TimeTicks::Now();
447 506
448 // Because we feed the decoder one NALU at a time, we can be sure each frame 507 // Because we feed the decoder a limited number of NALUs at a time, we can be
449 // comes from a bitstream buffer numbered at least as high as our current 508 // sure each the bitstream buffer from which a frame comes has a limited
450 // decoded frame's index, and less than the id of the next bitstream buffer 509 // range. Assert that.
451 // we'll send for decoding. Assert that. 510 CHECK_GE((picture.bitstream_buffer_id() + 1) * num_NALs_per_decode_,
452 CHECK_GE(picture.bitstream_buffer_id(), num_decoded_frames_); 511 num_decoded_frames_);
453 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_); 512 CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_);
454 ++num_decoded_frames_; 513 ++num_decoded_frames_;
455 514
456 media::GLESBuffer* gles_buffer = 515 media::GLESBuffer* gles_buffer =
457 picture_buffers_by_id_[picture.picture_buffer_id()]; 516 picture_buffers_by_id_[picture.picture_buffer_id()];
458 CHECK(gles_buffer); 517 CHECK(gles_buffer);
459 rendering_helper_.RenderTexture(gles_buffer->texture_id()); 518 rendering_helper_->RenderTexture(gles_buffer->texture_id());
460 519
461 decoder_->ReusePictureBuffer(picture.picture_buffer_id()); 520 decoder_->ReusePictureBuffer(picture.picture_buffer_id());
462 } 521 }
463 522
464 void EglRenderingVDAClient::NotifyInitializeDone() { 523 void EglRenderingVDAClient::NotifyInitializeDone() {
465 CHECK_EQ(message_loop(), MessageLoop::current());
466 SetState(CS_INITIALIZED); 524 SetState(CS_INITIALIZED);
467 DecodeNextNALU(); 525 initialize_done_ticks_ = base::TimeTicks::Now();
526 DecodeNextNALUs();
468 } 527 }
469 528
470 void EglRenderingVDAClient::NotifyEndOfStream() { 529 void EglRenderingVDAClient::NotifyEndOfStream() {
471 CHECK_EQ(message_loop(), MessageLoop::current());
472 SetState(CS_DONE); 530 SetState(CS_DONE);
473 } 531 }
474 532
475 void EglRenderingVDAClient::NotifyEndOfBitstreamBuffer( 533 void EglRenderingVDAClient::NotifyEndOfBitstreamBuffer(
476 int32 bitstream_buffer_id) { 534 int32 bitstream_buffer_id) {
477 CHECK_EQ(message_loop(), MessageLoop::current());
478 ++num_done_bitstream_buffers_; 535 ++num_done_bitstream_buffers_;
479 DecodeNextNALU(); 536 DecodeNextNALUs();
480 } 537 }
481 538
482 void EglRenderingVDAClient::NotifyFlushDone() { 539 void EglRenderingVDAClient::NotifyFlushDone() {
483 CHECK_EQ(message_loop(), MessageLoop::current());
484 SetState(CS_FLUSHED); 540 SetState(CS_FLUSHED);
485 } 541 }
486 542
487 void EglRenderingVDAClient::NotifyAbortDone() { 543 void EglRenderingVDAClient::NotifyAbortDone() {
488 CHECK_EQ(message_loop(), MessageLoop::current());
489 SetState(CS_ABORTED); 544 SetState(CS_ABORTED);
490 } 545 }
491 546
492 void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { 547 void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) {
493 CHECK_EQ(message_loop(), MessageLoop::current());
494 SetState(CS_ERROR); 548 SetState(CS_ERROR);
495 error_ = error; 549 error_ = error;
496 } 550 }
497 551
498 void EglRenderingVDAClient::SetDecoder(VideoDecodeAccelerator* decoder) { 552 void EglRenderingVDAClient::SetDecoder(VideoDecodeAccelerator* decoder) {
499 decoder_ = decoder; 553 decoder_ = decoder;
500 SetState(CS_DECODER_SET); 554 SetState(CS_DECODER_SET);
501 } 555 }
502 556
503 static bool LookingAtNAL(const std::string& encoded, size_t pos) { 557 static bool LookingAtNAL(const std::string& encoded, size_t pos) {
504 return pos + 3 < encoded.size() && 558 return pos + 3 < encoded.size() &&
505 encoded[pos] == 0 && encoded[pos + 1] == 0 && 559 encoded[pos] == 0 && encoded[pos + 1] == 0 &&
506 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; 560 encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
507 } 561 }
508 562
509 void EglRenderingVDAClient::DecodeNextNALU() { 563 void EglRenderingVDAClient::GetRangeForNextNALs(
564 size_t start_pos, size_t* end_pos) {
565 *end_pos = start_pos;
566 CHECK(LookingAtNAL(*encoded_data_, start_pos));
567 for (int i = 0; i < num_NALs_per_decode_; ++i) {
568 *end_pos += 4;
569 while (*end_pos + 3 < encoded_data_->size() &&
570 !LookingAtNAL(*encoded_data_, *end_pos)) {
571 ++*end_pos;
572 }
573 if (*end_pos + 3 >= encoded_data_->size()) {
574 *end_pos = encoded_data_->size();
575 return;
576 }
577 }
578 }
579
580 void EglRenderingVDAClient::DecodeNextNALUs() {
510 if (encoded_data_next_pos_to_decode_ == encoded_data_->size()) { 581 if (encoded_data_next_pos_to_decode_ == encoded_data_->size()) {
511 decoder_->Flush(); 582 decoder_->Flush();
512 return; 583 return;
513 } 584 }
514 size_t start_pos = encoded_data_next_pos_to_decode_; 585 size_t start_pos = encoded_data_next_pos_to_decode_;
515 CHECK(LookingAtNAL(*encoded_data_, start_pos)); 586 size_t end_pos;
516 size_t end_pos = encoded_data_next_pos_to_decode_ + 4; 587 GetRangeForNextNALs(start_pos, &end_pos);
517 while (end_pos + 3 < encoded_data_->size() &&
518 !LookingAtNAL(*encoded_data_, end_pos)) {
519 ++end_pos;
520 }
521 if (end_pos + 3 >= encoded_data_->size())
522 end_pos = encoded_data_->size();
523 588
524 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and 589 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and
525 // hand it off to the decoder. 590 // hand it off to the decoder.
526 base::SharedMemory shm; 591 base::SharedMemory shm;
527 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos)) 592 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos))
528 << start_pos << ", " << end_pos; 593 << start_pos << ", " << end_pos;
529 memcpy(shm.memory(), encoded_data_->data() + start_pos, end_pos - start_pos); 594 memcpy(shm.memory(), encoded_data_->data() + start_pos, end_pos - start_pos);
530 base::SharedMemoryHandle dup_handle; 595 base::SharedMemoryHandle dup_handle;
531 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle)); 596 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle));
532 media::BitstreamBuffer bitstream_buffer( 597 media::BitstreamBuffer bitstream_buffer(
533 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos); 598 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos);
534 decoder_->Decode(bitstream_buffer); 599 decoder_->Decode(bitstream_buffer);
535 encoded_data_next_pos_to_decode_ = end_pos; 600 encoded_data_next_pos_to_decode_ = end_pos;
536 } 601 }
537 602
603 double EglRenderingVDAClient::frames_per_second() {
604 base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_;
605 CHECK_GT(delta.InSecondsF(), 0);
606 return num_decoded_frames_ / delta.InSecondsF();
607 }
608
609 // Test parameters:
610 // - Number of NALs per Decode() call.
611 // - Number of concurrent decoders.
612 class OmxVideoDecodeAcceleratorTest
613 : public ::testing::TestWithParam<std::pair<int, int> > {
614 };
615
538 // Test the most straightforward case possible: data is decoded from a single 616 // Test the most straightforward case possible: data is decoded from a single
539 // chunk and rendered to the screen. 617 // chunk and rendered to the screen.
540 TEST(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { 618 TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) {
541 logging::SetMinLogLevel(-1); 619 // Can be useful for debugging VLOGs from OVDA.
542 ClientStateNotification note; 620 // logging::SetMinLogLevel(-1);
543 ClientState state; 621
544 // Read in the video data and hand it off to the client for later decoding. 622 // Required for Thread to work. Not used otherwise.
623 base::ShadowingAtExitManager at_exit_manager_;
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 nit: no ending _
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Done.
624
625 const int num_NALs_per_decode = GetParam().first;
626 const size_t num_concurrent_decoders = GetParam().second;
627
628 // Suppress EGL surface swapping in all but one test, to cut down overall test
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 Looks like 2 tests have num_NALs_per_decode == 1?
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Done.
629 // runtime.
630 const bool suppress_swap_to_display = num_NALs_per_decode > 1;
631
632 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL);
633 std::vector<EglRenderingVDAClient*> clients(num_concurrent_decoders, NULL);
634 std::vector<OmxVideoDecodeAccelerator*> decoders(
635 num_concurrent_decoders, NULL);
636 // Read in the video data.
545 std::string data_str; 637 std::string data_str;
546 CHECK(file_util::ReadFileToString(FilePath(std::string("test-25fps.h264")), 638 CHECK(file_util::ReadFileToString(FilePath(std::string("test-25fps.h264")),
547 &data_str)); 639 &data_str));
548 EglRenderingVDAClient client(&note, &data_str);
549 OmxVideoDecodeAccelerator decoder(&client, client.message_loop());
550 client.SetDecoder(&decoder);
551 decoder.SetEglState(client.egl_display(), client.egl_context());
552 ASSERT_EQ((state = note.Wait()), CS_DECODER_SET);
553 640
641 // Initialize the rendering helper.
642 base::Thread rendering_thread("EglRenderingVDAClientThread");
643 rendering_thread.Start();
644 RenderingHelper rendering_helper;
554 645
555 // Configure the decoder. 646 base::WaitableEvent done(false, false);
556 int32 config_array[] = { 647 rendering_thread.message_loop()->PostTask(
557 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_FOURCC, 648 FROM_HERE,
558 media::VIDEOCODECFOURCC_H264, 649 base::Bind(&RenderingHelper::Initialize,
559 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_WIDTH, kFrameWidth, 650 base::Unretained(&rendering_helper),
560 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_HEIGHT, kFrameHeight, 651 suppress_swap_to_display, num_concurrent_decoders,
561 media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT, media::VIDEOCOLORFORMAT_RGBA, 652 static_cast<int>(kFrameWidth), static_cast<int>(kFrameHeight),
562 media::VIDEOATTRIBUTEKEY_TERMINATOR 653 &done));
563 }; 654 done.Wait();
564 std::vector<uint32> config(
565 config_array, config_array + arraysize(config_array));
566 CHECK(decoder.Initialize(config));
567 ASSERT_EQ((state = note.Wait()), CS_INITIALIZED);
568 // InitializeDone kicks off decoding inside the client, so we just need to
569 // wait for Flush.
570 ASSERT_EQ((state = note.Wait()), CS_FLUSHED);
571 655
572 EXPECT_EQ(client.num_decoded_frames(), 25 /* fps */ * 10 /* seconds */); 656 // First kick off all the decoders.
573 // Hard-coded the number of NALUs in the stream. Icky. 657 for (size_t index = 0; index < num_concurrent_decoders; ++index) {
574 EXPECT_EQ(client.num_done_bitstream_buffers(), 258); 658 ClientStateNotification* note = new ClientStateNotification();
575 } 659 notes[index] = note;
660 EglRenderingVDAClient* client = new EglRenderingVDAClient(
661 &rendering_helper, index,
662 note, &data_str, num_NALs_per_decode,
663 suppress_swap_to_display);
664 clients[index] = client;
665 OmxVideoDecodeAccelerator* decoder =
666 new OmxVideoDecodeAccelerator(client, rendering_thread.message_loop());
667 decoders[index] = decoder;
668 client->SetDecoder(decoder);
669 decoder->SetEglState(client->egl_display(), client->egl_context());
670 ASSERT_EQ(note->Wait(), CS_DECODER_SET);
671
672 // Configure the decoder.
673 int32 config_array[] = {
674 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_FOURCC,
675 media::VIDEOCODECFOURCC_H264,
676 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_WIDTH, kFrameWidth,
677 media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_HEIGHT, kFrameHeight,
678 media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT, media::VIDEOCOLORFORMAT_RGBA,
679 media::VIDEOATTRIBUTEKEY_TERMINATOR
680 };
681 std::vector<uint32> config(
682 config_array, config_array + arraysize(config_array));
683 CHECK(decoder->Initialize(config));
684 }
685 // Then wait for all the decodes to finish.
686 for (size_t i = 0; i < num_concurrent_decoders; ++i) {
687 ClientStateNotification* note = notes[i];
688 ASSERT_EQ(note->Wait(), CS_INITIALIZED);
689 // InitializeDone kicks off decoding inside the client, so we just need to
690 // wait for Flush.
691 ASSERT_EQ(note->Wait(), CS_FLUSHED);
692 }
693 // Finally assert that decoding went as expected.
694 for (size_t i = 0; i < num_concurrent_decoders; ++i) {
695 EglRenderingVDAClient* client = clients[i];
696 EXPECT_EQ(client->num_decoded_frames(), 25 /* fps */ * 10 /* seconds */);
697 // Hard-coded the number of NALUs in the stream. Icky.
698 EXPECT_EQ(client->num_done_bitstream_buffers(),
699 ceil(258.0 / num_NALs_per_decode));
700 // These numbers are pulled out of a hat, but seem to be safe with current
701 // hardware.
702 double min_expected_fps = suppress_swap_to_display ? 175 : 50;
703 min_expected_fps /= num_concurrent_decoders;
704 LOG(INFO) << "Decoder " << i << " fps: " << client->frames_per_second();
705 EXPECT_GT(client->frames_per_second(), min_expected_fps);
706 }
707 STLDeleteElements(&decoders);
708 STLDeleteElements(&clients);
709 STLDeleteElements(&notes);
710
711 rendering_thread.message_loop()->PostTask(
712 FROM_HERE,
713 base::Bind(&RenderingHelper::UnInitialize,
714 base::Unretained(&rendering_helper),
715 &done));
716 done.Wait();
717 rendering_thread.Stop();
718 };
719
720 // TODO(fischman): using 16 and higher below breaks decode - visual artifacts
721 // are introduced as well as spurious frames are delivered (more pictures are
722 // returned than NALUs are fed to the decoder). Increase the "15" below when
723 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is fixed.
724 INSTANTIATE_TEST_CASE_P(
725 DecodeVariations, OmxVideoDecodeAcceleratorTest,
726 ::testing::Values(
727 std::make_pair(1, 1), std::make_pair(1, 3), std::make_pair(2, 1),
728 std::make_pair(3, 1), std::make_pair(5, 1), std::make_pair(8, 1),
729 std::make_pair(15, 1)));
576 730
577 // TODO(fischman, vrk): add more tests! In particular: 731 // TODO(fischman, vrk): add more tests! In particular:
578 // - Test that chunking Decode() calls differently works. 732 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder.
579 // - Test for memory leaks (valgrind) 733 // - Test for memory leaks (valgrind)
580 // - Test decode speed. Ideally we can beat 60fps esp on simple test.mp4.
581 // - Test alternate configurations 734 // - Test alternate configurations
582 // - Test failure conditions. 735 // - Test failure conditions.
583 // - Test multiple decodes; sequentially & concurrently.
vrk (LEFT CHROMIUM) 2011/06/09 20:36:11 In what way did you want to test decodes sequentia
Ami GONE FROM CHROMIUM 2011/06/09 23:22:26 Play one stream, then play another, with the same
584 // - Test frame size changes mid-stream 736 // - Test frame size changes mid-stream
585 737
586 } // namespace 738 } // namespace
OLDNEW
« no previous file with comments | « content/common/gpu/omx_video_decode_accelerator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698