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

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: remove #if 0 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.
Ami GONE FROM CHROMIUM 2012/05/24 21:30:30 Add TODO to drop this?
sail 2012/05/29 03:45:01 Done.
80 const uint8_t MP4_EXTRA_DATA[] = {
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/24 21:30:30 I think you missed this comment from my last revie
sail 2012/05/29 03:45:01 Ahh sorry, overlooked that. I reverted this chang
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