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

Unified Diff: content/common/gpu/media/video_decode_accelerator_unittest.cc

Issue 8510039: Initial implementation of the DXVA 2.0 H.264 hardware decoder for pepper for Windows. The decodin... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/common/gpu/media/video_decode_accelerator_unittest.cc
===================================================================
--- content/common/gpu/media/video_decode_accelerator_unittest.cc (revision 114547)
+++ content/common/gpu/media/video_decode_accelerator_unittest.cc (working copy)
@@ -28,6 +28,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
+#include "base/process_util.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
@@ -36,14 +37,21 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+
+#if (!defined(OS_CHROMEOS) || !defined(ARCH_CPU_ARMEL)) && !defined(OS_WIN)
+#error The VideoAccelerator tests are only supported on cros/ARM/Windows.
+#endif
+
+#if defined(OS_WIN)
+#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
+#else // OS_WIN
#include "content/common/gpu/media/omx_video_decode_accelerator.h"
+#endif // defined(OS_WIN)
+
#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/GLES2/gl2.h"
-#if !defined(OS_CHROMEOS) || !defined(ARCH_CPU_ARMEL)
-#error This test (and OmxVideoDecodeAccelerator) are only supported on cros/ARM!
-#endif
-
using media::VideoDecodeAccelerator;
namespace {
@@ -61,20 +69,21 @@
// (the latter tests just decode speed).
// - |profile| is the media::H264Profile set during Initialization.
// An empty value for a numeric field means "ignore".
-const char* test_video_data = "test-25fps.h264:320:240:250:258:50:175:1";
+const FilePath::CharType* test_video_data =
+ FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1");
// Parse |data| into its constituent parts and set the various output fields
// accordingly. CHECK-fails on unexpected or missing required data.
// Unspecified optional fields are set to -1.
-void ParseTestVideoData(std::string data,
- std::string* file_name,
+void ParseTestVideoData(FilePath::StringType data,
+ FilePath::StringType* file_name,
int* width, int* height,
int* num_frames,
int* num_NALUs,
int* min_fps_render,
int* min_fps_no_render,
int* profile) {
- std::vector<std::string> elements;
+ std::vector<FilePath::StringType> elements;
base::SplitString(data, ':', &elements);
CHECK_GE(elements.size(), 1U) << data;
CHECK_LE(elements.size(), 8U) << data;
@@ -98,17 +107,12 @@
CHECK(base::StringToInt(elements[7], profile));
}
-
-// Helper for managing X11, EGL, and GLES2 resources. Xlib is not thread-safe,
-// and GL state is thread-specific, so all the methods of this class (except for
-// ctor/dtor) ensure they're being run on a single thread.
-//
-// TODO(fischman): consider moving this into media/ if we can de-dup some of the
-// code that ends up getting copy/pasted all over the place (esp. the GL setup
-// code).
+// Provides functionality for managing EGL, GLES2 and UI resources.
+// This class is not thread safe and thus all the methods of this class
+// (except for ctor/dtor) ensure they're being run on a single thread.
class RenderingHelper {
public:
- explicit RenderingHelper();
+ RenderingHelper();
~RenderingHelper();
// Initialize all structures to prepare to render to one or more windows of
@@ -119,8 +123,8 @@
// then all the usual work is done, except for the final swap of the EGL
// surface to the display. This cuts test times over 50% so is worth doing
// when testing non-rendering-related aspects.
- void Initialize(bool suppress_swap_to_display, int num_windows,
- int width, int height, base::WaitableEvent* done);
+ void Initialize(bool suppress_swap_to_display, int num_windows, int width,
+ int height, base::WaitableEvent* done);
// Undo the effects of Initialize() and signal |*done|.
void UnInitialize(base::WaitableEvent* done);
@@ -136,26 +140,43 @@
// Delete |texture_id|.
void DeleteTexture(GLuint texture_id);
+ // Platform specific Init/Uninit.
+ void PlatformInitialize();
+ void PlatformUnInitialize();
+
+ // Platform specific window creation.
+ EGLNativeWindowType PlatformCreateWindow(int top_left_x, int top_left_y);
+
+ // Platform specific display surface returned here.
+ EGLDisplay PlatformGetDisplay();
+
EGLDisplay egl_display() { return egl_display_; }
+
EGLContext egl_context() { return egl_context_; }
+
MessageLoop* message_loop() { return message_loop_; }
- private:
- // Zero-out internal state. Helper for ctor & UnInitialize().
+ protected:
void Clear();
- bool suppress_swap_to_display_;
+ // We ensure all operations are carried out on the same thread by remembering
+ // where we were Initialized.
+ MessageLoop* message_loop_;
int width_;
int height_;
- Display* x_display_;
- std::vector<Window> x_windows_;
+ bool suppress_swap_to_display_;
+
EGLDisplay egl_display_;
EGLContext egl_context_;
std::vector<EGLSurface> egl_surfaces_;
std::map<GLuint, int> texture_id_to_surface_index_;
- // We ensure all operations are carried out on the same thread by remembering
- // where we were Initialized.
- MessageLoop* message_loop_;
+
+#if defined(OS_WIN)
+ std::vector<HWND> windows_;
+#else // OS_WIN
+ Display* x_display_;
+ std::vector<Window> x_windows_;
+#endif // OS_WIN
};
RenderingHelper::RenderingHelper() {
@@ -164,21 +185,9 @@
RenderingHelper::~RenderingHelper() {
CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
+ Clear();
}
-void RenderingHelper::Clear() {
- suppress_swap_to_display_ = false;
- width_ = 0;
- height_ = 0;
- x_display_ = NULL;
- x_windows_.clear();
- egl_display_ = EGL_NO_DISPLAY;
- egl_context_ = EGL_NO_CONTEXT;
- egl_surfaces_.clear();
- texture_id_to_surface_index_.clear();
- message_loop_ = NULL;
-}
-
// Helper for Shader creation.
static void CreateShader(
GLuint program, GLenum type, const char* source, int size) {
@@ -200,7 +209,8 @@
void RenderingHelper::Initialize(
bool suppress_swap_to_display,
int num_windows,
- int width, int height,
+ int width,
+ int height,
base::WaitableEvent* done) {
// Use width_ != 0 as a proxy for the class having already been
// Initialize()'d, and UnInitialize() before continuing.
@@ -218,15 +228,10 @@
message_loop_ = MessageLoop::current();
CHECK_GT(num_windows, 0);
- // Per-display X11 & EGL initialization.
- CHECK(x_display_ = XOpenDisplay(NULL));
- int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
- XSetWindowAttributes window_attributes;
- window_attributes.background_pixel =
- BlackPixel(x_display_, DefaultScreen(x_display_));
- window_attributes.override_redirect = true;
+ PlatformInitialize();
- egl_display_ = eglGetDisplay(x_display_);
+ egl_display_ = PlatformGetDisplay();
+
EGLint major;
EGLint minor;
CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
@@ -253,28 +258,16 @@
// Arrange X windows whimsically, with some padding.
int top_left_x = (width + 20) * (i % 4);
int top_left_y = (height + 12) * (i % 3);
- Window x_window = XCreateWindow(
- x_display_, DefaultRootWindow(x_display_),
- top_left_x, top_left_y, width_, height_,
- 0 /* border width */,
- depth, CopyFromParent /* class */, CopyFromParent /* visual */,
- (CWBackPixel | CWOverrideRedirect), &window_attributes);
- x_windows_.push_back(x_window);
- XStoreName(x_display_, x_window, "OmxVideoDecodeAcceleratorTest");
- XSelectInput(x_display_, x_window, ExposureMask);
- XMapWindow(x_display_, x_window);
+ EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y);
EGLSurface egl_surface =
- eglCreateWindowSurface(egl_display_, egl_config, x_window, NULL);
+ eglCreateWindowSurface(egl_display_, egl_config, window, NULL);
egl_surfaces_.push_back(egl_surface);
CHECK_NE(egl_surface, EGL_NO_SURFACE);
}
CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0],
egl_surfaces_[0], egl_context_)) << eglGetError();
- // GLES2 initialization. Note: This is pretty much copy/pasted from
- // media/tools/player_x11/gles_video_renderer.cc, with some simplification
- // applied.
static const float kVertices[] =
{ -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
@@ -319,28 +312,33 @@
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
kTextureCoordsEgl);
-
done->Signal();
}
void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
CHECK_EQ(MessageLoop::current(), message_loop_);
- // Destroy resources acquired in Initialize, in reverse-acquisition order.
CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) << eglGetError();
CHECK(eglDestroyContext(egl_display_, egl_context_));
for (size_t i = 0; i < egl_surfaces_.size(); ++i)
CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
CHECK(eglTerminate(egl_display_));
- for (size_t i = 0; i < x_windows_.size(); ++i) {
- CHECK(XUnmapWindow(x_display_, x_windows_[i]));
- CHECK(XDestroyWindow(x_display_, x_windows_[i]));
- }
- // Mimic newly-created object.
Clear();
done->Signal();
}
+void RenderingHelper::Clear() {
+ suppress_swap_to_display_ = false;
+ width_ = 0;
+ height_ = 0;
+ texture_id_to_surface_index_.clear();
+ message_loop_ = NULL;
+ egl_display_ = EGL_NO_DISPLAY;
+ egl_context_ = EGL_NO_CONTEXT;
+ egl_surfaces_.clear();
+ PlatformUnInitialize();
+}
+
void RenderingHelper::CreateTexture(int window_id, GLuint* texture_id,
base::WaitableEvent* done) {
if (MessageLoop::current() != message_loop_) {
@@ -390,6 +388,76 @@
CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
}
+#if defined(OS_WIN)
+void RenderingHelper::PlatformInitialize() {}
+
+void RenderingHelper::PlatformUnInitialize() {
+ for (size_t i = 0; i < windows_.size(); ++i) {
+ DestroyWindow(windows_[i]);
+ }
+ windows_.clear();
+}
+
+EGLNativeWindowType RenderingHelper::PlatformCreateWindow(
+ int top_left_x, int top_left_y) {
+ HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest",
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x,
+ top_left_y, width_, height_, NULL, NULL, NULL,
+ NULL);
+ CHECK(window != NULL);
+ windows_.push_back(window);
+ return window;
+}
+
+EGLDisplay RenderingHelper::PlatformGetDisplay() {
+ return eglGetDisplay(EGL_DEFAULT_DISPLAY);
+}
+
+#else // OS_WIN
+
+void RenderingHelper::PlatformInitialize() {
+ CHECK(x_display_ = XOpenDisplay(NULL));
+}
+
+void RenderingHelper::PlatformUnInitialize() {
+ // Destroy resources acquired in Initialize, in reverse-acquisition order.
+ for (size_t i = 0; i < x_windows_.size(); ++i) {
+ CHECK(XUnmapWindow(x_display_, x_windows_[i]));
+ CHECK(XDestroyWindow(x_display_, x_windows_[i]));
+ }
+ // Mimic newly created object.
+ x_display_ = NULL;
+ x_windows_.clear();
+}
+
+EGLDisplay RenderingHelper::PlatformGetDisplay() {
+ return eglGetDisplay(x_display_);
+}
+
+EGLNativeWindowType RenderingHelper::PlatformCreateWindow(int top_left_x,
+ int top_left_y) {
+ int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
+
+ XSetWindowAttributes window_attributes;
+ window_attributes.background_pixel =
+ BlackPixel(x_display_, DefaultScreen(x_display_));
+ window_attributes.override_redirect = true;
+
+ Window x_window = XCreateWindow(
+ x_display_, DefaultRootWindow(x_display_),
+ top_left_x, top_left_y, width_, height_,
+ 0 /* border width */,
+ depth, CopyFromParent /* class */, CopyFromParent /* visual */,
+ (CWBackPixel | CWOverrideRedirect), window_attributes);
Ami GONE FROM CHROMIUM 2011/12/21 01:41:16 s/window_attributes/&window_attributes/
ananta 2011/12/21 02:59:58 Done.
+ x_windows_.push_back(x_window);
+ XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest");
+ XSelectInput(x_display_, x_window, ExposureMask);
+ XMapWindow(x_display_, x_window);
+ return x_window;
+}
+
+#endif // OS_WIN
+
// State of the EglRenderingVDAClient below. Order matters here as the test
// makes assumptions about it.
enum ClientState {
@@ -523,7 +591,7 @@
size_t encoded_data_next_pos_to_decode_;
int next_bitstream_buffer_id_;
ClientStateNotification* note_;
- scoped_refptr<OmxVideoDecodeAccelerator> decoder_;
+ scoped_refptr<VideoDecodeAccelerator> decoder_;
std::set<int> outstanding_texture_ids_;
int reset_after_frame_num_;
int delete_decoder_state_;
@@ -569,8 +637,15 @@
void EglRenderingVDAClient::CreateDecoder() {
CHECK(decoder_deleted());
- decoder_ = new OmxVideoDecodeAccelerator(this);
- decoder_->SetEglState(egl_display(), egl_context());
+#if defined(OS_WIN)
+ scoped_refptr<DXVAVideoDecodeAccelerator> decoder =
+ new DXVAVideoDecodeAccelerator(this, base::GetCurrentProcessHandle());
+#else // OS_WIN
+ scoped_refptr<OmxVideoDecodeAccelerator> decoder =
+ new OmxVideoDecodeAccelerator(this);
+ decoder->SetEglState(egl_display(), egl_context());
+#endif // OS_WIN
+ decoder_ = decoder.release();
SetState(CS_DECODER_SET);
if (decoder_deleted())
return;
@@ -785,7 +860,7 @@
// - Number of concurrent in-flight Decode() calls per decoder.
// - reset_after_frame_num: see EglRenderingVDAClient ctor.
// - delete_decoder_phase: see EglRenderingVDAClient ctor.
-class OmxVideoDecodeAcceleratorTest
+class VideoDecodeAcceleratorTest
: public ::testing::TestWithParam<
Tuple5<int, int, int, ResetPoint, ClientState> > {
};
@@ -809,7 +884,7 @@
// Test the most straightforward case possible: data is decoded from a single
// chunk and rendered to the screen.
-TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) {
+TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) {
// Can be useful for debugging VLOGs from OVDA.
// logging::SetMinLogLevel(-1);
@@ -822,7 +897,7 @@
const int reset_after_frame_num = GetParam().d;
const int delete_decoder_state = GetParam().e;
- std::string test_video_file;
+ FilePath::StringType test_video_file;
int frame_width, frame_height;
int num_frames, num_NALUs, min_fps_render, min_fps_no_render, profile;
ParseTestVideoData(test_video_data, &test_video_file, &frame_width,
@@ -849,7 +924,9 @@
// Initialize the rendering helper.
base::Thread rendering_thread("EglRenderingVDAClientThread");
- rendering_thread.Start();
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_UI;
+ rendering_thread.StartWithOptions(options);
Ami GONE FROM CHROMIUM 2011/12/21 01:41:16 Per IM convo cros/arm needs this to be TYPE_DEFAUL
ananta 2011/12/21 02:59:58 Done.
RenderingHelper rendering_helper;
base::WaitableEvent done(false, false);
@@ -889,7 +966,8 @@
// We expect initialization to fail only when more than the supported
// number of decoders is instantiated. Assert here that something else
// didn't trigger failure.
- ASSERT_GT(num_concurrent_decoders, kMinSupportedNumConcurrentDecoders);
+ ASSERT_GT(num_concurrent_decoders,
+ static_cast<size_t>(kMinSupportedNumConcurrentDecoders));
continue;
}
ASSERT_EQ(state, CS_INITIALIZED);
@@ -947,14 +1025,14 @@
// Test that Reset() mid-stream works fine and doesn't affect decoding even when
// Decode() calls are made during the reset.
INSTANTIATE_TEST_CASE_P(
- MidStreamReset, OmxVideoDecodeAcceleratorTest,
+ MidStreamReset, VideoDecodeAcceleratorTest,
::testing::Values(
MakeTuple(1, 1, 1, static_cast<ResetPoint>(100), CS_RESET)));
// Test that Destroy() mid-stream works fine (primarily this is testing that no
// crashes occur).
INSTANTIATE_TEST_CASE_P(
- TearDownTiming, OmxVideoDecodeAcceleratorTest,
+ TearDownTiming, VideoDecodeAcceleratorTest,
::testing::Values(
MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET),
MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED),
@@ -970,7 +1048,7 @@
// Test that decoding various variation works: multiple concurrent decoders and
// multiple NALUs per Decode() call.
INSTANTIATE_TEST_CASE_P(
- DecodeVariations, OmxVideoDecodeAcceleratorTest,
+ DecodeVariations, VideoDecodeAcceleratorTest,
::testing::Values(
MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET),
MakeTuple(1, 1, 10, END_OF_STREAM_RESET, CS_RESET),
@@ -991,7 +1069,7 @@
// Find out how many concurrent decoders can go before we exhaust system
// resources.
INSTANTIATE_TEST_CASE_P(
- ResourceExhaustion, OmxVideoDecodeAcceleratorTest,
+ ResourceExhaustion, VideoDecodeAcceleratorTest,
::testing::Values(
// +0 hack below to promote enum to int.
MakeTuple(1, kMinSupportedNumConcurrentDecoders + 0, 1,
@@ -1009,16 +1087,18 @@
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args.
- CommandLine cmd_line(argc, argv); // Must run after InitGoogleTest.
- CommandLine::SwitchMap switches = cmd_line.GetSwitches();
+ CommandLine::Init(argc, argv);
+
+ CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ DCHECK(cmd_line);
+
+ CommandLine::SwitchMap switches = cmd_line->GetSwitches();
for (CommandLine::SwitchMap::const_iterator it = switches.begin();
it != switches.end(); ++it) {
if (it->first == "test_video_data") {
test_video_data = it->second.c_str();
- continue;
}
LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
}
-
return RUN_ALL_TESTS();
}

Powered by Google App Engine
This is Rietveld 408576698