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

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

Issue 10388108: Implement media::VideoDecodeAccelerator on Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address review comments Created 8 years, 7 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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
(...skipping 20 matching lines...) Expand all
31 #include "base/process_util.h" 31 #include "base/process_util.h"
32 #include "base/stl_util.h" 32 #include "base/stl_util.h"
33 #include "base/string_number_conversions.h" 33 #include "base/string_number_conversions.h"
34 #include "base/string_split.h" 34 #include "base/string_split.h"
35 #include "base/stringize_macros.h" 35 #include "base/stringize_macros.h"
36 #include "base/synchronization/condition_variable.h" 36 #include "base/synchronization/condition_variable.h"
37 #include "base/synchronization/lock.h" 37 #include "base/synchronization/lock.h"
38 #include "base/synchronization/waitable_event.h" 38 #include "base/synchronization/waitable_event.h"
39 #include "base/threading/thread.h" 39 #include "base/threading/thread.h"
40 #include "base/utf_string_conversions.h" 40 #include "base/utf_string_conversions.h"
41 41 #include "content/common/gpu/media/rendering_helper.h"
42 #if (!defined(OS_CHROMEOS) || !defined(ARCH_CPU_ARMEL)) && !defined(OS_WIN)
43 #error The VideoAccelerator tests are only supported on cros/ARM/Windows.
44 #endif
45 42
46 #if defined(OS_WIN) 43 #if defined(OS_WIN)
47 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" 44 #include "content/common/gpu/media/dxva_video_decode_accelerator.h"
48 #else // OS_WIN 45 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
49 #include "content/common/gpu/media/omx_video_decode_accelerator.h" 46 #include "content/common/gpu/media/omx_video_decode_accelerator.h"
47 #elif defined(OS_MACOSX)
48 #include "content/common/gpu/media/mac_video_decode_accelerator.h"
49 #else
50 #error The VideoAccelerator tests are not supported on this platform.
50 #endif // defined(OS_WIN) 51 #endif // defined(OS_WIN)
51 52
52 #include "third_party/angle/include/EGL/egl.h"
53
54 #if defined(OS_WIN)
55 #include "ui/gl/gl_bindings.h"
56 #include "ui/gl/gl_context.h"
57 #include "ui/gl/gl_implementation.h"
58 #include "ui/gl/gl_surface.h"
59 #else // OS_WIN
60 #include "third_party/angle/include/GLES2/gl2.h"
61 #endif // OS_WIN
62
63 using media::VideoDecodeAccelerator; 53 using media::VideoDecodeAccelerator;
54 using video_test_util::RenderingHelper;
64 55
65 namespace { 56 namespace {
66 57
67 // Values optionally filled in from flags; see main() below. 58 // Values optionally filled in from flags; see main() below.
68 // The syntax of this variable is: 59 // The syntax of this variable is:
69 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender 60 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender
70 // where only the first field is required. Value details: 61 // where only the first field is required. Value details:
71 // - |filename| must be an h264 Annex B (NAL) stream. 62 // - |filename| must be an h264 Annex B (NAL) stream.
72 // - |width| and |height| are in pixels. 63 // - |width| and |height| are in pixels.
73 // - |numframes| is the number of picture frames in the file. 64 // - |numframes| is the number of picture frames in the file.
74 // - |numNALUs| is the number of NAL units in the stream. 65 // - |numNALUs| is the number of NAL units in the stream.
75 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds 66 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds
76 // expected to be achieved with and without rendering to the screen, resp. 67 // expected to be achieved with and without rendering to the screen, resp.
77 // (the latter tests just decode speed). 68 // (the latter tests just decode speed).
78 // - |profile| is the media::H264Profile set during Initialization. 69 // - |profile| is the media::H264Profile set during Initialization.
79 // An empty value for a numeric field means "ignore". 70 // An empty value for a numeric field means "ignore".
71 #if defined(OS_MACOSX)
72 const FilePath::CharType* test_video_data =
73 FILE_PATH_LITERAL("test-25fps_high.h264:1280:720:249:252:50:175:4");
74 #else
80 const FilePath::CharType* test_video_data = 75 const FilePath::CharType* test_video_data =
81 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1"); 76 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1");
77 #endif
78
79 // AAVC data required to initialize the H.264 video decoder.
80 const uint8_t MP4_EXTRA_DATA[] = {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Hopefully you can drop this in favor of H264Parser
81 0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x19,
82 0x67, 0x64, 0x00, 0x1f, 0xac, 0x34, 0xec, 0x05,
83 0x00, 0x5b, 0xa1, 0x00, 0x00, 0x03, 0x00, 0x01,
84 0x00, 0x00, 0x03, 0x00, 0x32, 0x0f, 0x18, 0x31,
85 0x38, 0x01, 0x00, 0x05, 0x68, 0xef, 0xb2, 0xc8,
86 0xb0,
87 };
82 88
83 // Parse |data| into its constituent parts and set the various output fields 89 // Parse |data| into its constituent parts and set the various output fields
84 // accordingly. CHECK-fails on unexpected or missing required data. 90 // accordingly. CHECK-fails on unexpected or missing required data.
85 // Unspecified optional fields are set to -1. 91 // Unspecified optional fields are set to -1.
86 void ParseTestVideoData(FilePath::StringType data, 92 void ParseTestVideoData(FilePath::StringType data,
87 FilePath::StringType* file_name, 93 FilePath::StringType* file_name,
88 int* width, int* height, 94 int* width, int* height,
89 int* num_frames, 95 int* num_frames,
90 int* num_NALUs, 96 int* num_NALUs,
91 int* min_fps_render, 97 int* min_fps_render,
(...skipping 16 matching lines...) Expand all
108 if (!elements[4].empty()) 114 if (!elements[4].empty())
109 CHECK(base::StringToInt(elements[4], num_NALUs)); 115 CHECK(base::StringToInt(elements[4], num_NALUs));
110 if (!elements[5].empty()) 116 if (!elements[5].empty())
111 CHECK(base::StringToInt(elements[5], min_fps_render)); 117 CHECK(base::StringToInt(elements[5], min_fps_render));
112 if (!elements[6].empty()) 118 if (!elements[6].empty())
113 CHECK(base::StringToInt(elements[6], min_fps_no_render)); 119 CHECK(base::StringToInt(elements[6], min_fps_no_render));
114 if (!elements[7].empty()) 120 if (!elements[7].empty())
115 CHECK(base::StringToInt(elements[7], profile)); 121 CHECK(base::StringToInt(elements[7], profile));
116 } 122 }
117 123
118 // Provides functionality for managing EGL, GLES2 and UI resources.
119 // This class is not thread safe and thus all the methods of this class
120 // (except for ctor/dtor) ensure they're being run on a single thread.
121 class RenderingHelper {
122 public:
123 RenderingHelper();
124 ~RenderingHelper();
125
126 // Initialize all structures to prepare to render to one or more windows of
127 // the specified dimensions. CHECK-fails if any initialization step fails.
128 // After this returns, texture creation and rendering can be requested. This
129 // method can be called multiple times, in which case all previously-acquired
130 // resources and initializations are discarded. If |suppress_swap_to_display|
131 // then all the usual work is done, except for the final swap of the EGL
132 // surface to the display. This cuts test times over 50% so is worth doing
133 // when testing non-rendering-related aspects.
134 void Initialize(bool suppress_swap_to_display, int num_windows, int width,
135 int height, base::WaitableEvent* done);
136
137 // Undo the effects of Initialize() and signal |*done|.
138 void UnInitialize(base::WaitableEvent* done);
139
140 // Return a newly-created GLES2 texture id rendering to a specific window, and
141 // signal |*done|.
142 void CreateTexture(int window_id, GLuint* texture_id,
143 base::WaitableEvent* done);
144
145 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|).
146 void RenderTexture(GLuint texture_id);
147
148 // Delete |texture_id|.
149 void DeleteTexture(GLuint texture_id);
150
151 // Platform specific Init/Uninit.
152 void PlatformInitialize();
153 void PlatformUnInitialize();
154
155 // Platform specific window creation.
156 EGLNativeWindowType PlatformCreateWindow(int top_left_x, int top_left_y);
157
158 // Platform specific display surface returned here.
159 EGLDisplay PlatformGetDisplay();
160
161 EGLDisplay egl_display() { return egl_display_; }
162
163 EGLContext egl_context() { return egl_context_; }
164
165 MessageLoop* message_loop() { return message_loop_; }
166
167 protected:
168 void Clear();
169
170 // We ensure all operations are carried out on the same thread by remembering
171 // where we were Initialized.
172 MessageLoop* message_loop_;
173 int width_;
174 int height_;
175 bool suppress_swap_to_display_;
176
177 EGLDisplay egl_display_;
178 EGLContext egl_context_;
179 std::vector<EGLSurface> egl_surfaces_;
180 std::map<GLuint, int> texture_id_to_surface_index_;
181
182 #if defined(OS_WIN)
183 std::vector<HWND> windows_;
184 #else // OS_WIN
185 Display* x_display_;
186 std::vector<Window> x_windows_;
187 #endif // OS_WIN
188 };
189
190 RenderingHelper::RenderingHelper() {
191 Clear();
192 }
193
194 RenderingHelper::~RenderingHelper() {
195 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
196 Clear();
197 }
198
199 // Helper for Shader creation.
200 static void CreateShader(
201 GLuint program, GLenum type, const char* source, int size) {
202 GLuint shader = glCreateShader(type);
203 glShaderSource(shader, 1, &source, &size);
204 glCompileShader(shader);
205 int result = GL_FALSE;
206 glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
207 if (!result) {
208 char log[4096];
209 glGetShaderInfoLog(shader, arraysize(log), NULL, log);
210 LOG(FATAL) << log;
211 }
212 glAttachShader(program, shader);
213 glDeleteShader(shader);
214 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
215 }
216
217 void RenderingHelper::Initialize(
218 bool suppress_swap_to_display,
219 int num_windows,
220 int width,
221 int height,
222 base::WaitableEvent* done) {
223 // Use width_ != 0 as a proxy for the class having already been
224 // Initialize()'d, and UnInitialize() before continuing.
225 if (width_) {
226 base::WaitableEvent done(false, false);
227 UnInitialize(&done);
228 done.Wait();
229 }
230
231 suppress_swap_to_display_ = suppress_swap_to_display;
232 CHECK_GT(width, 0);
233 CHECK_GT(height, 0);
234 width_ = width;
235 height_ = height;
236 message_loop_ = MessageLoop::current();
237 CHECK_GT(num_windows, 0);
238
239 PlatformInitialize();
240
241 egl_display_ = PlatformGetDisplay();
242
243 EGLint major;
244 EGLint minor;
245 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
246 static EGLint rgba8888[] = {
247 EGL_RED_SIZE, 8,
248 EGL_GREEN_SIZE, 8,
249 EGL_BLUE_SIZE, 8,
250 EGL_ALPHA_SIZE, 8,
251 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
252 EGL_NONE,
253 };
254 EGLConfig egl_config;
255 int num_configs;
256 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
257 << eglGetError();
258 CHECK_GE(num_configs, 1);
259 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
260 egl_context_ = eglCreateContext(
261 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
262 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();
263
264 // Per-window/surface X11 & EGL initialization.
265 for (int i = 0; i < num_windows; ++i) {
266 // Arrange X windows whimsically, with some padding.
267 int top_left_x = (width + 20) * (i % 4);
268 int top_left_y = (height + 12) * (i % 3);
269
270 EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y);
271 EGLSurface egl_surface =
272 eglCreateWindowSurface(egl_display_, egl_config, window, NULL);
273 egl_surfaces_.push_back(egl_surface);
274 CHECK_NE(egl_surface, EGL_NO_SURFACE);
275 }
276 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0],
277 egl_surfaces_[0], egl_context_)) << eglGetError();
278
279 static const float kVertices[] =
280 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
281 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
282 static const char kVertexShader[] = STRINGIZE(
283 varying vec2 interp_tc;
284 attribute vec4 in_pos;
285 attribute vec2 in_tc;
286 void main() {
287 interp_tc = in_tc;
288 gl_Position = in_pos;
289 }
290 );
291 static const char kFragmentShaderEgl[] = STRINGIZE(
292 precision mediump float;
293 varying vec2 interp_tc;
294 uniform sampler2D tex;
295 void main() {
296 gl_FragColor = texture2D(tex, interp_tc);
297 }
298 );
299 GLuint program = glCreateProgram();
300 CreateShader(program, GL_VERTEX_SHADER,
301 kVertexShader, arraysize(kVertexShader));
302 CreateShader(program, GL_FRAGMENT_SHADER,
303 kFragmentShaderEgl, arraysize(kFragmentShaderEgl));
304 glLinkProgram(program);
305 int result = GL_FALSE;
306 glGetProgramiv(program, GL_LINK_STATUS, &result);
307 if (!result) {
308 char log[4096];
309 glGetShaderInfoLog(program, arraysize(log), NULL, log);
310 LOG(FATAL) << log;
311 }
312 glUseProgram(program);
313 glDeleteProgram(program);
314
315 glUniform1i(glGetUniformLocation(program, "tex"), 0);
316 int pos_location = glGetAttribLocation(program, "in_pos");
317 glEnableVertexAttribArray(pos_location);
318 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
319 int tc_location = glGetAttribLocation(program, "in_tc");
320 glEnableVertexAttribArray(tc_location);
321 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
322 kTextureCoordsEgl);
323 done->Signal();
324 }
325
326 void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
327 CHECK_EQ(MessageLoop::current(), message_loop_);
328 CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
329 EGL_NO_CONTEXT)) << eglGetError();
330 CHECK(eglDestroyContext(egl_display_, egl_context_));
331 for (size_t i = 0; i < egl_surfaces_.size(); ++i)
332 CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
333 CHECK(eglTerminate(egl_display_));
334 Clear();
335 done->Signal();
336 }
337
338 void RenderingHelper::Clear() {
339 suppress_swap_to_display_ = false;
340 width_ = 0;
341 height_ = 0;
342 texture_id_to_surface_index_.clear();
343 message_loop_ = NULL;
344 egl_display_ = EGL_NO_DISPLAY;
345 egl_context_ = EGL_NO_CONTEXT;
346 egl_surfaces_.clear();
347 PlatformUnInitialize();
348 }
349
350 void RenderingHelper::CreateTexture(int window_id, GLuint* texture_id,
351 base::WaitableEvent* done) {
352 if (MessageLoop::current() != message_loop_) {
353 message_loop_->PostTask(
354 FROM_HERE,
355 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this),
356 window_id, texture_id, done));
357 return;
358 }
359 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
360 egl_surfaces_[window_id], egl_context_))
361 << eglGetError();
362 glGenTextures(1, texture_id);
363 glBindTexture(GL_TEXTURE_2D, *texture_id);
364 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA,
365 GL_UNSIGNED_BYTE, NULL);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
368 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures.
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
370 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
371 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
372 CHECK(texture_id_to_surface_index_.insert(
373 std::make_pair(*texture_id, window_id)).second);
374 done->Signal();
375 }
376
377 void RenderingHelper::RenderTexture(GLuint texture_id) {
378 CHECK_EQ(MessageLoop::current(), message_loop_);
379 glActiveTexture(GL_TEXTURE0);
380 glBindTexture(GL_TEXTURE_2D, texture_id);
381 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
382 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
383 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
384 if (!suppress_swap_to_display_) {
385 int window_id = texture_id_to_surface_index_[texture_id];
386 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
387 egl_surfaces_[window_id], egl_context_))
388 << eglGetError();
389 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]);
390 }
391 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
392 }
393
394 void RenderingHelper::DeleteTexture(GLuint texture_id) {
395 glDeleteTextures(1, &texture_id);
396 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
397 }
398
399 #if defined(OS_WIN)
400 void RenderingHelper::PlatformInitialize() {}
401
402 void RenderingHelper::PlatformUnInitialize() {
403 for (size_t i = 0; i < windows_.size(); ++i) {
404 DestroyWindow(windows_[i]);
405 }
406 windows_.clear();
407 }
408
409 EGLNativeWindowType RenderingHelper::PlatformCreateWindow(
410 int top_left_x, int top_left_y) {
411 HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest",
412 WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x,
413 top_left_y, width_, height_, NULL, NULL, NULL,
414 NULL);
415 CHECK(window != NULL);
416 windows_.push_back(window);
417 return window;
418 }
419
420 EGLDisplay RenderingHelper::PlatformGetDisplay() {
421 return eglGetDisplay(EGL_DEFAULT_DISPLAY);
422 }
423
424 #else // OS_WIN
425
426 void RenderingHelper::PlatformInitialize() {
427 CHECK(x_display_ = base::MessagePumpForUI::GetDefaultXDisplay());
428 }
429
430 void RenderingHelper::PlatformUnInitialize() {
431 // Destroy resources acquired in Initialize, in reverse-acquisition order.
432 for (size_t i = 0; i < x_windows_.size(); ++i) {
433 CHECK(XUnmapWindow(x_display_, x_windows_[i]));
434 CHECK(XDestroyWindow(x_display_, x_windows_[i]));
435 }
436 // Mimic newly created object.
437 x_display_ = NULL;
438 x_windows_.clear();
439 }
440
441 EGLDisplay RenderingHelper::PlatformGetDisplay() {
442 return eglGetDisplay(x_display_);
443 }
444
445 EGLNativeWindowType RenderingHelper::PlatformCreateWindow(int top_left_x,
446 int top_left_y) {
447 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
448
449 XSetWindowAttributes window_attributes;
450 window_attributes.background_pixel =
451 BlackPixel(x_display_, DefaultScreen(x_display_));
452 window_attributes.override_redirect = true;
453
454 Window x_window = XCreateWindow(
455 x_display_, DefaultRootWindow(x_display_),
456 top_left_x, top_left_y, width_, height_,
457 0 /* border width */,
458 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
459 (CWBackPixel | CWOverrideRedirect), &window_attributes);
460 x_windows_.push_back(x_window);
461 XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest");
462 XSelectInput(x_display_, x_window, ExposureMask);
463 XMapWindow(x_display_, x_window);
464 return x_window;
465 }
466
467 #endif // OS_WIN
468
469 // State of the EglRenderingVDAClient below. Order matters here as the test 124 // State of the EglRenderingVDAClient below. Order matters here as the test
470 // makes assumptions about it. 125 // makes assumptions about it.
471 enum ClientState { 126 enum ClientState {
472 CS_CREATED, 127 CS_CREATED,
473 CS_DECODER_SET, 128 CS_DECODER_SET,
474 CS_INITIALIZED, 129 CS_INITIALIZED,
475 CS_FLUSHING, 130 CS_FLUSHING,
476 CS_FLUSHED, 131 CS_FLUSHED,
477 CS_DONE, 132 CS_DONE,
478 CS_RESETTING, 133 CS_RESETTING,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 // last play-through (governed by |num_play_throughs|). 199 // last play-through (governed by |num_play_throughs|).
545 EglRenderingVDAClient(RenderingHelper* rendering_helper, 200 EglRenderingVDAClient(RenderingHelper* rendering_helper,
546 int rendering_window_id, 201 int rendering_window_id,
547 ClientStateNotification* note, 202 ClientStateNotification* note,
548 const std::string& encoded_data, 203 const std::string& encoded_data,
549 int num_NALUs_per_decode, 204 int num_NALUs_per_decode,
550 int num_in_flight_decodes, 205 int num_in_flight_decodes,
551 int num_play_throughs, 206 int num_play_throughs,
552 int reset_after_frame_num, 207 int reset_after_frame_num,
553 int delete_decoder_state, 208 int delete_decoder_state,
209 int frame_width,
210 int frame_height,
554 int profile); 211 int profile);
555 virtual ~EglRenderingVDAClient(); 212 virtual ~EglRenderingVDAClient();
556 void CreateDecoder(); 213 void CreateDecoder();
557 214
558 // VideoDecodeAccelerator::Client implementation. 215 // VideoDecodeAccelerator::Client implementation.
559 // The heart of the Client. 216 // The heart of the Client.
560 virtual void ProvidePictureBuffers( 217 virtual void ProvidePictureBuffers(
561 uint32 requested_num_of_buffers, 218 uint32 requested_num_of_buffers,
562 const gfx::Size& dimensions); 219 const gfx::Size& dimensions);
563 virtual void DismissPictureBuffer(int32 picture_buffer_id); 220 virtual void DismissPictureBuffer(int32 picture_buffer_id);
564 virtual void PictureReady(const media::Picture& picture); 221 virtual void PictureReady(const media::Picture& picture);
565 // Simple state changes. 222 // Simple state changes.
566 virtual void NotifyInitializeDone(); 223 virtual void NotifyInitializeDone();
567 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id); 224 virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id);
568 virtual void NotifyFlushDone(); 225 virtual void NotifyFlushDone();
569 virtual void NotifyResetDone(); 226 virtual void NotifyResetDone();
570 virtual void NotifyError(VideoDecodeAccelerator::Error error); 227 virtual void NotifyError(VideoDecodeAccelerator::Error error);
571 228
572 // Simple getters for inspecting the state of the Client. 229 // Simple getters for inspecting the state of the Client.
573 ClientState state() { return state_; } 230 ClientState state() { return state_; }
574 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } 231 int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
575 int num_decoded_frames() { return num_decoded_frames_; } 232 int num_decoded_frames() { return num_decoded_frames_; }
576 EGLDisplay egl_display() { return rendering_helper_->egl_display(); }
577 EGLContext egl_context() { return rendering_helper_->egl_context(); }
578 double frames_per_second(); 233 double frames_per_second();
579 bool decoder_deleted() { return !decoder_; } 234 bool decoder_deleted() { return !decoder_; }
580 235
581 private: 236 private:
582 typedef std::map<int, media::PictureBuffer*> PictureBufferById; 237 typedef std::map<int, media::PictureBuffer*> PictureBufferById;
583 238
584 void SetState(ClientState new_state); 239 void SetState(ClientState new_state);
585 240
586 // Delete the associated OMX decoder helper. 241 // Delete the associated OMX decoder helper.
587 void DeleteDecoder(); 242 void DeleteDecoder();
(...skipping 18 matching lines...) Expand all
606 std::set<int> outstanding_texture_ids_; 261 std::set<int> outstanding_texture_ids_;
607 int remaining_play_throughs_; 262 int remaining_play_throughs_;
608 int reset_after_frame_num_; 263 int reset_after_frame_num_;
609 int delete_decoder_state_; 264 int delete_decoder_state_;
610 ClientState state_; 265 ClientState state_;
611 int num_decoded_frames_; 266 int num_decoded_frames_;
612 int num_done_bitstream_buffers_; 267 int num_done_bitstream_buffers_;
613 PictureBufferById picture_buffers_by_id_; 268 PictureBufferById picture_buffers_by_id_;
614 base::TimeTicks initialize_done_ticks_; 269 base::TimeTicks initialize_done_ticks_;
615 base::TimeTicks last_frame_delivered_ticks_; 270 base::TimeTicks last_frame_delivered_ticks_;
271 int frame_width_;
272 int frame_height_;
616 int profile_; 273 int profile_;
617 }; 274 };
618 275
619 EglRenderingVDAClient::EglRenderingVDAClient( 276 EglRenderingVDAClient::EglRenderingVDAClient(
620 RenderingHelper* rendering_helper, 277 RenderingHelper* rendering_helper,
621 int rendering_window_id, 278 int rendering_window_id,
622 ClientStateNotification* note, 279 ClientStateNotification* note,
623 const std::string& encoded_data, 280 const std::string& encoded_data,
624 int num_NALUs_per_decode, 281 int num_NALUs_per_decode,
625 int num_in_flight_decodes, 282 int num_in_flight_decodes,
626 int num_play_throughs, 283 int num_play_throughs,
627 int reset_after_frame_num, 284 int reset_after_frame_num,
628 int delete_decoder_state, 285 int delete_decoder_state,
286 int frame_width,
287 int frame_height,
629 int profile) 288 int profile)
630 : rendering_helper_(rendering_helper), 289 : rendering_helper_(rendering_helper),
631 rendering_window_id_(rendering_window_id), 290 rendering_window_id_(rendering_window_id),
632 encoded_data_(encoded_data), num_NALUs_per_decode_(num_NALUs_per_decode), 291 encoded_data_(encoded_data), num_NALUs_per_decode_(num_NALUs_per_decode),
633 num_in_flight_decodes_(num_in_flight_decodes), outstanding_decodes_(0), 292 num_in_flight_decodes_(num_in_flight_decodes), outstanding_decodes_(0),
634 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0), 293 encoded_data_next_pos_to_decode_(0), next_bitstream_buffer_id_(0),
635 note_(note), 294 note_(note),
636 remaining_play_throughs_(num_play_throughs), 295 remaining_play_throughs_(num_play_throughs),
637 reset_after_frame_num_(reset_after_frame_num), 296 reset_after_frame_num_(reset_after_frame_num),
638 delete_decoder_state_(delete_decoder_state), 297 delete_decoder_state_(delete_decoder_state),
639 state_(CS_CREATED), 298 state_(CS_CREATED),
640 num_decoded_frames_(0), num_done_bitstream_buffers_(0), 299 num_decoded_frames_(0), num_done_bitstream_buffers_(0),
300 frame_width_(frame_width),
301 frame_height_(frame_height),
641 profile_(profile) { 302 profile_(profile) {
642 CHECK_GT(num_NALUs_per_decode, 0); 303 CHECK_GT(num_NALUs_per_decode, 0);
643 CHECK_GT(num_in_flight_decodes, 0); 304 CHECK_GT(num_in_flight_decodes, 0);
644 CHECK_GT(num_play_throughs, 0); 305 CHECK_GT(num_play_throughs, 0);
645 } 306 }
646 307
647 EglRenderingVDAClient::~EglRenderingVDAClient() { 308 EglRenderingVDAClient::~EglRenderingVDAClient() {
648 DeleteDecoder(); // Clean up in case of expected error. 309 DeleteDecoder(); // Clean up in case of expected error.
649 CHECK(decoder_deleted()); 310 CHECK(decoder_deleted());
650 STLDeleteValues(&picture_buffers_by_id_); 311 STLDeleteValues(&picture_buffers_by_id_);
651 SetState(CS_DESTROYED); 312 SetState(CS_DESTROYED);
652 } 313 }
653 314
654 void EglRenderingVDAClient::CreateDecoder() { 315 void EglRenderingVDAClient::CreateDecoder() {
655 CHECK(decoder_deleted()); 316 CHECK(decoder_deleted());
656 #if defined(OS_WIN) 317 #if defined(OS_WIN)
657 scoped_refptr<DXVAVideoDecodeAccelerator> decoder = 318 scoped_refptr<DXVAVideoDecodeAccelerator> decoder =
658 new DXVAVideoDecodeAccelerator(this); 319 new DXVAVideoDecodeAccelerator(this);
659 #else // OS_WIN 320 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
660 scoped_refptr<OmxVideoDecodeAccelerator> decoder = 321 scoped_refptr<OmxVideoDecodeAccelerator> decoder =
661 new OmxVideoDecodeAccelerator(this); 322 new OmxVideoDecodeAccelerator(this);
662 decoder->SetEglState(egl_display(), egl_context()); 323 decoder->SetEglState(
324 static_cast<EGLDisplay>(rendering_helper->GetGLDisplay()),
325 static_cast<EGLContext>(rendering_helper->GetGLContext()));
326 #elif defined(OS_MACOSX)
327 scoped_refptr<MacVideoDecodeAccelerator> decoder =
328 new MacVideoDecodeAccelerator(this);
329 decoder->SetGLContext(rendering_helper_->GetGLContext());
330 std::vector<uint8_t> avc_data(MP4_EXTRA_DATA,
331 MP4_EXTRA_DATA + arraysize(MP4_EXTRA_DATA));
332 if (!decoder->SetConfigInfo(frame_width_, frame_height_, avc_data)) {
333 SetState(CS_ERROR);
334 return;
335 }
663 #endif // OS_WIN 336 #endif // OS_WIN
664 decoder_ = decoder.release(); 337 decoder_ = decoder.release();
665 SetState(CS_DECODER_SET); 338 SetState(CS_DECODER_SET);
666 if (decoder_deleted()) 339 if (decoder_deleted())
667 return; 340 return;
668 341
669 // Configure the decoder. 342 // Configure the decoder.
670 media::VideoCodecProfile profile = media::H264PROFILE_BASELINE; 343 media::VideoCodecProfile profile = media::H264PROFILE_BASELINE;
671 if (profile_ != -1) 344 if (profile_ != -1)
672 profile = static_cast<media::VideoCodecProfile>(profile_); 345 profile = static_cast<media::VideoCodecProfile>(profile_);
673 CHECK(decoder_->Initialize(profile)); 346 CHECK(decoder_->Initialize(profile));
674 } 347 }
675 348
676 void EglRenderingVDAClient::ProvidePictureBuffers( 349 void EglRenderingVDAClient::ProvidePictureBuffers(
677 uint32 requested_num_of_buffers, 350 uint32 requested_num_of_buffers,
678 const gfx::Size& dimensions) { 351 const gfx::Size& dimensions) {
679 if (decoder_deleted()) 352 if (decoder_deleted())
680 return; 353 return;
681 std::vector<media::PictureBuffer> buffers; 354 std::vector<media::PictureBuffer> buffers;
682 355
683 for (uint32 i = 0; i < requested_num_of_buffers; ++i) { 356 for (uint32 i = 0; i < requested_num_of_buffers; ++i) {
684 uint32 id = picture_buffers_by_id_.size(); 357 uint32 id = picture_buffers_by_id_.size();
685 GLuint texture_id; 358 uint32 texture_id;
686 base::WaitableEvent done(false, false); 359 base::WaitableEvent done(false, false);
687 rendering_helper_->CreateTexture(rendering_window_id_, &texture_id, &done); 360 rendering_helper_->CreateTexture(rendering_window_id_, &texture_id, &done);
688 done.Wait(); 361 done.Wait();
689 CHECK(outstanding_texture_ids_.insert(texture_id).second); 362 CHECK(outstanding_texture_ids_.insert(texture_id).second);
690 media::PictureBuffer* buffer = 363 media::PictureBuffer* buffer =
691 new media::PictureBuffer(id, dimensions, texture_id); 364 new media::PictureBuffer(id, dimensions, texture_id);
692 CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second); 365 CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
693 buffers.push_back(*buffer); 366 buffers.push_back(*buffer);
694 } 367 }
695 decoder_->AssignPictureBuffers(buffers); 368 decoder_->AssignPictureBuffers(buffers);
696 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
697 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
698 } 369 }
699 370
700 void EglRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { 371 void EglRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
701 PictureBufferById::iterator it = 372 PictureBufferById::iterator it =
702 picture_buffers_by_id_.find(picture_buffer_id); 373 picture_buffers_by_id_.find(picture_buffer_id);
703 CHECK(it != picture_buffers_by_id_.end()); 374 CHECK(it != picture_buffers_by_id_.end());
704 CHECK_EQ(outstanding_texture_ids_.erase(it->second->texture_id()), 1U); 375 CHECK_EQ(outstanding_texture_ids_.erase(it->second->texture_id()), 1U);
705 rendering_helper_->DeleteTexture(it->second->texture_id()); 376 rendering_helper_->DeleteTexture(it->second->texture_id());
706 delete it->second; 377 delete it->second;
707 picture_buffers_by_id_.erase(it); 378 picture_buffers_by_id_.erase(it);
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and 528 // Populate the shared memory buffer w/ the NALU, duplicate its handle, and
858 // hand it off to the decoder. 529 // hand it off to the decoder.
859 base::SharedMemory shm; 530 base::SharedMemory shm;
860 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos)) 531 CHECK(shm.CreateAndMapAnonymous(end_pos - start_pos))
861 << start_pos << ", " << end_pos; 532 << start_pos << ", " << end_pos;
862 memcpy(shm.memory(), encoded_data_.data() + start_pos, end_pos - start_pos); 533 memcpy(shm.memory(), encoded_data_.data() + start_pos, end_pos - start_pos);
863 base::SharedMemoryHandle dup_handle; 534 base::SharedMemoryHandle dup_handle;
864 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle)); 535 CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle));
865 media::BitstreamBuffer bitstream_buffer( 536 media::BitstreamBuffer bitstream_buffer(
866 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos); 537 next_bitstream_buffer_id_++, dup_handle, end_pos - start_pos);
867 decoder_->Decode(bitstream_buffer); 538 // Avoid becoming reentrant by decoding on next event cycle.
539 MessageLoop::current()->PostTask(
540 FROM_HERE,
541 base::Bind(&VideoDecodeAccelerator::Decode, decoder_, bitstream_buffer));
542
868 ++outstanding_decodes_; 543 ++outstanding_decodes_;
869 encoded_data_next_pos_to_decode_ = end_pos; 544 encoded_data_next_pos_to_decode_ = end_pos;
870 545
871 if (!remaining_play_throughs_ && 546 if (!remaining_play_throughs_ &&
872 -delete_decoder_state_ == next_bitstream_buffer_id_) { 547 -delete_decoder_state_ == next_bitstream_buffer_id_) {
873 DeleteDecoder(); 548 DeleteDecoder();
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 I think you missed my comment: Should this be post
874 } 549 }
875 } 550 }
876 551
877 double EglRenderingVDAClient::frames_per_second() { 552 double EglRenderingVDAClient::frames_per_second() {
878 base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_; 553 base::TimeDelta delta = last_frame_delivered_ticks_ - initialize_done_ticks_;
879 if (delta.InSecondsF() == 0) 554 if (delta.InSecondsF() == 0)
880 return 0; 555 return 0;
881 return num_decoded_frames_ / delta.InSecondsF(); 556 return num_decoded_frames_ / delta.InSecondsF();
882 } 557 }
883 558
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 base::Thread rendering_thread("EglRenderingVDAClientThread"); 631 base::Thread rendering_thread("EglRenderingVDAClientThread");
957 base::Thread::Options options; 632 base::Thread::Options options;
958 options.message_loop_type = MessageLoop::TYPE_DEFAULT; 633 options.message_loop_type = MessageLoop::TYPE_DEFAULT;
959 #if defined(OS_WIN) 634 #if defined(OS_WIN)
960 // For windows the decoding thread initializes the media foundation decoder 635 // For windows the decoding thread initializes the media foundation decoder
961 // which uses COM. We need the thread to be a UI thread. 636 // which uses COM. We need the thread to be a UI thread.
962 options.message_loop_type = MessageLoop::TYPE_UI; 637 options.message_loop_type = MessageLoop::TYPE_UI;
963 #endif // OS_WIN 638 #endif // OS_WIN
964 639
965 rendering_thread.StartWithOptions(options); 640 rendering_thread.StartWithOptions(options);
966 RenderingHelper rendering_helper; 641 scoped_ptr<RenderingHelper> rendering_helper(RenderingHelper::Create());
967 642
968 base::WaitableEvent done(false, false); 643 base::WaitableEvent done(false, false);
969 rendering_thread.message_loop()->PostTask( 644 rendering_thread.message_loop()->PostTask(
970 FROM_HERE, 645 FROM_HERE,
971 base::Bind(&RenderingHelper::Initialize, 646 base::Bind(&RenderingHelper::Initialize,
972 base::Unretained(&rendering_helper), 647 base::Unretained(rendering_helper.get()),
973 suppress_swap_to_display, num_concurrent_decoders, 648 suppress_swap_to_display, num_concurrent_decoders,
974 frame_width, frame_height, &done)); 649 frame_width, frame_height, &done));
975 done.Wait(); 650 done.Wait();
976 651
977 // First kick off all the decoders. 652 // First kick off all the decoders.
978 for (size_t index = 0; index < num_concurrent_decoders; ++index) { 653 for (size_t index = 0; index < num_concurrent_decoders; ++index) {
979 ClientStateNotification* note = new ClientStateNotification(); 654 ClientStateNotification* note = new ClientStateNotification();
980 notes[index] = note; 655 notes[index] = note;
981 EglRenderingVDAClient* client = new EglRenderingVDAClient( 656 EglRenderingVDAClient* client = new EglRenderingVDAClient(
982 &rendering_helper, index, 657 rendering_helper.get(), index, note, data_str, num_NALUs_per_decode,
983 note, data_str, num_NALUs_per_decode, 658 num_in_flight_decodes, num_play_throughs, reset_after_frame_num,
984 num_in_flight_decodes, num_play_throughs, 659 delete_decoder_state, frame_width, frame_height, profile);
985 reset_after_frame_num, delete_decoder_state, profile);
986 clients[index] = client; 660 clients[index] = client;
987 661
988 rendering_thread.message_loop()->PostTask( 662 rendering_thread.message_loop()->PostTask(
989 FROM_HERE, 663 FROM_HERE,
990 base::Bind(&EglRenderingVDAClient::CreateDecoder, 664 base::Bind(&EglRenderingVDAClient::CreateDecoder,
991 base::Unretained(client))); 665 base::Unretained(client)));
992 666
993 ASSERT_EQ(note->Wait(), CS_DECODER_SET); 667 ASSERT_EQ(note->Wait(), CS_DECODER_SET);
994 } 668 }
995 // Then wait for all the decodes to finish. 669 // Then wait for all the decodes to finish.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 FROM_HERE, 729 FROM_HERE,
1056 base::Bind(&STLDeleteElements<std::vector<EglRenderingVDAClient*> >, 730 base::Bind(&STLDeleteElements<std::vector<EglRenderingVDAClient*> >,
1057 &clients)); 731 &clients));
1058 rendering_thread.message_loop()->PostTask( 732 rendering_thread.message_loop()->PostTask(
1059 FROM_HERE, 733 FROM_HERE,
1060 base::Bind(&STLDeleteElements<std::vector<ClientStateNotification*> >, 734 base::Bind(&STLDeleteElements<std::vector<ClientStateNotification*> >,
1061 &notes)); 735 &notes));
1062 rendering_thread.message_loop()->PostTask( 736 rendering_thread.message_loop()->PostTask(
1063 FROM_HERE, 737 FROM_HERE,
1064 base::Bind(&RenderingHelper::UnInitialize, 738 base::Bind(&RenderingHelper::UnInitialize,
1065 base::Unretained(&rendering_helper), 739 base::Unretained(rendering_helper.get()),
1066 &done)); 740 &done));
1067 done.Wait(); 741 done.Wait();
1068 rendering_thread.Stop(); 742 rendering_thread.Stop();
1069 }; 743 };
1070 744
1071 // Test that replay after EOS works fine. 745 // Test that replay after EOS works fine.
1072 INSTANTIATE_TEST_CASE_P( 746 INSTANTIATE_TEST_CASE_P(
1073 ReplayAfterEOS, VideoDecodeAcceleratorTest, 747 ReplayAfterEOS, VideoDecodeAcceleratorTest,
1074 ::testing::Values( 748 ::testing::Values(
1075 MakeTuple(1, 1, 1, 4, END_OF_STREAM_RESET, CS_RESET))); 749 MakeTuple(1, 1, 1, 4, END_OF_STREAM_RESET, CS_RESET)));
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1149 823
1150 CommandLine::SwitchMap switches = cmd_line->GetSwitches(); 824 CommandLine::SwitchMap switches = cmd_line->GetSwitches();
1151 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); 825 for (CommandLine::SwitchMap::const_iterator it = switches.begin();
1152 it != switches.end(); ++it) { 826 it != switches.end(); ++it) {
1153 if (it->first == "test_video_data") { 827 if (it->first == "test_video_data") {
1154 test_video_data = it->second.c_str(); 828 test_video_data = it->second.c_str();
1155 continue; 829 continue;
1156 } 830 }
1157 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; 831 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
1158 } 832 }
833
834 base::ShadowingAtExitManager at_exit_manager;
835 RenderingHelper::InitializePlatform();
836
1159 #if defined(OS_WIN) 837 #if defined(OS_WIN)
1160 base::ShadowingAtExitManager at_exit_manager;
1161 gfx::InitializeGLBindings(gfx::kGLImplementationEGLGLES2);
1162 gfx::GLSurface::InitializeOneOff();
1163 {
1164 // Hack to ensure that EGL extension function pointers are initialized.
1165 scoped_refptr<gfx::GLSurface> surface(
1166 gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)));
1167 scoped_refptr<gfx::GLContext> context(
1168 gfx::GLContext::CreateGLContext(NULL, surface.get(),
1169 gfx::PreferIntegratedGpu));
1170 context->MakeCurrent(surface.get());
1171 }
1172 DXVAVideoDecodeAccelerator::PreSandboxInitialization(); 838 DXVAVideoDecodeAccelerator::PreSandboxInitialization();
1173 #endif // OS_WIN 839 #endif
840
1174 return RUN_ALL_TESTS(); 841 return RUN_ALL_TESTS();
1175 } 842 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698