Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 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" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 26 | 26 |
| 27 #include "base/at_exit.h" | 27 #include "base/at_exit.h" |
| 28 #include "base/bind.h" | 28 #include "base/bind.h" |
| 29 #include "base/command_line.h" | 29 #include "base/command_line.h" |
| 30 #include "base/file_util.h" | 30 #include "base/file_util.h" |
| 31 #include "base/process_util.h" | |
| 31 #include "base/stl_util.h" | 32 #include "base/stl_util.h" |
| 32 #include "base/string_number_conversions.h" | 33 #include "base/string_number_conversions.h" |
| 33 #include "base/string_split.h" | 34 #include "base/string_split.h" |
| 34 #include "base/stringize_macros.h" | 35 #include "base/stringize_macros.h" |
| 35 #include "base/synchronization/condition_variable.h" | 36 #include "base/synchronization/condition_variable.h" |
| 36 #include "base/synchronization/lock.h" | 37 #include "base/synchronization/lock.h" |
| 37 #include "base/synchronization/waitable_event.h" | 38 #include "base/synchronization/waitable_event.h" |
| 38 #include "base/threading/thread.h" | 39 #include "base/threading/thread.h" |
| 40 #include "base/utf_string_conversions.h" | |
| 41 | |
| 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 | |
| 46 #if defined(OS_WIN) | |
| 47 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" | |
| 48 #else // OS_WIN | |
| 39 #include "content/common/gpu/media/omx_video_decode_accelerator.h" | 49 #include "content/common/gpu/media/omx_video_decode_accelerator.h" |
| 50 #endif // defined(OS_WIN) | |
| 51 | |
| 40 #include "third_party/angle/include/EGL/egl.h" | 52 #include "third_party/angle/include/EGL/egl.h" |
| 41 #include "third_party/angle/include/GLES2/gl2.h" | 53 #include "third_party/angle/include/GLES2/gl2.h" |
| 42 | 54 |
| 43 #if !defined(OS_CHROMEOS) || !defined(ARCH_CPU_ARMEL) | |
| 44 #error This test (and OmxVideoDecodeAccelerator) are only supported on cros/ARM! | |
| 45 #endif | |
| 46 | |
| 47 using media::VideoDecodeAccelerator; | 55 using media::VideoDecodeAccelerator; |
| 48 | 56 |
| 49 namespace { | 57 namespace { |
| 50 | 58 |
| 51 // Values optionally filled in from flags; see main() below. | 59 // Values optionally filled in from flags; see main() below. |
| 52 // The syntax of this variable is: | 60 // The syntax of this variable is: |
| 53 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender | 61 // filename:width:height:numframes:numNALUs:minFPSwithRender:minFPSnoRender |
| 54 // where only the first field is required. Value details: | 62 // where only the first field is required. Value details: |
| 55 // - |filename| must be an h264 Annex B (NAL) stream. | 63 // - |filename| must be an h264 Annex B (NAL) stream. |
| 56 // - |width| and |height| are in pixels. | 64 // - |width| and |height| are in pixels. |
| 57 // - |numframes| is the number of picture frames in the file. | 65 // - |numframes| is the number of picture frames in the file. |
| 58 // - |numNALUs| is the number of NAL units in the stream. | 66 // - |numNALUs| is the number of NAL units in the stream. |
| 59 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds | 67 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds |
| 60 // expected to be achieved with and without rendering to the screen, resp. | 68 // expected to be achieved with and without rendering to the screen, resp. |
| 61 // (the latter tests just decode speed). | 69 // (the latter tests just decode speed). |
| 62 // - |profile| is the media::H264Profile set during Initialization. | 70 // - |profile| is the media::H264Profile set during Initialization. |
| 63 // An empty value for a numeric field means "ignore". | 71 // 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"; | 72 const FilePath::CharType* test_video_data = |
| 73 FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1"); | |
| 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(FilePath::StringType data, |
| 70 std::string* file_name, | 79 FilePath::StringType* 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, |
| 75 int* min_fps_no_render, | 84 int* min_fps_no_render, |
| 76 int* profile) { | 85 int* profile) { |
| 77 std::vector<std::string> elements; | 86 std::vector<FilePath::StringType> elements; |
| 78 base::SplitString(data, ':', &elements); | 87 base::SplitString(data, ':', &elements); |
| 79 CHECK_GE(elements.size(), 1U) << data; | 88 CHECK_GE(elements.size(), 1U) << data; |
| 80 CHECK_LE(elements.size(), 8U) << data; | 89 CHECK_LE(elements.size(), 8U) << data; |
| 81 *file_name = elements[0]; | 90 *file_name = elements[0]; |
| 82 *width = *height = *num_frames = *num_NALUs = -1; | 91 *width = *height = *num_frames = *num_NALUs = -1; |
| 83 *min_fps_render = *min_fps_no_render = -1; | 92 *min_fps_render = *min_fps_no_render = -1; |
| 84 *profile = -1; | 93 *profile = -1; |
| 85 if (!elements[1].empty()) | 94 if (!elements[1].empty()) |
| 86 CHECK(base::StringToInt(elements[1], width)); | 95 CHECK(base::StringToInt(elements[1], width)); |
| 87 if (!elements[2].empty()) | 96 if (!elements[2].empty()) |
| 88 CHECK(base::StringToInt(elements[2], height)); | 97 CHECK(base::StringToInt(elements[2], height)); |
| 89 if (!elements[3].empty()) | 98 if (!elements[3].empty()) |
| 90 CHECK(base::StringToInt(elements[3], num_frames)); | 99 CHECK(base::StringToInt(elements[3], num_frames)); |
| 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 |
| 101 | 110 // Provides base functionality for managing EGL and GLES2 resources. |
| 102 // Helper for managing X11, EGL, and GLES2 resources. Xlib is not thread-safe, | 111 // This class is not thread safe and thus all the methods of this class |
| 103 // and GL state is thread-specific, so all the methods of this class (except for | 112 // (except for ctor/dtor) ensure they're being run on a single thread. |
| 104 // ctor/dtor) ensure they're being run on a single thread. | 113 class RenderingHelperBase { |
| 105 // | |
| 106 // TODO(fischman): consider moving this into media/ if we can de-dup some of the | |
| 107 // code that ends up getting copy/pasted all over the place (esp. the GL setup | |
| 108 // code). | |
| 109 class RenderingHelper { | |
| 110 public: | 114 public: |
| 111 explicit RenderingHelper(); | 115 RenderingHelperBase(); |
| 112 ~RenderingHelper(); | 116 virtual ~RenderingHelperBase(); |
| 113 | 117 |
| 114 // Initialize all structures to prepare to render to one or more windows of | 118 // Initialize all structures to prepare to render to one or more windows of |
| 115 // the specified dimensions. CHECK-fails if any initialization step fails. | 119 // the specified dimensions. CHECK-fails if any initialization step fails. |
| 116 // After this returns, texture creation and rendering can be requested. This | 120 // After this returns, texture creation and rendering can be requested. This |
| 117 // method can be called multiple times, in which case all previously-acquired | 121 // method can be called multiple times, in which case all previously-acquired |
| 118 // resources and initializations are discarded. If |suppress_swap_to_display| | 122 // 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 | 123 // then all the usual work is done, except for the final swap of the EGL |
| 120 // surface to the display. This cuts test times over 50% so is worth doing | 124 // surface to the display. This cuts test times over 50% so is worth doing |
| 121 // when testing non-rendering-related aspects. | 125 // when testing non-rendering-related aspects. |
| 122 void Initialize(bool suppress_swap_to_display, int num_windows, | 126 void Initialize(bool suppress_swap_to_display, int num_windows, int width, |
| 123 int width, int height, base::WaitableEvent* done); | 127 int height, base::WaitableEvent* done); |
| 124 | 128 |
| 125 // Undo the effects of Initialize() and signal |*done|. | 129 // Undo the effects of Initialize() and signal |*done|. |
| 126 void UnInitialize(base::WaitableEvent* done); | 130 void UnInitialize(base::WaitableEvent* done); |
| 127 | 131 |
| 128 // Return a newly-created GLES2 texture id rendering to a specific window, and | 132 // Return a newly-created GLES2 texture id rendering to a specific window, and |
| 129 // signal |*done|. | 133 // signal |*done|. |
| 130 void CreateTexture(int window_id, GLuint* texture_id, | 134 void CreateTexture(int window_id, GLuint* texture_id, |
| 131 base::WaitableEvent* done); | 135 base::WaitableEvent* done); |
| 132 | 136 |
| 133 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|). | 137 // Render |texture_id| to the screen (unless |suppress_swap_to_display_|). |
| 134 void RenderTexture(GLuint texture_id); | 138 void RenderTexture(GLuint texture_id); |
| 135 | 139 |
| 136 // Delete |texture_id|. | 140 // Delete |texture_id|. |
| 137 void DeleteTexture(GLuint texture_id); | 141 void DeleteTexture(GLuint texture_id); |
| 138 | 142 |
| 143 // Platform specific Init/Uninit. | |
| 144 virtual void PlatformInitialize() = 0; | |
| 145 virtual void PlatformUnInitialize() = 0; | |
| 146 | |
| 147 // Platform specific window creation. | |
| 148 virtual EGLNativeWindowType PlatformCreateWindow(int top_left_x, | |
| 149 int top_left_y) = 0; | |
| 150 | |
| 151 // Platform specific display surface returned here. | |
| 152 virtual EGLDisplay PlatformGetDisplay() = 0; | |
| 153 | |
| 139 EGLDisplay egl_display() { return egl_display_; } | 154 EGLDisplay egl_display() { return egl_display_; } |
| 155 | |
| 140 EGLContext egl_context() { return egl_context_; } | 156 EGLContext egl_context() { return egl_context_; } |
| 157 | |
| 141 MessageLoop* message_loop() { return message_loop_; } | 158 MessageLoop* message_loop() { return message_loop_; } |
| 142 | 159 |
| 143 private: | 160 protected: |
| 144 // Zero-out internal state. Helper for ctor & UnInitialize(). | |
| 145 void Clear(); | 161 void Clear(); |
| 146 | 162 |
| 147 bool suppress_swap_to_display_; | 163 // We ensure all operations are carried out on the same thread by remembering |
| 164 // where we were Initialized. | |
| 165 MessageLoop* message_loop_; | |
| 148 int width_; | 166 int width_; |
| 149 int height_; | 167 int height_; |
| 150 Display* x_display_; | 168 bool suppress_swap_to_display_; |
| 151 std::vector<Window> x_windows_; | 169 |
| 152 EGLDisplay egl_display_; | 170 EGLDisplay egl_display_; |
| 153 EGLContext egl_context_; | 171 EGLContext egl_context_; |
| 154 std::vector<EGLSurface> egl_surfaces_; | 172 std::vector<EGLSurface> egl_surfaces_; |
| 155 std::map<GLuint, int> texture_id_to_surface_index_; | 173 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 }; | 174 }; |
| 160 | 175 |
| 161 RenderingHelper::RenderingHelper() { | 176 RenderingHelperBase::RenderingHelperBase() { |
| 162 Clear(); | 177 Clear(); |
| 163 } | 178 } |
| 164 | 179 |
| 165 RenderingHelper::~RenderingHelper() { | 180 RenderingHelperBase::~RenderingHelperBase() { |
| 166 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor."; | 181 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor."; |
| 167 } | 182 Clear(); |
| 168 | |
| 169 void RenderingHelper::Clear() { | |
| 170 suppress_swap_to_display_ = false; | |
| 171 width_ = 0; | |
| 172 height_ = 0; | |
| 173 x_display_ = NULL; | |
| 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 } | 183 } |
| 181 | 184 |
| 182 // Helper for Shader creation. | 185 // Helper for Shader creation. |
| 183 static void CreateShader( | 186 static void CreateShader( |
| 184 GLuint program, GLenum type, const char* source, int size) { | 187 GLuint program, GLenum type, const char* source, int size) { |
| 185 GLuint shader = glCreateShader(type); | 188 GLuint shader = glCreateShader(type); |
| 186 glShaderSource(shader, 1, &source, &size); | 189 glShaderSource(shader, 1, &source, &size); |
| 187 glCompileShader(shader); | 190 glCompileShader(shader); |
| 188 int result = GL_FALSE; | 191 int result = GL_FALSE; |
| 189 glGetShaderiv(shader, GL_COMPILE_STATUS, &result); | 192 glGetShaderiv(shader, GL_COMPILE_STATUS, &result); |
| 190 if (!result) { | 193 if (!result) { |
| 191 char log[4096]; | 194 char log[4096]; |
| 192 glGetShaderInfoLog(shader, arraysize(log), NULL, log); | 195 glGetShaderInfoLog(shader, arraysize(log), NULL, log); |
| 193 LOG(FATAL) << log; | 196 LOG(FATAL) << log; |
| 194 } | 197 } |
| 195 glAttachShader(program, shader); | 198 glAttachShader(program, shader); |
| 196 glDeleteShader(shader); | 199 glDeleteShader(shader); |
| 197 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 200 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 198 } | 201 } |
| 199 | 202 |
| 200 void RenderingHelper::Initialize( | 203 void RenderingHelperBase::Initialize(bool suppress_swap_to_display, |
| 201 bool suppress_swap_to_display, | 204 int num_windows, |
| 202 int num_windows, | 205 int width, |
| 203 int width, int height, | 206 int height, |
| 204 base::WaitableEvent* done) { | 207 base::WaitableEvent* done) { |
| 205 // Use width_ != 0 as a proxy for the class having already been | 208 // Use width_ != 0 as a proxy for the class having already been |
| 206 // Initialize()'d, and UnInitialize() before continuing. | 209 // Initialize()'d, and UnInitialize() before continuing. |
| 207 if (width_) { | 210 if (width_) { |
| 208 base::WaitableEvent done(false, false); | 211 base::WaitableEvent done(false, false); |
| 209 UnInitialize(&done); | 212 UnInitialize(&done); |
| 210 done.Wait(); | 213 done.Wait(); |
| 211 } | 214 } |
| 212 | 215 |
| 213 suppress_swap_to_display_ = suppress_swap_to_display; | 216 suppress_swap_to_display_ = suppress_swap_to_display; |
| 214 CHECK_GT(width, 0); | 217 CHECK_GT(width, 0); |
| 215 CHECK_GT(height, 0); | 218 CHECK_GT(height, 0); |
| 216 width_ = width; | 219 width_ = width; |
| 217 height_ = height; | 220 height_ = height; |
| 218 message_loop_ = MessageLoop::current(); | 221 message_loop_ = MessageLoop::current(); |
| 219 CHECK_GT(num_windows, 0); | 222 CHECK_GT(num_windows, 0); |
| 220 | 223 |
| 221 // Per-display X11 & EGL initialization. | 224 PlatformInitialize(); |
| 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 | 225 |
| 229 egl_display_ = eglGetDisplay(x_display_); | 226 egl_display_ = PlatformGetDisplay(); |
| 227 | |
| 230 EGLint major; | 228 EGLint major; |
| 231 EGLint minor; | 229 EGLint minor; |
| 232 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError(); | 230 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError(); |
| 233 static EGLint rgba8888[] = { | 231 static EGLint rgba8888[] = { |
| 234 EGL_RED_SIZE, 8, | 232 EGL_RED_SIZE, 8, |
| 235 EGL_GREEN_SIZE, 8, | 233 EGL_GREEN_SIZE, 8, |
| 236 EGL_BLUE_SIZE, 8, | 234 EGL_BLUE_SIZE, 8, |
| 237 EGL_ALPHA_SIZE, 8, | 235 EGL_ALPHA_SIZE, 8, |
| 238 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | 236 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| 239 EGL_NONE, | 237 EGL_NONE, |
| 240 }; | 238 }; |
| 241 EGLConfig egl_config; | 239 EGLConfig egl_config; |
| 242 int num_configs; | 240 int num_configs; |
| 243 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) | 241 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) |
| 244 << eglGetError(); | 242 << eglGetError(); |
| 245 CHECK_GE(num_configs, 1); | 243 CHECK_GE(num_configs, 1); |
| 246 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; | 244 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; |
| 247 egl_context_ = eglCreateContext( | 245 egl_context_ = eglCreateContext( |
| 248 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); | 246 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); |
| 249 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError(); | 247 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError(); |
| 250 | 248 |
| 251 // Per-window/surface X11 & EGL initialization. | 249 // Per-window/surface X11 & EGL initialization. |
| 252 for (int i = 0; i < num_windows; ++i) { | 250 for (int i = 0; i < num_windows; ++i) { |
| 253 // Arrange X windows whimsically, with some padding. | 251 // Arrange X windows whimsically, with some padding. |
| 254 int top_left_x = (width + 20) * (i % 4); | 252 int top_left_x = (width + 20) * (i % 4); |
| 255 int top_left_y = (height + 12) * (i % 3); | 253 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 | 254 |
| 255 EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y); | |
| 267 EGLSurface egl_surface = | 256 EGLSurface egl_surface = |
| 268 eglCreateWindowSurface(egl_display_, egl_config, x_window, NULL); | 257 eglCreateWindowSurface(egl_display_, egl_config, window, NULL); |
| 269 egl_surfaces_.push_back(egl_surface); | 258 egl_surfaces_.push_back(egl_surface); |
| 270 CHECK_NE(egl_surface, EGL_NO_SURFACE); | 259 CHECK_NE(egl_surface, EGL_NO_SURFACE); |
| 271 } | 260 } |
| 272 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0], | 261 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0], |
| 273 egl_surfaces_[0], egl_context_)) << eglGetError(); | 262 egl_surfaces_[0], egl_context_)) << eglGetError(); |
| 274 | 263 |
| 275 // GLES2 initialization. Note: This is pretty much copy/pasted from | |
| 276 // media/tools/player_x11/gles_video_renderer.cc, with some simplification | |
| 277 // applied. | |
| 278 static const float kVertices[] = | 264 static const float kVertices[] = |
| 279 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; | 265 { -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, }; | 266 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, }; |
| 281 static const char kVertexShader[] = STRINGIZE( | 267 static const char kVertexShader[] = STRINGIZE( |
| 282 varying vec2 interp_tc; | 268 varying vec2 interp_tc; |
| 283 attribute vec4 in_pos; | 269 attribute vec4 in_pos; |
| 284 attribute vec2 in_tc; | 270 attribute vec2 in_tc; |
| 285 void main() { | 271 void main() { |
| 286 interp_tc = in_tc; | 272 interp_tc = in_tc; |
| 287 gl_Position = in_pos; | 273 gl_Position = in_pos; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 312 glDeleteProgram(program); | 298 glDeleteProgram(program); |
| 313 | 299 |
| 314 glUniform1i(glGetUniformLocation(program, "tex"), 0); | 300 glUniform1i(glGetUniformLocation(program, "tex"), 0); |
| 315 int pos_location = glGetAttribLocation(program, "in_pos"); | 301 int pos_location = glGetAttribLocation(program, "in_pos"); |
| 316 glEnableVertexAttribArray(pos_location); | 302 glEnableVertexAttribArray(pos_location); |
| 317 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); | 303 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); |
| 318 int tc_location = glGetAttribLocation(program, "in_tc"); | 304 int tc_location = glGetAttribLocation(program, "in_tc"); |
| 319 glEnableVertexAttribArray(tc_location); | 305 glEnableVertexAttribArray(tc_location); |
| 320 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, | 306 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
| 321 kTextureCoordsEgl); | 307 kTextureCoordsEgl); |
| 322 | |
| 323 done->Signal(); | 308 done->Signal(); |
| 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(); |
| 320 PlatformUnInitialize(); | |
| 341 done->Signal(); | 321 done->Signal(); |
| 342 } | 322 } |
| 343 | 323 |
| 344 void RenderingHelper::CreateTexture(int window_id, GLuint* texture_id, | 324 void RenderingHelperBase::Clear() { |
| 345 base::WaitableEvent* done) { | 325 suppress_swap_to_display_ = false; |
| 326 width_ = 0; | |
| 327 height_ = 0; | |
| 328 texture_id_to_surface_index_.clear(); | |
| 329 message_loop_ = NULL; | |
| 330 egl_display_ = EGL_NO_DISPLAY; | |
| 331 egl_context_ = EGL_NO_CONTEXT; | |
| 332 egl_surfaces_.clear(); | |
| 333 } | |
| 334 | |
| 335 void RenderingHelperBase::CreateTexture(int window_id, GLuint* texture_id, | |
| 336 base::WaitableEvent* done) { | |
| 346 if (MessageLoop::current() != message_loop_) { | 337 if (MessageLoop::current() != message_loop_) { |
| 347 message_loop_->PostTask( | 338 message_loop_->PostTask( |
| 348 FROM_HERE, | 339 FROM_HERE, |
| 349 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), | 340 base::Bind(&RenderingHelperBase::CreateTexture, base::Unretained(this), |
| 350 window_id, texture_id, done)); | 341 window_id, texture_id, done)); |
| 351 return; | 342 return; |
| 352 } | 343 } |
| 353 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], | 344 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], |
| 354 egl_surfaces_[window_id], egl_context_)) | 345 egl_surfaces_[window_id], egl_context_)) |
| 355 << eglGetError(); | 346 << eglGetError(); |
| 356 glGenTextures(1, texture_id); | 347 glGenTextures(1, texture_id); |
| 357 glBindTexture(GL_TEXTURE_2D, *texture_id); | 348 glBindTexture(GL_TEXTURE_2D, *texture_id); |
| 358 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, | 349 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, |
| 359 GL_UNSIGNED_BYTE, NULL); | 350 GL_UNSIGNED_BYTE, NULL); |
| 360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 351 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 352 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. | 353 // 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); | 354 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); | 355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 365 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 356 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 366 CHECK(texture_id_to_surface_index_.insert( | 357 CHECK(texture_id_to_surface_index_.insert( |
| 367 std::make_pair(*texture_id, window_id)).second); | 358 std::make_pair(*texture_id, window_id)).second); |
| 368 done->Signal(); | 359 done->Signal(); |
| 369 } | 360 } |
| 370 | 361 |
| 371 void RenderingHelper::RenderTexture(GLuint texture_id) { | 362 void RenderingHelperBase::RenderTexture(GLuint texture_id) { |
| 372 CHECK_EQ(MessageLoop::current(), message_loop_); | 363 CHECK_EQ(MessageLoop::current(), message_loop_); |
| 373 glActiveTexture(GL_TEXTURE0); | 364 glActiveTexture(GL_TEXTURE0); |
| 374 glBindTexture(GL_TEXTURE_2D, texture_id); | 365 glBindTexture(GL_TEXTURE_2D, texture_id); |
| 375 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 366 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 376 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 367 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 377 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); | 368 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
| 369 | |
| 378 if (!suppress_swap_to_display_) { | 370 if (!suppress_swap_to_display_) { |
| 379 int window_id = texture_id_to_surface_index_[texture_id]; | 371 int window_id = texture_id_to_surface_index_[texture_id]; |
| 380 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], | 372 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], |
| 381 egl_surfaces_[window_id], egl_context_)) | 373 egl_surfaces_[window_id], egl_context_)) |
| 382 << eglGetError(); | 374 << eglGetError(); |
| 383 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]); | 375 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]); |
| 384 } | 376 } |
| 385 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); | 377 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
| 386 } | 378 } |
| 387 | 379 |
| 388 void RenderingHelper::DeleteTexture(GLuint texture_id) { | 380 void RenderingHelperBase::DeleteTexture(GLuint texture_id) { |
| 389 glDeleteTextures(1, &texture_id); | 381 glDeleteTextures(1, &texture_id); |
| 390 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 382 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 391 } | 383 } |
| 392 | 384 |
| 385 #if defined(OS_WIN) | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
Is the sum-total of the difference between the two
ananta
2011/12/20 02:27:22
Done.
| |
| 386 // Provides Windows specific functionality for managing resources like HWND's | |
| 387 // The OpenGL and GLES management is provided by the RenderingHelperBase class. | |
| 388 class RenderingHelper : public RenderingHelperBase { | |
| 389 public: | |
| 390 RenderingHelper(); | |
| 391 virtual ~RenderingHelper(); | |
| 392 | |
| 393 virtual EGLNativeWindowType PlatformCreateWindow(int top_left_x, | |
| 394 int top_left_y) OVERRIDE; | |
| 395 | |
| 396 virtual EGLDisplay PlatformGetDisplay() OVERRIDE; | |
| 397 | |
| 398 virtual void PlatformInitialize() OVERRIDE {}; | |
| 399 | |
| 400 virtual void PlatformUnInitialize() OVERRIDE; | |
| 401 | |
| 402 private: | |
| 403 std::vector<HWND> windows_; | |
| 404 }; | |
| 405 | |
| 406 RenderingHelper::RenderingHelper() | |
| 407 : windows_(NULL) {} | |
| 408 | |
| 409 RenderingHelper::~RenderingHelper() { | |
| 410 PlatformUnInitialize(); | |
| 411 } | |
| 412 | |
| 413 EGLNativeWindowType RenderingHelper::PlatformCreateWindow( | |
| 414 int top_left_x, int top_left_y) { | |
| 415 HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest", | |
| 416 WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x, | |
| 417 top_left_y, width_, height_, NULL, NULL, NULL, | |
| 418 NULL); | |
| 419 CHECK(window != NULL); | |
| 420 windows_.push_back(window); | |
| 421 return window; | |
| 422 } | |
| 423 | |
| 424 EGLDisplay RenderingHelper::PlatformGetDisplay() { | |
| 425 return eglGetDisplay(EGL_DEFAULT_DISPLAY); | |
| 426 } | |
| 427 | |
| 428 void RenderingHelper::PlatformUnInitialize() { | |
| 429 for (size_t i = 0; i < windows_.size(); ++i) { | |
| 430 DestroyWindow(windows_[i]); | |
| 431 } | |
| 432 windows_.clear(); | |
| 433 } | |
| 434 | |
| 435 #else // OS_WIN | |
| 436 | |
| 437 // Provides X11 specific functionality for managing X11 resources. The OpenGL | |
| 438 // and GLES management is provided by the RenderingHelperBase class. | |
| 439 class RenderingHelper : public RenderingHelperBase { | |
| 440 public: | |
| 441 explicit RenderingHelper(); | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
Drop explicit.
ananta
2011/12/20 02:27:22
This class has not been deleted. Platform specific
| |
| 442 ~RenderingHelper(); | |
| 443 | |
| 444 virtual void Initialize( | |
| 445 bool suppress_swap_to_display, int num_windows, | |
| 446 int width, int height, base::WaitableEvent* done) OVERRIDE; | |
| 447 | |
| 448 virtual void PlatformInitialize() OVERRIDE; | |
| 449 | |
| 450 // Zero-out internal state. | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
indent
ananta
2011/12/20 02:27:22
Class is now gone.
| |
| 451 virtual void PlatformUnInitialize() OVERRIDE; | |
| 452 | |
| 453 virtual EGLNativeWindowType PlatformCreateWindow(int top_left_x, | |
| 454 int top_left_y) OVERRIDE; | |
| 455 | |
| 456 virtual EGLDisplay PlatformGetDisplay() OVERRIDE; | |
| 457 | |
| 458 private: | |
| 459 // Zero-out internal state. Helper for ctor & UnInitialize(). | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
Drop comment?
| |
| 460 | |
| 461 Display* x_display_; | |
| 462 std::vector<Window> x_windows_; | |
| 463 XSetWindowAttributes window_attributes_; | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
This doesn't need to be a class member (it can jus
ananta
2011/12/20 02:27:22
Done.
| |
| 464 }; | |
| 465 | |
| 466 RenderingHelper::RenderingHelper() { | |
| 467 PlatformUnInitialize(); | |
| 468 } | |
| 469 | |
| 470 RenderingHelper::~RenderingHelper() { | |
| 471 } | |
| 472 | |
| 473 void RenderingHelper::PlatformInitialize() { | |
| 474 CHECK(x_display_ = XOpenDisplay(NULL)); | |
| 475 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_)); | |
| 476 window_attributes_.background_pixel = | |
| 477 BlackPixel(x_display_, DefaultScreen(x_display_)); | |
| 478 window_attributes_.override_redirect = true; | |
| 479 } | |
| 480 | |
| 481 void RenderingHelper::PlatformUnInitialize() { | |
| 482 // Destroy resources acquired in Initialize, in reverse-acquisition order. | |
| 483 for (size_t i = 0; i < x_windows_.size(); ++i) { | |
| 484 CHECK(XUnmapWindow(x_display_, x_windows_[i])); | |
| 485 CHECK(XDestroyWindow(x_display_, x_windows_[i])); | |
| 486 } | |
| 487 // Mimic newly created object. | |
| 488 x_display_ = NULL; | |
| 489 x_windows_.clear(); | |
| 490 memset(&window_attributes_, 0, sizeof(XSetWindowAttributes)); | |
| 491 } | |
| 492 | |
| 493 EGLDisplay RenderingHelper::PlatformGetDisplay() { | |
| 494 return eglGetDisplay(x_display_); | |
| 495 } | |
| 496 | |
| 497 EGLNativeWindowType RenderingHelper::PlatformCreateWindow(int top_left_x, | |
| 498 int top_left_y) { | |
| 499 Window x_window = XCreateWindow( | |
| 500 x_display_, DefaultRootWindow(x_display_), | |
| 501 top_left_x, top_left_y, width_, height_, | |
| 502 0 /* border width */, | |
| 503 depth, CopyFromParent /* class */, CopyFromParent /* visual */, | |
| 504 (CWBackPixel | CWOverrideRedirect), &window_attributes_); | |
| 505 x_windows_.push_back(x_window); | |
| 506 XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest"); | |
| 507 XSelectInput(x_display_, x_window, ExposureMask); | |
| 508 XMapWindow(x_display_, x_window); | |
| 509 return x_window; | |
| 510 } | |
| 511 | |
| 512 #endif // OS_WIN | |
| 513 | |
| 393 // State of the EglRenderingVDAClient below. Order matters here as the test | 514 // State of the EglRenderingVDAClient below. Order matters here as the test |
| 394 // makes assumptions about it. | 515 // makes assumptions about it. |
| 395 enum ClientState { | 516 enum ClientState { |
| 396 CS_CREATED, | 517 CS_CREATED, |
| 397 CS_DECODER_SET, | 518 CS_DECODER_SET, |
| 398 CS_INITIALIZED, | 519 CS_INITIALIZED, |
| 399 CS_FLUSHING, | 520 CS_FLUSHING, |
| 400 CS_FLUSHED, | 521 CS_FLUSHED, |
| 401 CS_DONE, | 522 CS_DONE, |
| 402 CS_RESETTING, | 523 CS_RESETTING, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 | 637 |
| 517 RenderingHelper* rendering_helper_; | 638 RenderingHelper* rendering_helper_; |
| 518 int rendering_window_id_; | 639 int rendering_window_id_; |
| 519 std::string encoded_data_; | 640 std::string encoded_data_; |
| 520 const int num_NALUs_per_decode_; | 641 const int num_NALUs_per_decode_; |
| 521 const int num_in_flight_decodes_; | 642 const int num_in_flight_decodes_; |
| 522 int outstanding_decodes_; | 643 int outstanding_decodes_; |
| 523 size_t encoded_data_next_pos_to_decode_; | 644 size_t encoded_data_next_pos_to_decode_; |
| 524 int next_bitstream_buffer_id_; | 645 int next_bitstream_buffer_id_; |
| 525 ClientStateNotification* note_; | 646 ClientStateNotification* note_; |
| 526 scoped_refptr<OmxVideoDecodeAccelerator> decoder_; | 647 scoped_refptr<VideoDecodeAccelerator> decoder_; |
| 527 std::set<int> outstanding_texture_ids_; | 648 std::set<int> outstanding_texture_ids_; |
| 528 int reset_after_frame_num_; | 649 int reset_after_frame_num_; |
| 529 int delete_decoder_state_; | 650 int delete_decoder_state_; |
| 530 ClientState state_; | 651 ClientState state_; |
| 531 int num_decoded_frames_; | 652 int num_decoded_frames_; |
| 532 int num_done_bitstream_buffers_; | 653 int num_done_bitstream_buffers_; |
| 533 PictureBufferById picture_buffers_by_id_; | 654 PictureBufferById picture_buffers_by_id_; |
| 534 base::TimeTicks initialize_done_ticks_; | 655 base::TimeTicks initialize_done_ticks_; |
| 535 base::TimeTicks last_frame_delivered_ticks_; | 656 base::TimeTicks last_frame_delivered_ticks_; |
| 536 int profile_; | 657 int profile_; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 562 | 683 |
| 563 EglRenderingVDAClient::~EglRenderingVDAClient() { | 684 EglRenderingVDAClient::~EglRenderingVDAClient() { |
| 564 DeleteDecoder(); // Clean up in case of expected error. | 685 DeleteDecoder(); // Clean up in case of expected error. |
| 565 CHECK(decoder_deleted()); | 686 CHECK(decoder_deleted()); |
| 566 STLDeleteValues(&picture_buffers_by_id_); | 687 STLDeleteValues(&picture_buffers_by_id_); |
| 567 SetState(CS_DESTROYED); | 688 SetState(CS_DESTROYED); |
| 568 } | 689 } |
| 569 | 690 |
| 570 void EglRenderingVDAClient::CreateDecoder() { | 691 void EglRenderingVDAClient::CreateDecoder() { |
| 571 CHECK(decoder_deleted()); | 692 CHECK(decoder_deleted()); |
| 572 decoder_ = new OmxVideoDecodeAccelerator(this); | 693 #if defined(OS_WIN) |
| 573 decoder_->SetEglState(egl_display(), egl_context()); | 694 scoped_refptr<DXVAVideoDecodeAccelerator> decoder; |
| 695 decoder = new DXVAVideoDecodeAccelerator(this, | |
|
Ami GONE FROM CHROMIUM
2011/12/19 22:53:44
assign in previous line
ananta
2011/12/20 02:27:22
Done.
| |
| 696 base::GetCurrentProcessHandle()); | |
| 697 decoder_ = decoder.release(); | |
| 698 #else // OS_WIN | |
| 699 scoped_refptr<OmxVideoDecodeAccelerator> decoder = | |
| 700 new OmxVideoDecodeAccelerator(this); | |
| 701 decoder->SetEglState(egl_display(), egl_context()); | |
| 702 decoder_ = decoder.release(); | |
| 703 #endif // OS_WIN | |
| 574 SetState(CS_DECODER_SET); | 704 SetState(CS_DECODER_SET); |
| 575 if (decoder_deleted()) | 705 if (decoder_deleted()) |
| 576 return; | 706 return; |
| 577 | 707 |
| 578 // Configure the decoder. | 708 // Configure the decoder. |
| 579 media::VideoDecodeAccelerator::Profile profile = media::H264PROFILE_BASELINE; | 709 media::VideoDecodeAccelerator::Profile profile = media::H264PROFILE_BASELINE; |
| 580 if (profile_ != -1) | 710 if (profile_ != -1) |
| 581 profile = static_cast<media::VideoDecodeAccelerator::Profile>(profile_); | 711 profile = static_cast<media::VideoDecodeAccelerator::Profile>(profile_); |
| 582 CHECK(decoder_->Initialize(profile)); | 712 CHECK(decoder_->Initialize(profile)); |
| 583 } | 713 } |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 778 return 0; | 908 return 0; |
| 779 return num_decoded_frames_ / delta.InSecondsF(); | 909 return num_decoded_frames_ / delta.InSecondsF(); |
| 780 } | 910 } |
| 781 | 911 |
| 782 // Test parameters: | 912 // Test parameters: |
| 783 // - Number of NALUs per Decode() call. | 913 // - Number of NALUs per Decode() call. |
| 784 // - Number of concurrent decoders. | 914 // - Number of concurrent decoders. |
| 785 // - Number of concurrent in-flight Decode() calls per decoder. | 915 // - Number of concurrent in-flight Decode() calls per decoder. |
| 786 // - reset_after_frame_num: see EglRenderingVDAClient ctor. | 916 // - reset_after_frame_num: see EglRenderingVDAClient ctor. |
| 787 // - delete_decoder_phase: see EglRenderingVDAClient ctor. | 917 // - delete_decoder_phase: see EglRenderingVDAClient ctor. |
| 788 class OmxVideoDecodeAcceleratorTest | 918 class VideoDecodeAcceleratorTest |
| 789 : public ::testing::TestWithParam< | 919 : public ::testing::TestWithParam< |
| 790 Tuple5<int, int, int, ResetPoint, ClientState> > { | 920 Tuple5<int, int, int, ResetPoint, ClientState> > { |
| 791 }; | 921 }; |
| 792 | 922 |
| 793 // Wait for |note| to report a state and if it's not |expected_state| then | 923 // Wait for |note| to report a state and if it's not |expected_state| then |
| 794 // assert |client| has deleted its decoder. | 924 // assert |client| has deleted its decoder. |
| 795 static void AssertWaitForStateOrDeleted(ClientStateNotification* note, | 925 static void AssertWaitForStateOrDeleted(ClientStateNotification* note, |
| 796 EglRenderingVDAClient* client, | 926 EglRenderingVDAClient* client, |
| 797 ClientState expected_state) { | 927 ClientState expected_state) { |
| 798 ClientState state = note->Wait(); | 928 ClientState state = note->Wait(); |
| 799 if (state == expected_state) return; | 929 if (state == expected_state) return; |
| 800 ASSERT_TRUE(client->decoder_deleted()) | 930 ASSERT_TRUE(client->decoder_deleted()) |
| 801 << "Decoder not deleted but Wait() returned " << state | 931 << "Decoder not deleted but Wait() returned " << state |
| 802 << ", instead of " << expected_state; | 932 << ", instead of " << expected_state; |
| 803 } | 933 } |
| 804 | 934 |
| 805 // We assert a minimal number of concurrent decoders we expect to succeed. | 935 // 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 | 936 // Different platforms can support more concurrent decoders, so we don't assert |
| 807 // failure above this. | 937 // failure above this. |
| 808 enum { kMinSupportedNumConcurrentDecoders = 3 }; | 938 enum { kMinSupportedNumConcurrentDecoders = 3 }; |
| 809 | 939 |
| 810 // Test the most straightforward case possible: data is decoded from a single | 940 // Test the most straightforward case possible: data is decoded from a single |
| 811 // chunk and rendered to the screen. | 941 // chunk and rendered to the screen. |
| 812 TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { | 942 TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) { |
| 813 // Can be useful for debugging VLOGs from OVDA. | 943 // Can be useful for debugging VLOGs from OVDA. |
| 814 // logging::SetMinLogLevel(-1); | 944 // logging::SetMinLogLevel(-1); |
| 815 | 945 |
| 816 // Required for Thread to work. Not used otherwise. | 946 // Required for Thread to work. Not used otherwise. |
| 817 base::ShadowingAtExitManager at_exit_manager; | 947 base::ShadowingAtExitManager at_exit_manager; |
| 818 | 948 |
| 819 const int num_NALUs_per_decode = GetParam().a; | 949 const int num_NALUs_per_decode = GetParam().a; |
| 820 const size_t num_concurrent_decoders = GetParam().b; | 950 const size_t num_concurrent_decoders = GetParam().b; |
| 821 const size_t num_in_flight_decodes = GetParam().c; | 951 const size_t num_in_flight_decodes = GetParam().c; |
| 822 const int reset_after_frame_num = GetParam().d; | 952 const int reset_after_frame_num = GetParam().d; |
| 823 const int delete_decoder_state = GetParam().e; | 953 const int delete_decoder_state = GetParam().e; |
| 824 | 954 |
| 825 std::string test_video_file; | 955 FilePath::StringType test_video_file; |
| 826 int frame_width, frame_height; | 956 int frame_width, frame_height; |
| 827 int num_frames, num_NALUs, min_fps_render, min_fps_no_render, profile; | 957 int num_frames, num_NALUs, min_fps_render, min_fps_no_render, profile; |
| 828 ParseTestVideoData(test_video_data, &test_video_file, &frame_width, | 958 ParseTestVideoData(test_video_data, &test_video_file, &frame_width, |
| 829 &frame_height, &num_frames, &num_NALUs, | 959 &frame_height, &num_frames, &num_NALUs, |
| 830 &min_fps_render, &min_fps_no_render, &profile); | 960 &min_fps_render, &min_fps_no_render, &profile); |
| 831 min_fps_render /= num_concurrent_decoders; | 961 min_fps_render /= num_concurrent_decoders; |
| 832 min_fps_no_render /= num_concurrent_decoders; | 962 min_fps_no_render /= num_concurrent_decoders; |
| 833 | 963 |
| 834 // If we reset mid-stream and start playback over, account for frames that are | 964 // If we reset mid-stream and start playback over, account for frames that are |
| 835 // decoded twice in our expectations. | 965 // decoded twice in our expectations. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 882 // Then wait for all the decodes to finish. | 1012 // Then wait for all the decodes to finish. |
| 883 bool saw_init_failure = false; | 1013 bool saw_init_failure = false; |
| 884 for (size_t i = 0; i < num_concurrent_decoders; ++i) { | 1014 for (size_t i = 0; i < num_concurrent_decoders; ++i) { |
| 885 ClientStateNotification* note = notes[i]; | 1015 ClientStateNotification* note = notes[i]; |
| 886 ClientState state = note->Wait(); | 1016 ClientState state = note->Wait(); |
| 887 if (state != CS_INITIALIZED) { | 1017 if (state != CS_INITIALIZED) { |
| 888 saw_init_failure = true; | 1018 saw_init_failure = true; |
| 889 // We expect initialization to fail only when more than the supported | 1019 // We expect initialization to fail only when more than the supported |
| 890 // number of decoders is instantiated. Assert here that something else | 1020 // number of decoders is instantiated. Assert here that something else |
| 891 // didn't trigger failure. | 1021 // didn't trigger failure. |
| 892 ASSERT_GT(num_concurrent_decoders, kMinSupportedNumConcurrentDecoders); | 1022 ASSERT_GT(num_concurrent_decoders, |
| 1023 static_cast<size_t>(kMinSupportedNumConcurrentDecoders)); | |
| 893 continue; | 1024 continue; |
| 894 } | 1025 } |
| 895 ASSERT_EQ(state, CS_INITIALIZED); | 1026 ASSERT_EQ(state, CS_INITIALIZED); |
| 896 // InitializeDone kicks off decoding inside the client, so we just need to | 1027 // InitializeDone kicks off decoding inside the client, so we just need to |
| 897 // wait for Flush. | 1028 // wait for Flush. |
| 898 ASSERT_NO_FATAL_FAILURE( | 1029 ASSERT_NO_FATAL_FAILURE( |
| 899 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING)); | 1030 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING)); |
| 900 ASSERT_NO_FATAL_FAILURE( | 1031 ASSERT_NO_FATAL_FAILURE( |
| 901 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); | 1032 AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); |
| 902 // FlushDone requests Reset(). | 1033 // FlushDone requests Reset(). |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 940 base::Bind(&RenderingHelper::UnInitialize, | 1071 base::Bind(&RenderingHelper::UnInitialize, |
| 941 base::Unretained(&rendering_helper), | 1072 base::Unretained(&rendering_helper), |
| 942 &done)); | 1073 &done)); |
| 943 done.Wait(); | 1074 done.Wait(); |
| 944 rendering_thread.Stop(); | 1075 rendering_thread.Stop(); |
| 945 }; | 1076 }; |
| 946 | 1077 |
| 947 // Test that Reset() mid-stream works fine and doesn't affect decoding even when | 1078 // Test that Reset() mid-stream works fine and doesn't affect decoding even when |
| 948 // Decode() calls are made during the reset. | 1079 // Decode() calls are made during the reset. |
| 949 INSTANTIATE_TEST_CASE_P( | 1080 INSTANTIATE_TEST_CASE_P( |
| 950 MidStreamReset, OmxVideoDecodeAcceleratorTest, | 1081 MidStreamReset, VideoDecodeAcceleratorTest, |
| 951 ::testing::Values( | 1082 ::testing::Values( |
| 952 MakeTuple(1, 1, 1, static_cast<ResetPoint>(100), CS_RESET))); | 1083 MakeTuple(1, 1, 1, static_cast<ResetPoint>(100), CS_RESET))); |
| 953 | 1084 |
| 954 // Test that Destroy() mid-stream works fine (primarily this is testing that no | 1085 // Test that Destroy() mid-stream works fine (primarily this is testing that no |
| 955 // crashes occur). | 1086 // crashes occur). |
| 956 INSTANTIATE_TEST_CASE_P( | 1087 INSTANTIATE_TEST_CASE_P( |
| 957 TearDownTiming, OmxVideoDecodeAcceleratorTest, | 1088 TearDownTiming, VideoDecodeAcceleratorTest, |
| 958 ::testing::Values( | 1089 ::testing::Values( |
| 959 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET), | 1090 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET), |
| 960 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED), | 1091 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED), |
| 961 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING), | 1092 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING), |
| 962 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED), | 1093 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED), |
| 963 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING), | 1094 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING), |
| 964 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1095 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 965 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-1)), | 1096 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)), | 1097 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, static_cast<ClientState>(-10)), |
| 967 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, | 1098 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, |
| 968 static_cast<ClientState>(-100)))); | 1099 static_cast<ClientState>(-100)))); |
| 969 | 1100 |
| 970 // Test that decoding various variation works: multiple concurrent decoders and | 1101 // Test that decoding various variation works: multiple concurrent decoders and |
| 971 // multiple NALUs per Decode() call. | 1102 // multiple NALUs per Decode() call. |
| 972 INSTANTIATE_TEST_CASE_P( | 1103 INSTANTIATE_TEST_CASE_P( |
| 973 DecodeVariations, OmxVideoDecodeAcceleratorTest, | 1104 DecodeVariations, VideoDecodeAcceleratorTest, |
| 974 ::testing::Values( | 1105 ::testing::Values( |
| 975 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1106 MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 976 MakeTuple(1, 1, 10, END_OF_STREAM_RESET, CS_RESET), | 1107 MakeTuple(1, 1, 10, END_OF_STREAM_RESET, CS_RESET), |
| 977 MakeTuple(1, 1, 15, END_OF_STREAM_RESET, CS_RESET), // Tests queuing. | 1108 MakeTuple(1, 1, 15, END_OF_STREAM_RESET, CS_RESET), // Tests queuing. |
| 978 MakeTuple(1, 3, 1, END_OF_STREAM_RESET, CS_RESET), | 1109 MakeTuple(1, 3, 1, END_OF_STREAM_RESET, CS_RESET), |
| 979 MakeTuple(2, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1110 MakeTuple(2, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 980 MakeTuple(3, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1111 MakeTuple(3, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 981 MakeTuple(5, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1112 MakeTuple(5, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 982 MakeTuple(8, 1, 1, END_OF_STREAM_RESET, CS_RESET), | 1113 MakeTuple(8, 1, 1, END_OF_STREAM_RESET, CS_RESET), |
| 983 // TODO(fischman): decoding more than 15 NALUs at once breaks decode - | 1114 // TODO(fischman): decoding more than 15 NALUs at once breaks decode - |
| 984 // visual artifacts are introduced as well as spurious frames are | 1115 // visual artifacts are introduced as well as spurious frames are |
| 985 // delivered (more pictures are returned than NALUs are fed to the | 1116 // delivered (more pictures are returned than NALUs are fed to the |
| 986 // decoder). Increase the "15" below when | 1117 // decoder). Increase the "15" below when |
| 987 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is | 1118 // http://code.google.com/p/chrome-os-partner/issues/detail?id=4378 is |
| 988 // fixed. | 1119 // fixed. |
| 989 MakeTuple(15, 1, 1, END_OF_STREAM_RESET, CS_RESET))); | 1120 MakeTuple(15, 1, 1, END_OF_STREAM_RESET, CS_RESET))); |
| 990 | 1121 |
| 991 // Find out how many concurrent decoders can go before we exhaust system | 1122 // Find out how many concurrent decoders can go before we exhaust system |
| 992 // resources. | 1123 // resources. |
| 993 INSTANTIATE_TEST_CASE_P( | 1124 INSTANTIATE_TEST_CASE_P( |
| 994 ResourceExhaustion, OmxVideoDecodeAcceleratorTest, | 1125 ResourceExhaustion, VideoDecodeAcceleratorTest, |
| 995 ::testing::Values( | 1126 ::testing::Values( |
| 996 // +0 hack below to promote enum to int. | 1127 // +0 hack below to promote enum to int. |
| 997 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1, | 1128 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1, |
| 998 END_OF_STREAM_RESET, CS_RESET), | 1129 END_OF_STREAM_RESET, CS_RESET), |
| 999 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1, | 1130 MakeTuple(1, kMinSupportedNumConcurrentDecoders + 1, 1, |
| 1000 END_OF_STREAM_RESET, CS_RESET))); | 1131 END_OF_STREAM_RESET, CS_RESET))); |
| 1001 | 1132 |
| 1002 // TODO(fischman, vrk): add more tests! In particular: | 1133 // TODO(fischman, vrk): add more tests! In particular: |
| 1003 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. | 1134 // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. |
| 1004 // - Test alternate configurations | 1135 // - Test alternate configurations |
| 1005 // - Test failure conditions. | 1136 // - Test failure conditions. |
| 1006 // - Test frame size changes mid-stream | 1137 // - Test frame size changes mid-stream |
| 1007 | 1138 |
| 1008 } // namespace | 1139 } // namespace |
| 1009 | 1140 |
| 1010 int main(int argc, char **argv) { | 1141 int main(int argc, char **argv) { |
| 1011 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. | 1142 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. |
| 1012 CommandLine cmd_line(argc, argv); // Must run after InitGoogleTest. | 1143 CommandLine::Init(argc, argv); |
| 1013 CommandLine::SwitchMap switches = cmd_line.GetSwitches(); | 1144 |
| 1145 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | |
| 1146 DCHECK(cmd_line); | |
| 1147 | |
| 1148 CommandLine::SwitchMap switches = cmd_line->GetSwitches(); | |
| 1014 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); | 1149 for (CommandLine::SwitchMap::const_iterator it = switches.begin(); |
| 1015 it != switches.end(); ++it) { | 1150 it != switches.end(); ++it) { |
| 1016 if (it->first == "test_video_data") { | 1151 if (it->first == "test_video_data") { |
| 1017 test_video_data = it->second.c_str(); | 1152 test_video_data = it->second.c_str(); |
| 1018 continue; | |
| 1019 } | 1153 } |
| 1020 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; | 1154 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; |
| 1021 } | 1155 } |
| 1022 | |
| 1023 return RUN_ALL_TESTS(); | 1156 return RUN_ALL_TESTS(); |
| 1024 } | 1157 } |
| OLD | NEW |