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

Side by Side Diff: content/common/gpu/media/video_decode_accelerator_unittest.cc

Issue 8510039: Initial implementation of the DXVA 2.0 H.264 hardware decoder for pepper for Windows. The decodin... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years 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
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> 16 #include <fcntl.h>
17 #include <math.h> 17 #include <math.h>
18 #include <sys/stat.h> 18 #include <sys/stat.h>
19 #include <sys/types.h> 19 #include <sys/types.h>
20 20
21 // 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
22 // gtest uses as struct names (inside a namespace). This means that 22 // gtest uses as struct names (inside a namespace). This means that
23 // #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.
24 // This is http://code.google.com/p/googletest/issues/detail?id=371 24 // This is http://code.google.com/p/googletest/issues/detail?id=371
25 #include "testing/gtest/include/gtest/gtest.h"
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 See the comment above this line for why it's inclu
ananta 2011/12/17 00:40:25 Sorry about that. Restored. I did this to fix a li
26
27 #include "base/at_exit.h" 25 #include "base/at_exit.h"
28 #include "base/bind.h" 26 #include "base/bind.h"
29 #include "base/command_line.h" 27 #include "base/command_line.h"
30 #include "base/file_util.h" 28 #include "base/file_util.h"
29 #include "base/process_util.h"
31 #include "base/stl_util.h" 30 #include "base/stl_util.h"
32 #include "base/string_number_conversions.h" 31 #include "base/string_number_conversions.h"
33 #include "base/string_split.h" 32 #include "base/string_split.h"
34 #include "base/stringize_macros.h" 33 #include "base/stringize_macros.h"
35 #include "base/synchronization/condition_variable.h" 34 #include "base/synchronization/condition_variable.h"
36 #include "base/synchronization/lock.h" 35 #include "base/synchronization/lock.h"
37 #include "base/synchronization/waitable_event.h" 36 #include "base/synchronization/waitable_event.h"
38 #include "base/threading/thread.h" 37 #include "base/threading/thread.h"
38 #include "base/utf_string_conversions.h"
39
40 #if (defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)) || defined(OS_WIN)
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 If you negate this up here & #error out, then afte
ananta 2011/12/17 00:40:25 Done.
41 #if defined(OS_WIN)
42 #include "content/common/gpu/media/dxva_video_decode_accelerator.h"
43 #else // OS_WIN
39 #include "content/common/gpu/media/omx_video_decode_accelerator.h" 44 #include "content/common/gpu/media/omx_video_decode_accelerator.h"
45 #endif // defined(OS_WIN)
46 #endif // (defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)) || defined(OS_WIN)
47
48 #include "testing/gtest/include/gtest/gtest.h"
40 #include "third_party/angle/include/EGL/egl.h" 49 #include "third_party/angle/include/EGL/egl.h"
41 #include "third_party/angle/include/GLES2/gl2.h" 50 #include "third_party/angle/include/GLES2/gl2.h"
42 51
43 #if !defined(OS_CHROMEOS) || !defined(ARCH_CPU_ARMEL) 52 #if !defined(OS_CHROMEOS) && !defined(ARCH_CPU_ARMEL) && !defined(OS_WIN)
44 #error This test (and OmxVideoDecodeAccelerator) are only supported on cros/ARM! 53 #error The VideoAccelerator tests are only supported on cros/ARM/Windows.
45 #endif 54 #endif
46 55
47 using media::VideoDecodeAccelerator; 56 using media::VideoDecodeAccelerator;
48 57
49 namespace { 58 namespace {
50 59
51 // Values optionally filled in from flags; see main() below. 60 // Values optionally filled in from flags; see main() below.
52 // The syntax of this variable is: 61 // The syntax of this variable is:
53 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender 62 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender
54 // where only the first field is required. Value details: 63 // where only the first field is required. Value details:
55 // - |filename| must be an h264 Annex B (NAL) stream. 64 // - |filename| must be an h264 Annex B (NAL) stream.
56 // - |width| and |height| are in pixels. 65 // - |width| and |height| are in pixels.
57 // - |numframes| is the number of picture frames in the file. 66 // - |numframes| is the number of picture frames in the file.
58 // - |numNALUs| is the number of NAL units in the stream. 67 // - |numNALUs| is the number of NAL units in the stream.
59 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds 68 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds
60 // expected to be achieved with and without rendering to the screen, resp. 69 // expected to be achieved with and without rendering to the screen, resp.
61 // (the latter tests just decode speed). 70 // (the latter tests just decode speed).
62 // - |profile| is the media::H264Profile set during Initialization. 71 // - |profile| is the media::H264Profile set during Initialization.
63 // An empty value for a numeric field means "ignore". 72 // An empty value for a numeric field means "ignore".
64 const char* test_video_data = "test-25fps.h264:320:240:250:258:50:175:1"; 73 std::string test_video_data = "test-25fps.h264:320:240:250:258:50:175:1";
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 style guide prohibits global vars of class type, w
ananta 2011/12/17 00:40:25 Restored.
65 74
66 // Parse |data| into its constituent parts and set the various output fields 75 // Parse |data| into its constituent parts and set the various output fields
67 // accordingly. CHECK-fails on unexpected or missing required data. 76 // accordingly. CHECK-fails on unexpected or missing required data.
68 // Unspecified optional fields are set to -1. 77 // Unspecified optional fields are set to -1.
69 void ParseTestVideoData(std::string data, 78 void ParseTestVideoData(std::string data,
70 std::string* file_name, 79 std::string* file_name,
71 int* width, int* height, 80 int* width, int* height,
72 int* num_frames, 81 int* num_frames,
73 int* num_NALUs, 82 int* num_NALUs,
74 int* min_fps_render, 83 int* min_fps_render,
(...skipping 16 matching lines...) Expand all
91 if (!elements[4].empty()) 100 if (!elements[4].empty())
92 CHECK(base::StringToInt(elements[4], num_NALUs)); 101 CHECK(base::StringToInt(elements[4], num_NALUs));
93 if (!elements[5].empty()) 102 if (!elements[5].empty())
94 CHECK(base::StringToInt(elements[5], min_fps_render)); 103 CHECK(base::StringToInt(elements[5], min_fps_render));
95 if (!elements[6].empty()) 104 if (!elements[6].empty())
96 CHECK(base::StringToInt(elements[6], min_fps_no_render)); 105 CHECK(base::StringToInt(elements[6], min_fps_no_render));
97 if (!elements[7].empty()) 106 if (!elements[7].empty())
98 CHECK(base::StringToInt(elements[7], profile)); 107 CHECK(base::StringToInt(elements[7], profile));
99 } 108 }
100 109
110 // Helper for Shader creation.
111 static void CreateShader(
112 GLuint program, GLenum type, const char* source, int size) {
113 GLuint shader = glCreateShader(type);
114 glShaderSource(shader, 1, &source, &size);
115 glCompileShader(shader);
116 int result = GL_FALSE;
117 glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
118 if (!result) {
119 char log[4096];
120 glGetShaderInfoLog(shader, arraysize(log), NULL, log);
121 LOG(FATAL) << log;
122 }
123 glAttachShader(program, shader);
124 glDeleteShader(shader);
125 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
126 }
101 127
102 // Helper for managing X11, EGL, and GLES2 resources. Xlib is not thread-safe, 128 // Provides base functionality for managing EGL and GLES2 resources.
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Why move this below CreateShader above? It makes
ananta 2011/12/17 00:40:25 Moved this back to just before Initialize. The Cre
Ami GONE FROM CHROMIUM 2011/12/19 22:53:44 Hahahahahahaha - now it's harder to diff between p
103 // and GL state is thread-specific, so all the methods of this class (except for 129 // This class is not thread safe and thus all the methods of this class
104 // ctor/dtor) ensure they're being run on a single thread. 130 // (except for ctor/dtor) ensure they're being run on a single thread.
105 // 131 //
106 // TODO(fischman): consider moving this into media/ if we can de-dup some of the 132 // TODO(fischman): consider moving this into media/ if we can de-dup some of
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 TODO can be dropped now that the media/ version of
ananta 2011/12/17 00:40:25 Done.
107 // code that ends up getting copy/pasted all over the place (esp. the GL setup 133 // the code that ends up getting copy/pasted all over the place (esp. the GL
108 // code). 134 // setup code).
109 class RenderingHelper { 135 class RenderingHelperBase {
110 public: 136 public:
111 explicit RenderingHelper(); 137 RenderingHelperBase();
112 ~RenderingHelper(); 138 virtual ~RenderingHelperBase();
113 139
114 // Initialize all structures to prepare to render to one or more windows of 140 // Initialize all structures to prepare to render to one or more windows of
115 // the specified dimensions. CHECK-fails if any initialization step fails. 141 // the specified dimensions. CHECK-fails if any initialization step fails.
116 // After this returns, texture creation and rendering can be requested. This 142 // After this returns, texture creation and rendering can be requested. This
117 // method can be called multiple times, in which case all previously-acquired 143 // method can be called multiple times, in which case all previously-acquired
118 // resources and initializations are discarded. If |suppress_swap_to_display| 144 // resources and initializations are discarded. If |suppress_swap_to_display|
119 // then all the usual work is done, except for the final swap of the EGL 145 // then all the usual work is done, except for the final swap of the EGL
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 s/EGL// ?
ananta 2011/12/17 00:40:25 I just copied this as is from the existing comment
Ami GONE FROM CHROMIUM 2011/12/19 22:53:44 My point was that in the DXVA case the surfaces ar
120 // surface to the display. This cuts test times over 50% so is worth doing 146 // surface to the display. This cuts test times over 50% so is worth doing
121 // when testing non-rendering-related aspects. 147 // when testing non-rendering-related aspects.
122 void Initialize(bool suppress_swap_to_display, int num_windows, 148 virtual void Initialize(
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 You've introduced a de-facto requirement that subc
ananta 2011/12/17 00:40:25 Done.
123 int width, int height, base::WaitableEvent* done); 149 bool suppress_swap_to_display, int num_windows,
150 int width, int height, base::WaitableEvent* done);
124 151
125 // Undo the effects of Initialize() and signal |*done|. 152 // Undo the effects of Initialize() and signal |*done|.
126 void UnInitialize(base::WaitableEvent* done); 153 virtual void UnInitialize(base::WaitableEvent* done);
154
155 // Platform specific window creation.
156 virtual EGLNativeWindowType PlatformCreateWindow(int top_left_x,
157 int top_left_y) PURE;
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Is PURE cross-platform? I've only ever seen =0 in
ananta 2011/12/17 00:40:25 Done.
127 158
128 // Return a newly-created GLES2 texture id rendering to a specific window, and 159 // Return a newly-created GLES2 texture id rendering to a specific window, and
129 // signal |*done|. 160 // signal |*done|.
130 void CreateTexture(int window_id, GLuint* texture_id, 161 void CreateTexture(int window_id, GLuint* texture_id,
131 base::WaitableEvent* done); 162 base::WaitableEvent* done);
132 163
133 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|). 164 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|).
134 void RenderTexture(GLuint texture_id); 165 void RenderTexture(GLuint texture_id);
135 166
136 // Delete |texture_id|. 167 // Delete |texture_id|.
137 void DeleteTexture(GLuint texture_id); 168 void DeleteTexture(GLuint texture_id);
138 169
139 EGLDisplay egl_display() { return egl_display_; } 170 EGLDisplay egl_display() {
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 single-line
ananta 2011/12/17 00:40:25 Done.
140 EGLContext egl_context() { return egl_context_; } 171 return egl_display_;
172 }
173
174 EGLContext egl_context() {
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 single line
ananta 2011/12/17 00:40:25 Done.
175 return egl_context_;
176 }
177
141 MessageLoop* message_loop() { return message_loop_; } 178 MessageLoop* message_loop() { return message_loop_; }
142 179
143 private: 180 protected:
144 // Zero-out internal state. Helper for ctor & UnInitialize().
145 void Clear(); 181 void Clear();
146 182
147 bool suppress_swap_to_display_; 183 // We ensure all operations are carried out on the same thread by remembering
184 // where we were Initialized.
185 MessageLoop* message_loop_;
148 int width_; 186 int width_;
149 int height_; 187 int height_;
150 Display* x_display_; 188 bool suppress_swap_to_display_;
151 std::vector<Window> x_windows_; 189 int num_windows_;
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Never used.
ananta 2011/12/17 00:40:25 Removed
190
152 EGLDisplay egl_display_; 191 EGLDisplay egl_display_;
153 EGLContext egl_context_; 192 EGLContext egl_context_;
154 std::vector<EGLSurface> egl_surfaces_; 193 std::vector<EGLSurface> egl_surfaces_;
155 std::map<GLuint, int> texture_id_to_surface_index_; 194 std::map<GLuint, int> texture_id_to_surface_index_;
156 // We ensure all operations are carried out on the same thread by remembering
157 // where we were Initialized.
158 MessageLoop* message_loop_;
159 }; 195 };
160 196
161 RenderingHelper::RenderingHelper() { 197 RenderingHelperBase::RenderingHelperBase() {
162 Clear(); 198 Clear();
163 } 199 }
164 200
165 RenderingHelper::~RenderingHelper() { 201 RenderingHelperBase::~RenderingHelperBase() {
166 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor."; 202 Clear();
167 } 203 }
168 204
169 void RenderingHelper::Clear() { 205 void RenderingHelperBase::Initialize(bool suppress_swap_to_display,
170 suppress_swap_to_display_ = false; 206 int num_windows,
171 width_ = 0; 207 int width,
172 height_ = 0; 208 int height,
173 x_display_ = NULL; 209 base::WaitableEvent* done) {
174 x_windows_.clear();
175 egl_display_ = EGL_NO_DISPLAY;
176 egl_context_ = EGL_NO_CONTEXT;
177 egl_surfaces_.clear();
178 texture_id_to_surface_index_.clear();
179 message_loop_ = NULL;
180 }
181
182 // Helper for Shader creation.
183 static void CreateShader(
184 GLuint program, GLenum type, const char* source, int size) {
185 GLuint shader = glCreateShader(type);
186 glShaderSource(shader, 1, &source, &size);
187 glCompileShader(shader);
188 int result = GL_FALSE;
189 glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
190 if (!result) {
191 char log[4096];
192 glGetShaderInfoLog(shader, arraysize(log), NULL, log);
193 LOG(FATAL) << log;
194 }
195 glAttachShader(program, shader);
196 glDeleteShader(shader);
197 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
198 }
199
200 void RenderingHelper::Initialize(
201 bool suppress_swap_to_display,
202 int num_windows,
203 int width, int height,
204 base::WaitableEvent* done) {
205 // Use width_ != 0 as a proxy for the class having already been 210 // Use width_ != 0 as a proxy for the class having already been
206 // Initialize()'d, and UnInitialize() before continuing. 211 // Initialize()'d, and UnInitialize() before continuing.
207 if (width_) { 212 if (width_) {
208 base::WaitableEvent done(false, false); 213 base::WaitableEvent done(false, false);
209 UnInitialize(&done); 214 UnInitialize(&done);
210 done.Wait(); 215 done.Wait();
211 } 216 }
212 217
213 suppress_swap_to_display_ = suppress_swap_to_display; 218 suppress_swap_to_display_ = suppress_swap_to_display;
214 CHECK_GT(width, 0); 219 CHECK_GT(width, 0);
215 CHECK_GT(height, 0); 220 CHECK_GT(height, 0);
216 width_ = width; 221 width_ = width;
217 height_ = height; 222 height_ = height;
218 message_loop_ = MessageLoop::current(); 223 message_loop_ = MessageLoop::current();
219 CHECK_GT(num_windows, 0); 224 CHECK_GT(num_windows, 0);
225 num_windows_ = num_windows;
220 226
221 // Per-display X11 & EGL initialization.
222 CHECK(x_display_ = XOpenDisplay(NULL));
223 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
224 XSetWindowAttributes window_attributes;
225 window_attributes.background_pixel =
226 BlackPixel(x_display_, DefaultScreen(x_display_));
227 window_attributes.override_redirect = true;
228
229 egl_display_ = eglGetDisplay(x_display_);
230 EGLint major; 227 EGLint major;
231 EGLint minor; 228 EGLint minor;
232 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError(); 229 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
233 static EGLint rgba8888[] = { 230 static EGLint rgba8888[] = {
234 EGL_RED_SIZE, 8, 231 EGL_RED_SIZE, 8,
235 EGL_GREEN_SIZE, 8, 232 EGL_GREEN_SIZE, 8,
236 EGL_BLUE_SIZE, 8, 233 EGL_BLUE_SIZE, 8,
237 EGL_ALPHA_SIZE, 8, 234 EGL_ALPHA_SIZE, 8,
238 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 235 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
239 EGL_NONE, 236 EGL_NONE,
240 }; 237 };
241 EGLConfig egl_config; 238 EGLConfig egl_config;
242 int num_configs; 239 int num_configs;
243 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) 240 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
244 << eglGetError(); 241 << eglGetError();
245 CHECK_GE(num_configs, 1); 242 CHECK_GE(num_configs, 1);
246 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; 243 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
247 egl_context_ = eglCreateContext( 244 egl_context_ = eglCreateContext(
248 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); 245 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
249 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError(); 246 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();
250 247
251 // Per-window/surface X11 & EGL initialization. 248 // Per-window/surface X11 & EGL initialization.
252 for (int i = 0; i < num_windows; ++i) { 249 for (int i = 0; i < num_windows; ++i) {
253 // Arrange X windows whimsically, with some padding. 250 // Arrange X windows whimsically, with some padding.
254 int top_left_x = (width + 20) * (i % 4); 251 int top_left_x = (width + 20) * (i % 4);
255 int top_left_y = (height + 12) * (i % 3); 252 int top_left_y = (height + 12) * (i % 3);
256 Window x_window = XCreateWindow(
257 x_display_, DefaultRootWindow(x_display_),
258 top_left_x, top_left_y, width_, height_,
259 0 /* border width */,
260 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
261 (CWBackPixel | CWOverrideRedirect), &window_attributes);
262 x_windows_.push_back(x_window);
263 XStoreName(x_display_, x_window, "OmxVideoDecodeAcceleratorTest");
264 XSelectInput(x_display_, x_window, ExposureMask);
265 XMapWindow(x_display_, x_window);
266 253
254 EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y);
267 EGLSurface egl_surface = 255 EGLSurface egl_surface =
268 eglCreateWindowSurface(egl_display_, egl_config, x_window, NULL); 256 eglCreateWindowSurface(egl_display_, egl_config, window, NULL);
269 egl_surfaces_.push_back(egl_surface); 257 egl_surfaces_.push_back(egl_surface);
270 CHECK_NE(egl_surface, EGL_NO_SURFACE); 258 CHECK_NE(egl_surface, EGL_NO_SURFACE);
271 } 259 }
272 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0], 260 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0],
273 egl_surfaces_[0], egl_context_)) << eglGetError(); 261 egl_surfaces_[0], egl_context_)) << eglGetError();
274
275 // GLES2 initialization. Note: This is pretty much copy/pasted from 262 // GLES2 initialization. Note: This is pretty much copy/pasted from
276 // media/tools/player_x11/gles_video_renderer.cc, with some simplification 263 // media/tools/player_x11/gles_video_renderer.cc, with some simplification
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Drop the Note: since that file is now gone.
ananta 2011/12/17 00:40:25 Done.
277 // applied. 264 // applied.
278 static const float kVertices[] = 265 static const float kVertices[] =
279 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; 266 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
280 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, }; 267 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
281 static const char kVertexShader[] = STRINGIZE( 268 static const char kVertexShader[] = STRINGIZE(
282 varying vec2 interp_tc; 269 varying vec2 interp_tc;
283 attribute vec4 in_pos; 270 attribute vec4 in_pos;
284 attribute vec2 in_tc; 271 attribute vec2 in_tc;
285 void main() { 272 void main() {
286 interp_tc = in_tc; 273 interp_tc = in_tc;
(...skipping 25 matching lines...) Expand all
312 glDeleteProgram(program); 299 glDeleteProgram(program);
313 300
314 glUniform1i(glGetUniformLocation(program, "tex"), 0); 301 glUniform1i(glGetUniformLocation(program, "tex"), 0);
315 int pos_location = glGetAttribLocation(program, "in_pos"); 302 int pos_location = glGetAttribLocation(program, "in_pos");
316 glEnableVertexAttribArray(pos_location); 303 glEnableVertexAttribArray(pos_location);
317 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); 304 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
318 int tc_location = glGetAttribLocation(program, "in_tc"); 305 int tc_location = glGetAttribLocation(program, "in_tc");
319 glEnableVertexAttribArray(tc_location); 306 glEnableVertexAttribArray(tc_location);
320 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, 307 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
321 kTextureCoordsEgl); 308 kTextureCoordsEgl);
322
323 done->Signal();
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Since neither impl does anything after calling thi
324 } 309 }
325 310
326 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { 311 void RenderingHelperBase::UnInitialize(base::WaitableEvent* done) {
327 CHECK_EQ(MessageLoop::current(), message_loop_); 312 CHECK_EQ(MessageLoop::current(), message_loop_);
328 // Destroy resources acquired in Initialize, in reverse-acquisition order.
329 CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, 313 CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
330 EGL_NO_CONTEXT)) << eglGetError(); 314 EGL_NO_CONTEXT)) << eglGetError();
331 CHECK(eglDestroyContext(egl_display_, egl_context_)); 315 CHECK(eglDestroyContext(egl_display_, egl_context_));
332 for (size_t i = 0; i < egl_surfaces_.size(); ++i) 316 for (size_t i = 0; i < egl_surfaces_.size(); ++i)
333 CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i])); 317 CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
334 CHECK(eglTerminate(egl_display_)); 318 CHECK(eglTerminate(egl_display_));
335 for (size_t i = 0; i < x_windows_.size(); ++i) {
336 CHECK(XUnmapWindow(x_display_, x_windows_[i]));
337 CHECK(XDestroyWindow(x_display_, x_windows_[i]));
338 }
339 // Mimic newly-created object.
340 Clear(); 319 Clear();
341 done->Signal();
342 } 320 }
343 321
344 void RenderingHelper::CreateTexture(int window_id, GLuint* texture_id, 322 void RenderingHelperBase::Clear() {
345 base::WaitableEvent* done) { 323 suppress_swap_to_display_ = false;
324 width_ = 0;
325 height_ = 0;
326 texture_id_to_surface_index_.clear();
327 message_loop_ = NULL;
328 num_windows_ = 0;
329 egl_display_ = EGL_NO_DISPLAY;
330 egl_context_ = EGL_NO_CONTEXT;
331 egl_surfaces_.clear();
332 }
333
334 void RenderingHelperBase::CreateTexture(int window_id, GLuint* texture_id,
335 base::WaitableEvent* done) {
336 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Why is this before the trampoline?
ananta 2011/12/17 00:40:25 Stupid mistake :(
337 egl_surfaces_[window_id], egl_context_))
338 << eglGetError();
346 if (MessageLoop::current() != message_loop_) { 339 if (MessageLoop::current() != message_loop_) {
347 message_loop_->PostTask( 340 message_loop_->PostTask(
348 FROM_HERE, 341 FROM_HERE,
349 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), 342 base::Bind(&RenderingHelperBase::CreateTexture, base::Unretained(this),
350 window_id, texture_id, done)); 343 window_id, texture_id, done));
351 return; 344 return;
352 } 345 }
353 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
354 egl_surfaces_[window_id], egl_context_))
355 << eglGetError();
356 glGenTextures(1, texture_id); 346 glGenTextures(1, texture_id);
357 glBindTexture(GL_TEXTURE_2D, *texture_id); 347 glBindTexture(GL_TEXTURE_2D, *texture_id);
358 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, 348 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA,
359 GL_UNSIGNED_BYTE, NULL); 349 GL_UNSIGNED_BYTE, NULL);
360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 351 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
362 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. 352 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures.
363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 353 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
364 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
365 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 355 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
366 CHECK(texture_id_to_surface_index_.insert( 356 CHECK(texture_id_to_surface_index_.insert(
367 std::make_pair(*texture_id, window_id)).second); 357 std::make_pair(*texture_id, window_id)).second);
368 done->Signal(); 358 done->Signal();
369 } 359 }
370 360
371 void RenderingHelper::RenderTexture(GLuint texture_id) { 361 void RenderingHelperBase::RenderTexture(GLuint texture_id) {
372 CHECK_EQ(MessageLoop::current(), message_loop_); 362 CHECK_EQ(MessageLoop::current(), message_loop_);
373 glActiveTexture(GL_TEXTURE0); 363 glActiveTexture(GL_TEXTURE0);
374 glBindTexture(GL_TEXTURE_2D, texture_id); 364 glBindTexture(GL_TEXTURE_2D, texture_id);
375 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 365 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
376 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 366 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
377 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); 367 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
368
378 if (!suppress_swap_to_display_) { 369 if (!suppress_swap_to_display_) {
379 int window_id = texture_id_to_surface_index_[texture_id]; 370 int window_id = texture_id_to_surface_index_[texture_id];
380 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], 371 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
381 egl_surfaces_[window_id], egl_context_)) 372 egl_surfaces_[window_id], egl_context_))
382 << eglGetError(); 373 << eglGetError();
383 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]); 374 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]);
384 } 375 }
385 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); 376 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
386 } 377 }
387 378
388 void RenderingHelper::DeleteTexture(GLuint texture_id) { 379 void RenderingHelperBase::DeleteTexture(GLuint texture_id) {
389 glDeleteTextures(1, &texture_id); 380 glDeleteTextures(1, &texture_id);
390 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); 381 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
391 } 382 }
392 383
384 #if defined(OS_WIN)
385 // Provides Windows specific functionality for managing resources like HWND's
386 // The OpenGL and GLES management is provided by the RenderingHelperBase class.
387 class Win32RenderingHelper : public RenderingHelperBase {
388 public:
389 Win32RenderingHelper();
390 virtual ~Win32RenderingHelper();
391
392 virtual void Initialize(
393 bool suppress_swap_to_display, int num_windows,
394 int width, int height, base::WaitableEvent* done) OVERRIDE;
395
396 virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE;
397
398 EGLNativeWindowType PlatformCreateWindow(int top_left_x,
399 int top_left_y) OVERRIDE;
400 private:
401 void Clear();
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 This shadows the base-class Clear (which isn't vir
ananta 2011/12/17 00:40:25 Replaced this with a virtual override combo Platfo
402
403 std::vector<HWND> windows_;
404 };
405
406 Win32RenderingHelper::Win32RenderingHelper()
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Single line.
ananta 2011/12/17 00:40:25 Done.
407 : windows_(NULL) {
408 }
409
410 Win32RenderingHelper::~Win32RenderingHelper() {
411 Clear();
412 }
413
414 void Win32RenderingHelper::Initialize(bool suppress_swap_to_display,
415 int num_windows,
416 int width,
417 int height,
418 base::WaitableEvent* done) {
419 egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
420 RenderingHelperBase::Initialize(suppress_swap_to_display, num_windows, width,
421 height, done);
422 done->Signal();
423 }
424
425 void Win32RenderingHelper::UnInitialize(base::WaitableEvent* done) {
426 RenderingHelperBase::UnInitialize(done);
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 No need to undo the eglGetDisplay() from Initializ
ananta 2011/12/17 00:40:25 That happens in the base class Clear function. We
427 Clear();
428 done->Signal();
429 }
430
431 void Win32RenderingHelper::Clear() {
432 for (size_t i = 0; i < windows_.size(); ++i) {
433 DestroyWindow(windows_[i]);
434 }
435 windows_.clear();
436 }
437
438 EGLNativeWindowType Win32RenderingHelper::PlatformCreateWindow(
439 int top_left_x, int top_left_y) {
440 HWND window = CreateWindowEx(0,
441 L"Static",
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Wrap a bit more aggressively?
ananta 2011/12/17 00:40:25 Done.
442 L"VideoDecodeAcceleratorTest",
443 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
444 top_left_x,
445 top_left_y,
446 width_,
447 height_,
448 NULL,
449 NULL,
450 NULL,
451 NULL);
452 CHECK(window != NULL);
453 windows_.push_back(window);
454 return window;
455 }
456
457 #else // OS_WIN
458
459 // Provides X11 specific functionality for managing X11 resources. The OpenGL
460 // and GLES management is provided by the RenderingHelperBase class.
461 class OmxRenderingHelper : public RenderingHelperBase {
462 public:
463 explicit OmxRenderingHelper();
464 ~OmxRenderingHelper();
465
466 // Initialize all structures to prepare to render to one or more windows of
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Commentary isn't necessary for OVERRIDEs. Just pr
ananta 2011/12/17 00:40:25 Done.
467 // the specified dimensions. CHECK-fails if any initialization step fails.
468 // After this returns, texture creation and rendering can be requested. This
469 // method can be called multiple times, in which case all previously-acquired
470 // resources and initializations are discarded. If |suppress_swap_to_display|
471 // then all the usual work is done, except for the final swap of the EGL
472 // surface to the display. This cuts test times over 50% so is worth doing
473 // when testing non-rendering-related aspects.
474 virtual void Initialize(
475 bool suppress_swap_to_display, int num_windows,
476 int width, int height, base::WaitableEvent* done) OVERRIDE;
477
478 // Undo the effects of Initialize() and signal |*done|.
479 virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE;
480
481 virtual EGLNativeWindowType PlatformCreateWindow(int top_left_x,
482 int top_left_y) OVERRIDE;
483
484
485 private:
486 // Zero-out internal state. Helper for ctor & UnInitialize().
487 void Clear();
488
489 Display* x_display_;
490 std::vector<Window> x_windows_;
491 };
492
493 OmxRenderingHelper::OmxRenderingHelper() {
494 Clear();
495 }
496
497 OmxRenderingHelper::~OmxRenderingHelper() {
498 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
499 }
500
501 void OmxRenderingHelper::Clear() {
502 x_display_ = NULL;
503 x_windows_.clear();
504 }
505
506 void OmxRenderingHelper::Initialize(
507 bool suppress_swap_to_display,
508 int num_windows,
509 int width, int height,
510 base::WaitableEvent* done) {
511 // Per-display X11 & EGL initialization.
512 CHECK(x_display_ = XOpenDisplay(NULL));
513 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
514 XSetWindowAttributes window_attributes;
515 window_attributes.background_pixel =
516 BlackPixel(x_display_, DefaultScreen(x_display_));
517 window_attributes.override_redirect = true;
518
519 egl_display_ = eglGetDisplay(x_display_);
520
521 RenderingHelperBase::Initialize(suppress_swap_to_display, num_windows,
522 width, height, done);
523 done->Signal();
524 }
525
526 void OmxRenderingHelper::UnInitialize(base::WaitableEvent* done) {
527 RenderingHelperBase::Uninitialize();
528 // Destroy resources acquired in Initialize, in reverse-acquisition order.
529 for (size_t i = 0; i < x_windows_.size(); ++i) {
530 CHECK(XUnmapWindow(x_display_, x_windows_[i]));
531 CHECK(XDestroyWindow(x_display_, x_windows_[i]));
532 }
533 // Mimic newly-created object.
534 Clear();
535 done->Signal();
536 }
537
538 EGLNativeWindowType OmxRenderingHelper::PlatformCreateWindow(int top_left_x,
539 int top_left_y) {
540 Window x_window = XCreateWindow(
541 x_display_, DefaultRootWindow(x_display_),
542 top_left_x, top_left_y, width_, height_,
543 0 /* border width */,
544 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
545 (CWBackPixel | CWOverrideRedirect), &window_attributes);
546 x_windows_.push_back(x_window);
547 XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest");
548 XSelectInput(x_display_, x_window, ExposureMask);
549 XMapWindow(x_display_, x_window);
550 return x_window;
551 }
552
553 #endif // OS_WIN
554
393 // State of the EglRenderingVDAClient below. Order matters here as the test 555 // State of the EglRenderingVDAClient below. Order matters here as the test
394 // makes assumptions about it. 556 // makes assumptions about it.
395 enum ClientState { 557 enum ClientState {
396 CS_CREATED, 558 CS_CREATED,
397 CS_DECODER_SET, 559 CS_DECODER_SET,
398 CS_INITIALIZED, 560 CS_INITIALIZED,
399 CS_FLUSHING, 561 CS_FLUSHING,
400 CS_FLUSHED, 562 CS_FLUSHED,
401 CS_DONE, 563 CS_DONE,
402 CS_RESETTING, 564 CS_RESETTING,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { 618 class EglRenderingVDAClient : public VideoDecodeAccelerator::Client {
457 public: 619 public:
458 // Doesn't take ownership of |rendering_helper| or |note|, which must outlive 620 // Doesn't take ownership of |rendering_helper| or |note|, which must outlive
459 // |*this|. 621 // |*this|.
460 // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream 622 // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream
461 // Reset() should be done after that frame number is delivered, or 623 // Reset() should be done after that frame number is delivered, or
462 // END_OF_STREAM_RESET to indicate no mid-stream Reset(). 624 // END_OF_STREAM_RESET to indicate no mid-stream Reset().
463 // |delete_decoder_state| indicates when the underlying decoder should be 625 // |delete_decoder_state| indicates when the underlying decoder should be
464 // Destroy()'d and deleted and can take values: N<0: delete after -N Decode() 626 // Destroy()'d and deleted and can take values: N<0: delete after -N Decode()
465 // calls have been made, N>=0 means interpret as ClientState. 627 // calls have been made, N>=0 means interpret as ClientState.
466 EglRenderingVDAClient(RenderingHelper* rendering_helper, 628 EglRenderingVDAClient(RenderingHelperBase* rendering_helper,
467 int rendering_window_id, 629 int rendering_window_id,
468 ClientStateNotification* note, 630 ClientStateNotification* note,
469 const std::string& encoded_data, 631 const std::string& encoded_data,
470 int num_NALUs_per_decode, 632 int num_NALUs_per_decode,
471 int num_in_flight_decodes, 633 int num_in_flight_decodes,
472 int reset_after_frame_num, 634 int reset_after_frame_num,
473 int delete_decoder_state, 635 int delete_decoder_state,
474 int profile); 636 int profile);
475 virtual ~EglRenderingVDAClient(); 637 virtual ~EglRenderingVDAClient();
476 void CreateDecoder(); 638 void CreateDecoder();
(...skipping 30 matching lines...) Expand all
507 // Delete the associated OMX decoder helper. 669 // Delete the associated OMX decoder helper.
508 void DeleteDecoder(); 670 void DeleteDecoder();
509 671
510 // Compute & return in |*end_pos| the end position for the next batch of NALUs 672 // Compute & return in |*end_pos| the end position for the next batch of NALUs
511 // to ship to the decoder (based on |start_pos| & |num_NALUs_per_decode_|). 673 // to ship to the decoder (based on |start_pos| & |num_NALUs_per_decode_|).
512 void GetRangeForNextNALUs(size_t start_pos, size_t* end_pos); 674 void GetRangeForNextNALUs(size_t start_pos, size_t* end_pos);
513 675
514 // Request decode of the next batch of NALUs in the encoded data. 676 // Request decode of the next batch of NALUs in the encoded data.
515 void DecodeNextNALUs(); 677 void DecodeNextNALUs();
516 678
517 RenderingHelper* rendering_helper_; 679 RenderingHelperBase* rendering_helper_;
680
518 int rendering_window_id_; 681 int rendering_window_id_;
519 std::string encoded_data_; 682 std::string encoded_data_;
520 const int num_NALUs_per_decode_; 683 const int num_NALUs_per_decode_;
521 const int num_in_flight_decodes_; 684 const int num_in_flight_decodes_;
522 int outstanding_decodes_; 685 int outstanding_decodes_;
523 size_t encoded_data_next_pos_to_decode_; 686 size_t encoded_data_next_pos_to_decode_;
524 int next_bitstream_buffer_id_; 687 int next_bitstream_buffer_id_;
525 ClientStateNotification* note_; 688 ClientStateNotification* note_;
689 #if defined(OS_WIN)
690 scoped_refptr<DXVAVideoDecodeAccelerator> decoder_;
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 Can this simply store a scoped_refptr<media::Video
ananta 2011/12/17 00:40:25 Done.
691 #else // OS_WIN
526 scoped_refptr<OmxVideoDecodeAccelerator> decoder_; 692 scoped_refptr<OmxVideoDecodeAccelerator> decoder_;
693 #endif // OS_WIN
527 std::set<int> outstanding_texture_ids_; 694 std::set<int> outstanding_texture_ids_;
528 int reset_after_frame_num_; 695 int reset_after_frame_num_;
529 int delete_decoder_state_; 696 int delete_decoder_state_;
530 ClientState state_; 697 ClientState state_;
531 int num_decoded_frames_; 698 int num_decoded_frames_;
532 int num_done_bitstream_buffers_; 699 int num_done_bitstream_buffers_;
533 PictureBufferById picture_buffers_by_id_; 700 PictureBufferById picture_buffers_by_id_;
534 base::TimeTicks initialize_done_ticks_; 701 base::TimeTicks initialize_done_ticks_;
535 base::TimeTicks last_frame_delivered_ticks_; 702 base::TimeTicks last_frame_delivered_ticks_;
536 int profile_; 703 int profile_;
537 }; 704 };
538 705
539 EglRenderingVDAClient::EglRenderingVDAClient( 706 EglRenderingVDAClient::EglRenderingVDAClient(
540 RenderingHelper* rendering_helper, 707 RenderingHelperBase* rendering_helper,
541 int rendering_window_id, 708 int rendering_window_id,
542 ClientStateNotification* note, 709 ClientStateNotification* note,
543 const std::string& encoded_data, 710 const std::string& encoded_data,
544 int num_NALUs_per_decode, 711 int num_NALUs_per_decode,
545 int num_in_flight_decodes, 712 int num_in_flight_decodes,
546 int reset_after_frame_num, 713 int reset_after_frame_num,
547 int delete_decoder_state, 714 int delete_decoder_state,
548 int profile) 715 int profile)
549 : rendering_helper_(rendering_helper), 716 : rendering_helper_(rendering_helper),
550 rendering_window_id_(rendering_window_id), 717 rendering_window_id_(rendering_window_id),
(...skipping 11 matching lines...) Expand all
562 729
563 EglRenderingVDAClient::~EglRenderingVDAClient() { 730 EglRenderingVDAClient::~EglRenderingVDAClient() {
564 DeleteDecoder(); // Clean up in case of expected error. 731 DeleteDecoder(); // Clean up in case of expected error.
565 CHECK(decoder_deleted()); 732 CHECK(decoder_deleted());
566 STLDeleteValues(&picture_buffers_by_id_); 733 STLDeleteValues(&picture_buffers_by_id_);
567 SetState(CS_DESTROYED); 734 SetState(CS_DESTROYED);
568 } 735 }
569 736
570 void EglRenderingVDAClient::CreateDecoder() { 737 void EglRenderingVDAClient::CreateDecoder() {
571 CHECK(decoder_deleted()); 738 CHECK(decoder_deleted());
739 #if defined(OS_WIN)
740 decoder_ = new DXVAVideoDecodeAccelerator(this,
741 base::GetCurrentProcessHandle());
742 #else // OS_WIN
572 decoder_ = new OmxVideoDecodeAccelerator(this); 743 decoder_ = new OmxVideoDecodeAccelerator(this);
573 decoder_->SetEglState(egl_display(), egl_context()); 744 decoder_->SetEglState(egl_display(), egl_context());
745 #endif // OS_WIN
574 SetState(CS_DECODER_SET); 746 SetState(CS_DECODER_SET);
575 if (decoder_deleted()) 747 if (decoder_deleted())
576 return; 748 return;
577 749
578 // Configure the decoder. 750 // Configure the decoder.
579 media::VideoDecodeAccelerator::Profile profile = media::H264PROFILE_BASELINE; 751 media::VideoDecodeAccelerator::Profile profile = media::H264PROFILE_BASELINE;
580 if (profile_ != -1) 752 if (profile_ != -1)
581 profile = static_cast<media::VideoDecodeAccelerator::Profile>(profile_); 753 profile = static_cast<media::VideoDecodeAccelerator::Profile>(profile_);
582 CHECK(decoder_->Initialize(profile)); 754 CHECK(decoder_->Initialize(profile));
583 } 755 }
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 return 0; 950 return 0;
779 return num_decoded_frames_ / delta.InSecondsF(); 951 return num_decoded_frames_ / delta.InSecondsF();
780 } 952 }
781 953
782 // Test parameters: 954 // Test parameters:
783 // - Number of NALUs per Decode() call. 955 // - Number of NALUs per Decode() call.
784 // - Number of concurrent decoders. 956 // - Number of concurrent decoders.
785 // - Number of concurrent in-flight Decode() calls per decoder. 957 // - Number of concurrent in-flight Decode() calls per decoder.
786 // - reset_after_frame_num: see EglRenderingVDAClient ctor. 958 // - reset_after_frame_num: see EglRenderingVDAClient ctor.
787 // - delete_decoder_phase: see EglRenderingVDAClient ctor. 959 // - delete_decoder_phase: see EglRenderingVDAClient ctor.
788 class OmxVideoDecodeAcceleratorTest 960 class VideoDecodeAcceleratorTest
789 : public ::testing::TestWithParam< 961 : public ::testing::TestWithParam<
790 Tuple5<int, int, int, ResetPoint, ClientState> > { 962 Tuple5<int, int, int, ResetPoint, ClientState> > {
791 }; 963 };
792 964
793 // Wait for |note| to report a state and if it's not |expected_state| then 965 // Wait for |note| to report a state and if it's not |expected_state| then
794 // assert |client| has deleted its decoder. 966 // assert |client| has deleted its decoder.
795 static void AssertWaitForStateOrDeleted(ClientStateNotification* note, 967 static void AssertWaitForStateOrDeleted(ClientStateNotification* note,
796 EglRenderingVDAClient* client, 968 EglRenderingVDAClient* client,
797 ClientState expected_state) { 969 ClientState expected_state) {
798 ClientState state = note->Wait(); 970 ClientState state = note->Wait();
799 if (state == expected_state) return; 971 if (state == expected_state) return;
800 ASSERT_TRUE(client->decoder_deleted()) 972 ASSERT_TRUE(client->decoder_deleted())
801 << "Decoder not deleted but Wait() returned " << state 973 << "Decoder not deleted but Wait() returned " << state
802 << ", instead of " << expected_state; 974 << ", instead of " << expected_state;
803 } 975 }
804 976
805 // We assert a minimal number of concurrent decoders we expect to succeed. 977 // We assert a minimal number of concurrent decoders we expect to succeed.
806 // Different platforms can support more concurrent decoders, so we don't assert 978 // Different platforms can support more concurrent decoders, so we don't assert
807 // failure above this. 979 // failure above this.
808 enum { kMinSupportedNumConcurrentDecoders = 3 }; 980 enum { kMinSupportedNumConcurrentDecoders = 3 };
809 981
810 // Test the most straightforward case possible: data is decoded from a single 982 // Test the most straightforward case possible: data is decoded from a single
811 // chunk and rendered to the screen. 983 // chunk and rendered to the screen.
812 TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { 984 TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) {
813 // Can be useful for debugging VLOGs from OVDA. 985 // Can be useful for debugging VLOGs from OVDA.
814 // logging::SetMinLogLevel(-1); 986 // logging::SetMinLogLevel(-1);
815 987
816 // Required for Thread to work. Not used otherwise. 988 // Required for Thread to work. Not used otherwise.
817 base::ShadowingAtExitManager at_exit_manager; 989 base::ShadowingAtExitManager at_exit_manager;
818 990
819 const int num_NALUs_per_decode = GetParam().a; 991 const int num_NALUs_per_decode = GetParam().a;
820 const size_t num_concurrent_decoders = GetParam().b; 992 const size_t num_concurrent_decoders = GetParam().b;
821 const size_t num_in_flight_decodes = GetParam().c; 993 const size_t num_in_flight_decodes = GetParam().c;
822 const int reset_after_frame_num = GetParam().d; 994 const int reset_after_frame_num = GetParam().d;
(...skipping 15 matching lines...) Expand all
838 1010
839 // Suppress EGL surface swapping in all but a few tests, to cut down overall 1011 // Suppress EGL surface swapping in all but a few tests, to cut down overall
840 // test runtime. 1012 // test runtime.
841 const bool suppress_swap_to_display = num_NALUs_per_decode > 1; 1013 const bool suppress_swap_to_display = num_NALUs_per_decode > 1;
842 1014
843 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL); 1015 std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL);
844 std::vector<EglRenderingVDAClient*> clients(num_concurrent_decoders, NULL); 1016 std::vector<EglRenderingVDAClient*> clients(num_concurrent_decoders, NULL);
845 1017
846 // Read in the video data. 1018 // Read in the video data.
847 std::string data_str; 1019 std::string data_str;
848 CHECK(file_util::ReadFileToString(FilePath(test_video_file), &data_str)); 1020 CHECK(file_util::ReadFileToString(FilePath(UTF8ToWide(test_video_file)),
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 This is win-specific. Instead use FILE_PATH_LITERA
ananta 2011/12/17 00:40:25 Done.
1021 &data_str));
849 1022
850 // Initialize the rendering helper. 1023 // Initialize the rendering helper.
851 base::Thread rendering_thread("EglRenderingVDAClientThread"); 1024 base::Thread rendering_thread("EglRenderingVDAClientThread");
852 rendering_thread.Start(); 1025 rendering_thread.Start();
853 RenderingHelper rendering_helper; 1026 #if defined(OS_WIN)
1027 Win32RenderingHelper rendering_helper;
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 A crazy idea appears: if you named both renderingh
ananta 2011/12/17 00:40:25 Done.
1028 #else // OS_WIN
1029 OmxRenderingHelper rendering_helper;
1030 #endif // OS_WIN
854 1031
855 base::WaitableEvent done(false, false); 1032 base::WaitableEvent done(false, false);
856 rendering_thread.message_loop()->PostTask( 1033 rendering_thread.message_loop()->PostTask(
857 FROM_HERE, 1034 FROM_HERE,
858 base::Bind(&RenderingHelper::Initialize, 1035 base::Bind(&RenderingHelperBase::Initialize,
859 base::Unretained(&rendering_helper), 1036 base::Unretained(&rendering_helper),
860 suppress_swap_to_display, num_concurrent_decoders, 1037 suppress_swap_to_display, num_concurrent_decoders,
861 frame_width, frame_height, &done)); 1038 frame_width, frame_height, &done));
862 done.Wait(); 1039 done.Wait();
863 1040
864 // First kick off all the decoders. 1041 // First kick off all the decoders.
865 for (size_t index = 0; index < num_concurrent_decoders; ++index) { 1042 for (size_t index = 0; index < num_concurrent_decoders; ++index) {
866 ClientStateNotification* note = new ClientStateNotification(); 1043 ClientStateNotification* note = new ClientStateNotification();
867 notes[index] = note; 1044 notes[index] = note;
868 EglRenderingVDAClient* client = new EglRenderingVDAClient( 1045 EglRenderingVDAClient* client = new EglRenderingVDAClient(
(...skipping 13 matching lines...) Expand all
882 // Then wait for all the decodes to finish. 1059 // Then wait for all the decodes to finish.
883 bool saw_init_failure = false; 1060 bool saw_init_failure = false;
884 for (size_t i = 0; i < num_concurrent_decoders; ++i) { 1061 for (size_t i = 0; i < num_concurrent_decoders; ++i) {
885 ClientStateNotification* note = notes[i]; 1062 ClientStateNotification* note = notes[i];
886 ClientState state = note->Wait(); 1063 ClientState state = note->Wait();
887 if (state != CS_INITIALIZED) { 1064 if (state != CS_INITIALIZED) {
888 saw_init_failure = true; 1065 saw_init_failure = true;
889 // We expect initialization to fail only when more than the supported 1066 // We expect initialization to fail only when more than the supported
890 // number of decoders is instantiated. Assert here that something else 1067 // number of decoders is instantiated. Assert here that something else
891 // didn't trigger failure. 1068 // didn't trigger failure.
892 ASSERT_GT(num_concurrent_decoders, kMinSupportedNumConcurrentDecoders); 1069 ASSERT_GT(num_concurrent_decoders,
1070 static_cast<size_t>(kMinSupportedNumConcurrentDecoders));
893 continue; 1071 continue;
894 } 1072 }
895 ASSERT_EQ(state, CS_INITIALIZED); 1073 ASSERT_EQ(state, CS_INITIALIZED);
896 // InitializeDone kicks off decoding inside the client, so we just need to 1074 // InitializeDone kicks off decoding inside the client, so we just need to
897 // wait for Flush. 1075 // wait for Flush.
898 ASSERT_NO_FATAL_FAILURE( 1076 ASSERT_NO_FATAL_FAILURE(
899 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING)); 1077 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING));
900 ASSERT_NO_FATAL_FAILURE( 1078 ASSERT_NO_FATAL_FAILURE(
901 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); 1079 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED));
902 // FlushDone requests Reset(). 1080 // FlushDone requests Reset().
(...skipping 27 matching lines...) Expand all
930 rendering_thread.message_loop()->PostTask( 1108 rendering_thread.message_loop()->PostTask(
931 FROM_HERE, 1109 FROM_HERE,
932 base::Bind(&STLDeleteElements<std::vector<EglRenderingVDAClient*> >, 1110 base::Bind(&STLDeleteElements<std::vector<EglRenderingVDAClient*> >,
933 &clients)); 1111 &clients));
934 rendering_thread.message_loop()->PostTask( 1112 rendering_thread.message_loop()->PostTask(
935 FROM_HERE, 1113 FROM_HERE,
936 base::Bind(&STLDeleteElements<std::vector<ClientStateNotification*> >, 1114 base::Bind(&STLDeleteElements<std::vector<ClientStateNotification*> >,
937 &notes)); 1115 &notes));
938 rendering_thread.message_loop()->PostTask( 1116 rendering_thread.message_loop()->PostTask(
939 FROM_HERE, 1117 FROM_HERE,
940 base::Bind(&RenderingHelper::UnInitialize, 1118 base::Bind(&RenderingHelperBase::UnInitialize,
941 base::Unretained(&rendering_helper), 1119 base::Unretained(&rendering_helper),
942 &done)); 1120 &done));
943 done.Wait(); 1121 done.Wait();
944 rendering_thread.Stop(); 1122 rendering_thread.Stop();
945 }; 1123 };
946 1124
947 // Test that Reset() mid-stream works fine and doesn't affect decoding even when 1125 // Test that Reset() mid-stream works fine and doesn't affect decoding even when
948 // Decode() calls are made during the reset. 1126 // Decode() calls are made during the reset.
949 INSTANTIATE_TEST_CASE_P( 1127 INSTANTIATE_TEST_CASE_P(
950 MidStreamReset, OmxVideoDecodeAcceleratorTest, 1128 MidStreamReset, VideoDecodeAcceleratorTest,
951 ::testing::Values( 1129 ::testing::Values(
952 MakeTuple(1, 1, 1, static_cast<ResetPoint>(100), CS_RESET))); 1130 MakeTuple(1, 1, 1, static_cast<ResetPoint>(100), CS_RESET)));
953 1131
954 // Test that Destroy() mid-stream works fine (primarily this is testing that no 1132 // Test that Destroy() mid-stream works fine (primarily this is testing that no
955 // crashes occur). 1133 // crashes occur).
956 INSTANTIATE_TEST_CASE_P( 1134 INSTANTIATE_TEST_CASE_P(
957 TearDownTiming, OmxVideoDecodeAcceleratorTest, 1135 TearDownTiming, VideoDecodeAcceleratorTest,
958 ::testing::Values( 1136 ::testing::Values(
959 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET), 1137 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET),
960 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED), 1138 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED),
961 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING), 1139 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING),
962 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED), 1140 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED),
963 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING), 1141 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING),
964 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1142 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET),
965 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-1)), 1143 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-1)),
966 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-10)), 1144 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-10)),
967 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, 1145 MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
968 static_cast<ClientState>(-100)))); 1146 static_cast<ClientState>(-100))));
969 1147
970 // Test that decoding various variation works: multiple concurrent decoders and 1148 // Test that decoding various variation works: multiple concurrent decoders and
971 // multiple NALUs per Decode() call. 1149 // multiple NALUs per Decode() call.
972 INSTANTIATE_TEST_CASE_P( 1150 INSTANTIATE_TEST_CASE_P(
973 DecodeVariations, OmxVideoDecodeAcceleratorTest, 1151 DecodeVariations, VideoDecodeAcceleratorTest,
974 ::testing::Values( 1152 ::testing::Values(
975 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1153 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET),
976 MakeTuple(1, 1, 10, END_OF_STREAM_RESET, CS_RESET), 1154 MakeTuple(1, 1, 10, END_OF_STREAM_RESET, CS_RESET),
977 MakeTuple(1, 1, 15, END_OF_STREAM_RESET, CS_RESET), // Tests queuing. 1155 MakeTuple(1, 1, 15, END_OF_STREAM_RESET, CS_RESET), // Tests queuing.
978 MakeTuple(1, 3, 1, END_OF_STREAM_RESET, CS_RESET), 1156 MakeTuple(1, 3, 1, END_OF_STREAM_RESET, CS_RESET),
979 MakeTuple(2, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1157 MakeTuple(2, 1, 1, END_OF_STREAM_RESET, CS_RESET),
980 MakeTuple(3, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1158 MakeTuple(3, 1, 1, END_OF_STREAM_RESET, CS_RESET),
981 MakeTuple(5, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1159 MakeTuple(5, 1, 1, END_OF_STREAM_RESET, CS_RESET),
982 MakeTuple(8, 1, 1, END_OF_STREAM_RESET, CS_RESET), 1160 MakeTuple(8, 1, 1, END_OF_STREAM_RESET, CS_RESET),
983 // TODO(fischman): decoding more than 15 NALUs at once breaks decode - 1161 // TODO(fischman): decoding more than 15 NALUs at once breaks decode -
984 // visual artifacts are introduced as well as spurious frames are 1162 // visual artifacts are introduced as well as spurious frames are
985 // delivered (more pictures are returned than NALUs are fed to the 1163 // delivered (more pictures are returned than NALUs are fed to the
986 // decoder). Increase the "15" below when 1164 // decoder). Increase the "15" below when
987 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is 1165 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is
988 // fixed. 1166 // fixed.
989 MakeTuple(15, 1, 1, END_OF_STREAM_RESET, CS_RESET))); 1167 MakeTuple(15, 1, 1, END_OF_STREAM_RESET, CS_RESET)));
990 1168
991 // Find out how many concurrent decoders can go before we exhaust system 1169 // Find out how many concurrent decoders can go before we exhaust system
992 // resources. 1170 // resources.
993 INSTANTIATE_TEST_CASE_P( 1171 INSTANTIATE_TEST_CASE_P(
994 ResourceExhaustion, OmxVideoDecodeAcceleratorTest, 1172 ResourceExhaustion, VideoDecodeAcceleratorTest,
995 ::testing::Values( 1173 ::testing::Values(
996 // +0 hack below to promote enum to int. 1174 // +0 hack below to promote enum to int.
997 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1, 1175 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1,
998 END_OF_STREAM_RESET, CS_RESET), 1176 END_OF_STREAM_RESET, CS_RESET),
999 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1, 1177 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1,
1000 END_OF_STREAM_RESET, CS_RESET))); 1178 END_OF_STREAM_RESET, CS_RESET)));
1001 1179
1002 // TODO(fischman, vrk): add more tests! In particular: 1180 // TODO(fischman, vrk): add more tests! In particular:
1003 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. 1181 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder.
1004 // - Test alternate configurations 1182 // - Test alternate configurations
1005 // - Test failure conditions. 1183 // - Test failure conditions.
1006 // - Test frame size changes mid-stream 1184 // - Test frame size changes mid-stream
1007 1185
1008 } // namespace 1186 } // namespace
1009 1187
1010 int main(int argc, char **argv) { 1188 int main(int argc, char **argv) {
1011 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. 1189 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args.
1012 CommandLine cmd_line(argc, argv); // Must run after InitGoogleTest. 1190 CommandLine::Init(argc, argv);
1013 CommandLine::SwitchMap switches = cmd_line.GetSwitches(); 1191
1192 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
1193 DCHECK(cmd_line);
1194
1195 CommandLine::SwitchMap switches = cmd_line->GetSwitches();
1014 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); 1196 for (CommandLine::SwitchMap::const_iterator it = switches.begin();
1015 it != switches.end(); ++it) { 1197 it != switches.end(); ++it) {
1016 if (it->first == "test_video_data") { 1198 if (it->first == "test_video_data") {
1199 #if defined(OS_WIN)
Ami GONE FROM CHROMIUM 2011/12/16 07:38:54 FILE_PATH_LITERAL should let you lose this.
ananta 2011/12/17 00:40:25 Done.
1200 test_video_data = WideToUTF8(it->second);
1201 #else // OS_WIN
1017 test_video_data = it->second.c_str(); 1202 test_video_data = it->second.c_str();
1203 #endif // OS_WIN
1018 continue; 1204 continue;
1019 } 1205 }
1020 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; 1206 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
1021 } 1207 }
1022
1023 return RUN_ALL_TESTS(); 1208 return RUN_ALL_TESTS();
1024 } 1209 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698