diff options
25 files changed, 492 insertions, 425 deletions
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 03a594d..e4fcad6 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn @@ -7,7 +7,7 @@ import("//build/config/ui.gni") import("//content/common/common.gni") import("//mojo/public/tools/bindings/mojom.gni") -if (is_chromeos && use_x11 && cpu_arch != "arm") { +if (is_chromeos && cpu_arch != "arm") { action("libva_generate_stubs") { extra_header = "gpu/media/va_stub_header.fragment" @@ -18,6 +18,9 @@ if (is_chromeos && use_x11 && cpu_arch != "arm") { inputs = [ extra_header, ] + if (use_x11) { + sources += [ "content/common/gpu/media/va_x11.sigs" ] + } stubs_filename_root = "va_stubs" outputs = [ @@ -274,8 +277,8 @@ source_set("common") { } } - if (is_chromeos && use_x11) { - if (cpu_arch == "arm") { + if (is_chromeos) { + if (cpu_arch == "arm" && use_x11) { sources += [ "gpu/media/exynos_v4l2_video_device.cc", "gpu/media/exynos_v4l2_video_device.h", @@ -294,13 +297,16 @@ source_set("common") { "EGL", "GLESv2", ] - } else { # !arm + } + if (cpu_arch != "arm") { sources += [ "gpu/media/h264_dpb.cc", "gpu/media/h264_dpb.h", "gpu/media/va_surface.h", "gpu/media/vaapi_h264_decoder.cc", "gpu/media/vaapi_h264_decoder.h", + "gpu/media/vaapi_picture.cc", + "gpu/media/vaapi_picture.h", "gpu/media/vaapi_video_decode_accelerator.cc", "gpu/media/vaapi_video_decode_accelerator.h", "gpu/media/vaapi_video_encode_accelerator.cc", @@ -317,6 +323,12 @@ source_set("common") { "//media", "//third_party/libyuv", ] + if (use_x11) { + sources += [ + "gpu/media/vaapi_tfp_picture.cc", + "gpu/media/vaapi_tfp_picture.h", + ] + } } } diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc index f741cb2..3d3a437 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -31,9 +31,8 @@ #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11) #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" #include "content/common/gpu/media/v4l2_video_device.h" -#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" -#include "ui/gl/gl_context_glx.h" #include "ui/gl/gl_implementation.h" #elif defined(USE_OZONE) #include "media/ozone/media_ozone_platform.h" @@ -272,17 +271,9 @@ void GpuVideoDecodeAccelerator::Initialize( make_context_current_, device.Pass(), io_message_loop_)); -#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) - if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) { - VLOG(1) << "HW video decode acceleration not available without " - "DesktopGL (GLX)."; - SendCreateDecoderReply(init_done_msg, false); - return; - } - gfx::GLContextGLX* glx_context = - static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext()); - video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator( - glx_context->display(), make_context_current_)); +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + video_decode_accelerator_.reset( + new VaapiVideoDecodeAccelerator(make_context_current_)); #elif defined(USE_OZONE) media::MediaOzonePlatform* platform = media::MediaOzonePlatform::GetInstance(); diff --git a/content/common/gpu/media/gpu_video_encode_accelerator.cc b/content/common/gpu/media/gpu_video_encode_accelerator.cc index 12b473f..639d1d8 100644 --- a/content/common/gpu/media/gpu_video_encode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_encode_accelerator.cc @@ -17,13 +17,12 @@ #include "media/base/limits.h" #include "media/base/video_frame.h" -#if defined(OS_CHROMEOS) && defined(USE_X11) +#if defined(OS_CHROMEOS) -#if defined(ARCH_CPU_ARMEL) +#if defined(ARCH_CPU_ARMEL) && defined(USE_X11) #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" #elif defined(ARCH_CPU_X86_FAMILY) #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" -#include "ui/gfx/x/x11_types.h" #endif #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC) @@ -191,15 +190,15 @@ GpuVideoEncodeAccelerator::ConvertMediaToGpuProfiles(const std::vector< scoped_ptr<media::VideoEncodeAccelerator> GpuVideoEncodeAccelerator::CreateEncoder() { scoped_ptr<media::VideoEncodeAccelerator> encoder; -#if defined(OS_CHROMEOS) && defined(USE_X11) -#if defined(ARCH_CPU_ARMEL) +#if defined(OS_CHROMEOS) +#if defined(ARCH_CPU_ARMEL) && defined(USE_X11) scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder); if (device) encoder.reset(new V4L2VideoEncodeAccelerator(device.Pass())); #elif defined(ARCH_CPU_X86_FAMILY) const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode)) - encoder.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay())); + encoder.reset(new VaapiVideoEncodeAccelerator()); #endif #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC) encoder.reset(new AndroidVideoEncodeAccelerator()); diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc index fcd0307..4e9b60c 100644 --- a/content/common/gpu/media/rendering_helper.cc +++ b/content/common/gpu/media/rendering_helper.cc @@ -19,8 +19,6 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface.h" -#include "ui/gl/gl_surface_egl.h" -#include "ui/gl/gl_surface_glx.h" #if defined(OS_WIN) #include <windows.h> @@ -30,9 +28,11 @@ #include "ui/gfx/x/x11_types.h" #endif -#if !defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY) +#if defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) +#include "ui/gl/gl_surface_glx.h" #define GL_VARIANT_GLX 1 #else +#include "ui/gl/gl_surface_egl.h" #define GL_VARIANT_EGL 1 #endif @@ -127,16 +127,14 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, message_loop_ = base::MessageLoop::current(); #if defined(OS_WIN) - screen_size_ = - gfx::Size(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); window_ = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, - screen_size_.width(), - screen_size_.height(), + GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN), NULL, NULL, NULL, @@ -144,7 +142,6 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, #elif defined(USE_X11) Display* display = gfx::GetXDisplay(); Screen* screen = DefaultScreenOfDisplay(display); - screen_size_ = gfx::Size(XWidthOfScreen(screen), XHeightOfScreen(screen)); CHECK(display); @@ -159,8 +156,8 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, DefaultRootWindow(display), 0, 0, - screen_size_.width(), - screen_size_.height(), + XWidthOfScreen(screen), + XHeightOfScreen(screen), 0 /* border width */, depth, CopyFromParent /* class */, @@ -176,9 +173,11 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, CHECK(window_ != gfx::kNullAcceleratedWidget); gl_surface_ = gfx::GLSurface::CreateViewGLSurface(window_); + screen_size_ = gl_surface_->GetSize(); + gl_context_ = gfx::GLContext::CreateGLContext( NULL, gl_surface_.get(), gfx::PreferIntegratedGpu); - gl_context_->MakeCurrent(gl_surface_.get()); + CHECK(gl_context_->MakeCurrent(gl_surface_.get())); CHECK_GT(params.window_sizes.size(), 0U); videos_.resize(params.window_sizes.size()); @@ -304,14 +303,16 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, glEnableVertexAttribArray(tc_location); glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); - if (frame_duration_ != base::TimeDelta()) - WarmUpRendering(params.warm_up_iterations); + if (frame_duration_ != base::TimeDelta()) { + int warm_up_iterations = params.warm_up_iterations; + WarmUpRendering(warm_up_iterations); + } // It's safe to use Unretained here since |rendering_thread_| will be stopped // in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is // a member of that class. (See video_decode_accelerator_unittest.cc.) gfx::VSyncProvider* vsync_provider = gl_surface_->GetVSyncProvider(); - if (vsync_provider) + if (vsync_provider && frame_duration_ != base::TimeDelta()) vsync_provider->GetVSyncParameters(base::Bind( &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done)); else @@ -323,7 +324,7 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, // several frames here to warm up the rendering. void RenderingHelper::WarmUpRendering(int warm_up_iterations) { unsigned int texture_id; - scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]); + scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]()); glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); glTexImage2D(GL_TEXTURE_2D, @@ -467,7 +468,11 @@ void RenderingHelper::DeleteTexture(uint32 texture_id) { CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); } -void* RenderingHelper::GetGLContext() { +scoped_refptr<gfx::GLContext> RenderingHelper::GetGLContext() { + return gl_context_; +} + +void* RenderingHelper::GetGLContextHandle() { return gl_context_->GetHandle(); } @@ -489,7 +494,7 @@ void RenderingHelper::Clear() { #if defined(OS_WIN) if (window_) DestroyWindow(window_); -#else +#elif defined(USE_X11) // Destroy resources acquired in Initialize, in reverse-acquisition order. if (window_) { CHECK(XUnmapWindow(gfx::GetXDisplay(), window_)); diff --git a/content/common/gpu/media/rendering_helper.h b/content/common/gpu/media/rendering_helper.h index e66c8d5..e013fa7 100644 --- a/content/common/gpu/media/rendering_helper.h +++ b/content/common/gpu/media/rendering_helper.h @@ -114,8 +114,11 @@ class RenderingHelper { // Get the platform specific handle to the OpenGL display. void* GetGLDisplay(); + // Get the GL context. + scoped_refptr<gfx::GLContext> GetGLContext(); + // Get the platform specific handle to the OpenGL context. - void* GetGLContext(); + void* GetGLContextHandle(); // Get rendered thumbnails as RGB. // Sets alpha_solid to true if the alpha channel is entirely 0xff. diff --git a/content/common/gpu/media/va.sigs b/content/common/gpu/media/va.sigs index 9906f9f..ffcf7b3 100644 --- a/content/common/gpu/media/va.sigs +++ b/content/common/gpu/media/va.sigs @@ -31,10 +31,3 @@ VAStatus vaSetDisplayAttributes(VADisplay dpy, VADisplayAttribute *attr_list, in VAStatus vaSyncSurface(VADisplay dpy, VASurfaceID render_target); VAStatus vaTerminate(VADisplay dpy); VAStatus vaUnmapBuffer(VADisplay dpy, VABufferID buf_id); - - -//------------------------------------------------ -// Functions from libva-x11 used in chromium code. -//------------------------------------------------ -VADisplay vaGetDisplay(Display *dpy); -VAStatus vaPutSurface(VADisplay dpy, VASurfaceID surface, Drawable draw, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, VARectangle *cliprects, unsigned int number_cliprects, unsigned int flags); diff --git a/content/common/gpu/media/va_surface.h b/content/common/gpu/media/va_surface.h index 88dfc2a..5934bc5 100644 --- a/content/common/gpu/media/va_surface.h +++ b/content/common/gpu/media/va_surface.h @@ -8,7 +8,11 @@ #ifndef CONTENT_COMMON_GPU_MEDIA_VA_SURFACE_H_ #define CONTENT_COMMON_GPU_MEDIA_VA_SURFACE_H_ +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "content/common/content_export.h" #include "third_party/libva/va/va.h" +#include "ui/gfx/size.h" namespace content { @@ -16,7 +20,7 @@ namespace content { // and use as reference for decoding other surfaces. It is also handed by the // decoder to VaapiVideoDecodeAccelerator when the contents of the surface are // ready and should be displayed. VAVDA converts the surface contents into an -// X Pixmap bound to a texture for display and releases its reference to it. +// X/Drm Pixmap bound to a texture for display and releases its reference to it. // Decoder releases its references to the surface when it's done decoding and // using it as reference. Note that a surface may still be used for reference // after it's been sent to output and also after it is no longer used by VAVDA. @@ -56,11 +60,11 @@ namespace content { // | VASurface to VaapiVideoDecodeAccelerator, VASurface as reference for // | which stores it (taking a ref) on decoding more frames. // | pending_output_cbs_ queue until an output | -// | TFPPicture becomes available. v +// | VaapiPicture becomes available. v // | | Once the DecodeSurface is not // | | needed as reference anymore, // | v it is released, releasing the -// | A TFPPicture becomes available after associated VASurface reference. +// | A VaapiPicture becomes available after associated VASurface reference. // | the client of VVDA returns | // | a PictureBuffer associated with it. VVDA | // | puts the contents of the VASurface into | @@ -84,17 +88,22 @@ class CONTENT_EXPORT VASurface : public base::RefCountedThreadSafe<VASurface> { // are released. typedef base::Callback<void(VASurfaceID)> ReleaseCB; - VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb); + VASurface(VASurfaceID va_surface_id, + const gfx::Size& size, + const ReleaseCB& release_cb); VASurfaceID id() { return va_surface_id_; } + const gfx::Size& size() const { return size_; } + private: friend class base::RefCountedThreadSafe<VASurface>; ~VASurface(); const VASurfaceID va_surface_id_; + gfx::Size size_; ReleaseCB release_cb_; DISALLOW_COPY_AND_ASSIGN(VASurface); diff --git a/content/common/gpu/media/va_x11.sigs b/content/common/gpu/media/va_x11.sigs new file mode 100644 index 0000000..d87356b --- /dev/null +++ b/content/common/gpu/media/va_x11.sigs @@ -0,0 +1,9 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//------------------------------------------------ +// Functions from libva-x11 used in chromium code. +//------------------------------------------------ +VADisplay vaGetDisplay(Display *dpy); +VAStatus vaPutSurface(VADisplay dpy, VASurfaceID surface, Drawable draw, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, VARectangle *cliprects, unsigned int number_cliprects, unsigned int flags); diff --git a/content/common/gpu/media/vaapi_h264_decoder_unittest.cc b/content/common/gpu/media/vaapi_h264_decoder_unittest.cc index becfd42..244c9ac 100644 --- a/content/common/gpu/media/vaapi_h264_decoder_unittest.cc +++ b/content/common/gpu/media/vaapi_h264_decoder_unittest.cc @@ -81,35 +81,25 @@ class VaapiH264DecoderLoop { // Use the data in the frame: write to file and update MD5 sum. bool ProcessVideoFrame(const scoped_refptr<media::VideoFrame>& frame); - scoped_ptr<VaapiWrapper> wrapper_; + scoped_refptr<VaapiWrapper> wrapper_; scoped_ptr<VaapiH264Decoder> decoder_; std::string data_; // data read from input_file base::FilePath output_file_; // output data is written to this file std::vector<VASurfaceID> available_surfaces_; - // These members (x_display_, num_outputted_pictures_, num_surfaces_) + // These members (num_outputted_pictures_, num_surfaces_) // need to be initialized and possibly freed manually. - Display* x_display_; int num_outputted_pictures_; // number of pictures already outputted size_t num_surfaces_; // number of surfaces in the current set of surfaces base::MD5Context md5_context_; }; VaapiH264DecoderLoop::VaapiH264DecoderLoop() - : x_display_(NULL), num_outputted_pictures_(0), num_surfaces_(0) { + : num_outputted_pictures_(0), num_surfaces_(0) { base::MD5Init(&md5_context_); } VaapiH264DecoderLoop::~VaapiH264DecoderLoop() { - // We need to destruct decoder and wrapper first because: - // (1) The decoder has a reference to the wrapper. - // (2) The wrapper has a reference to x_display_. - decoder_.reset(); - wrapper_.reset(); - - if (x_display_) { - XCloseDisplay(x_display_); - } } void LogOnError(VaapiH264Decoder::VAVDAH264DecoderFailure error) { @@ -118,17 +108,11 @@ void LogOnError(VaapiH264Decoder::VAVDAH264DecoderFailure error) { bool VaapiH264DecoderLoop::Initialize(base::FilePath input_file, base::FilePath output_file) { - x_display_ = XOpenDisplay(NULL); - if (!x_display_) { - LOG(ERROR) << "Can't open X display"; - return false; - } - media::VideoCodecProfile profile = media::H264PROFILE_BASELINE; base::Closure report_error_cb = base::Bind(&LogOnError, VaapiH264Decoder::VAAPI_ERROR); - wrapper_ = VaapiWrapper::Create( - VaapiWrapper::kDecode, profile, x_display_, report_error_cb); + wrapper_ = + VaapiWrapper::Create(VaapiWrapper::kDecode, profile, report_error_cb); if (!wrapper_.get()) { LOG(ERROR) << "Can't create vaapi wrapper"; return false; @@ -296,8 +280,8 @@ void VaapiH264DecoderLoop::RefillSurfaces() { for (size_t i = 0; i < available_surfaces_.size(); i++) { VASurface::ReleaseCB release_cb = base::Bind( &VaapiH264DecoderLoop::RecycleSurface, base::Unretained(this)); - scoped_refptr<VASurface> surface( - new VASurface(available_surfaces_[i], release_cb)); + scoped_refptr<VASurface> surface(new VASurface( + available_surfaces_[i], decoder_->GetPicSize(), release_cb)); decoder_->ReuseSurface(surface); } available_surfaces_.clear(); diff --git a/content/common/gpu/media/vaapi_picture.cc b/content/common/gpu/media/vaapi_picture.cc new file mode 100644 index 0000000..10de50b --- /dev/null +++ b/content/common/gpu/media/vaapi_picture.cc @@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/media/vaapi_picture.h" +#include "content/common/gpu/media/vaapi_wrapper.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_implementation.h" + +#if defined(USE_X11) +#include "content/common/gpu/media/vaapi_tfp_picture.h" +#endif + +namespace content { + +// static +linked_ptr<VaapiPicture> VaapiPicture::CreatePicture( + const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + const base::Callback<bool(void)> make_context_current, + int32 picture_buffer_id, + uint32 texture_id, + const gfx::Size& size) { + linked_ptr<VaapiPicture> picture; +#if defined(USE_X11) + picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current, + picture_buffer_id, texture_id, size)); +#endif // USE_X11 + + if (picture.get() && !picture->Initialize()) + picture.reset(); + + return picture; +} + +// static +uint32 VaapiPicture::GetGLTextureTarget() { + return GL_TEXTURE_2D; +} + +} // namespace content diff --git a/content/common/gpu/media/vaapi_picture.h b/content/common/gpu/media/vaapi_picture.h new file mode 100644 index 0000000..fdb7a7e --- /dev/null +++ b/content/common/gpu/media/vaapi_picture.h @@ -0,0 +1,73 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains an interface of output pictures for the Vaapi +// video decoder. This is implemented by different window system +// (X11/Ozone) and used by VaapiVideoDecodeAccelerator to produce +// output pictures. + +#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_ +#define CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_ + +#include "base/callback.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/threading/non_thread_safe.h" +#include "ui/gfx/size.h" + +namespace content { + +class VASurface; +class VaapiWrapper; + +// Picture is native pixmap abstraction (X11/Ozone). +class VaapiPicture : public base::NonThreadSafe { + public: + virtual ~VaapiPicture() {} + + // Try to allocate the underlying resources for the picture. + virtual bool Initialize() = 0; + + int32 picture_buffer_id() const { return picture_buffer_id_; } + uint32 texture_id() const { return texture_id_; } + const gfx::Size& size() const { return size_; } + + // Downloads the |va_surface| into the picture, potentially scaling + // it if needed. + virtual bool DownloadFromSurface( + const scoped_refptr<VASurface>& va_surface) = 0; + + // Create a VaapiPicture of |size| to be associated with + // |picture_buffer_id| and bound to |texture_id|. + // |make_context_current| is provided for the GL operations. + static linked_ptr<VaapiPicture> CreatePicture( + const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + const base::Callback<bool(void)> make_context_current, + int32 picture_buffer_id, + uint32 texture_id, + const gfx::Size& size); + + // Get the texture target used to bind EGLImages (either + // GL_TEXTURE_2D on X11 or GL_TEXTURE_EXTERNAL_OES on DRM). + static uint32 GetGLTextureTarget(); + + protected: + VaapiPicture(int32 picture_buffer_id, + uint32 texture_id, + const gfx::Size& size) + : picture_buffer_id_(picture_buffer_id), + texture_id_(texture_id), + size_(size) {} + + private: + int32 picture_buffer_id_; + uint32 texture_id_; + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(VaapiPicture); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_PICTURE_H_ diff --git a/content/common/gpu/media/vaapi_tfp_picture.cc b/content/common/gpu/media/vaapi_tfp_picture.cc new file mode 100644 index 0000000..e914418 --- /dev/null +++ b/content/common/gpu/media/vaapi_tfp_picture.cc @@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/media/va_surface.h" +#include "content/common/gpu/media/vaapi_tfp_picture.h" +#include "content/common/gpu/media/vaapi_wrapper.h" +#include "ui/gfx/x/x11_types.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_image_glx.h" +#include "ui/gl/scoped_binders.h" + +namespace content { + +VaapiTFPPicture::VaapiTFPPicture( + const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + const base::Callback<bool(void)> make_context_current, + int32 picture_buffer_id, + uint32 texture_id, + const gfx::Size& size) + : VaapiPicture(picture_buffer_id, texture_id, size), + vaapi_wrapper_(vaapi_wrapper), + make_context_current_(make_context_current), + x_display_(gfx::GetXDisplay()), + x_pixmap_(0) { +} + +VaapiTFPPicture::~VaapiTFPPicture() { + if (glx_image_.get() && make_context_current_.Run()) { + glx_image_->ReleaseTexImage(GL_TEXTURE_2D); + glx_image_->Destroy(true); + DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); + } + + if (x_pixmap_) + XFreePixmap(x_display_, x_pixmap_); +} + +bool VaapiTFPPicture::Initialize() { + if (!make_context_current_.Run()) + return false; + + XWindowAttributes win_attr; + int screen = DefaultScreen(x_display_); + XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); + // TODO(posciak): pass the depth required by libva, not the RootWindow's + // depth + x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), + size().width(), size().height(), win_attr.depth); + if (!x_pixmap_) { + LOG(ERROR) << "Failed creating an X Pixmap for TFP"; + return false; + } + + glx_image_ = new gfx::GLImageGLX(size(), GL_RGB); + if (!glx_image_->Initialize(x_pixmap_)) { + // x_pixmap_ will be freed in the destructor. + LOG(ERROR) << "Failed creating a GLX Pixmap for TFP"; + return false; + } + + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id()); + if (!glx_image_->BindTexImage(GL_TEXTURE_2D)) { + LOG(ERROR) << "Failed to bind texture to glx image"; + return false; + } + + return true; +} + +bool VaapiTFPPicture::DownloadFromSurface( + const scoped_refptr<VASurface>& va_surface) { + return vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(), x_pixmap_, + va_surface->size()); +} + +} // namespace content diff --git a/content/common/gpu/media/vaapi_tfp_picture.h b/content/common/gpu/media/vaapi_tfp_picture.h new file mode 100644 index 0000000..a3208da --- /dev/null +++ b/content/common/gpu/media/vaapi_tfp_picture.h @@ -0,0 +1,56 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains an implementation of picture allocation for the +// X11 window system used by VaapiVideoDecodeAccelerator to produce +// output pictures. + +#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_ +#define CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "content/common/gpu/media/vaapi_picture.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_bindings.h" + +namespace gfx { +class GLImageGLX; +class GLContextGLX; +} + +namespace content { + +class VaapiWrapper; + +// Implementation of VaapiPicture for the X11 backed chromium. +class VaapiTFPPicture : public VaapiPicture { + public: + VaapiTFPPicture(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, + const base::Callback<bool(void)> make_context_current, + int32 picture_buffer_id, + uint32 texture_id, + const gfx::Size& size); + + ~VaapiTFPPicture() override; + + bool Initialize() override; + + bool DownloadFromSurface(const scoped_refptr<VASurface>& va_surface) override; + + private: + scoped_refptr<VaapiWrapper> vaapi_wrapper_; + + base::Callback<bool(void)> make_context_current_; + Display* x_display_; + + Pixmap x_pixmap_; + scoped_refptr<gfx::GLImageGLX> glx_image_; + + DISALLOW_COPY_AND_ASSIGN(VaapiTFPPicture); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_TFP_PICTURE_H_ diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc index df1f644..df9ec59 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc @@ -9,13 +9,12 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/synchronization/waitable_event.h" -#include "base/threading/non_thread_safe.h" #include "content/common/gpu/gpu_channel.h" +#include "content/common/gpu/media/vaapi_picture.h" #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" #include "media/base/bind_to_current_loop.h" #include "media/video/picture.h" #include "ui/gl/gl_bindings.h" -#include "ui/gl/scoped_binders.h" static void ReportToUMA( content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { @@ -61,164 +60,10 @@ void VaapiVideoDecodeAccelerator::NotifyError(Error error) { } } -// TFPPicture allocates X Pixmaps and binds them to textures passed -// in PictureBuffers from clients to them. TFPPictures are created as -// a consequence of receiving a set of PictureBuffers from clients and released -// at the end of decode (or when a new set of PictureBuffers is required). -// -// TFPPictures are used for output, contents of VASurfaces passed from decoder -// are put into the associated pixmap memory and sent to client. -class VaapiVideoDecodeAccelerator::TFPPicture : public base::NonThreadSafe { - public: - ~TFPPicture(); - - static linked_ptr<TFPPicture> Create( - const base::Callback<bool(void)>& make_context_current, - const GLXFBConfig& fb_config, - Display* x_display, - int32 picture_buffer_id, - uint32 texture_id, - gfx::Size size); - - int32 picture_buffer_id() { - return picture_buffer_id_; - } - - gfx::Size size() { - return size_; - } - - int x_pixmap() { - return x_pixmap_; - } - - // Bind texture to pixmap. Needs to be called every frame. - bool Bind(); - - private: - TFPPicture(const base::Callback<bool(void)>& make_context_current, - Display* x_display, - int32 picture_buffer_id, - uint32 texture_id, - gfx::Size size); - - bool Initialize(const GLXFBConfig& fb_config); - - base::Callback<bool(void)> make_context_current_; - - Display* x_display_; - - // Output id for the client. - int32 picture_buffer_id_; - uint32 texture_id_; - - gfx::Size size_; - - // Pixmaps bound to this texture. - Pixmap x_pixmap_; - GLXPixmap glx_pixmap_; - - DISALLOW_COPY_AND_ASSIGN(TFPPicture); -}; - -VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture( - const base::Callback<bool(void)>& make_context_current, - Display* x_display, - int32 picture_buffer_id, - uint32 texture_id, - gfx::Size size) - : make_context_current_(make_context_current), - x_display_(x_display), - picture_buffer_id_(picture_buffer_id), - texture_id_(texture_id), - size_(size), - x_pixmap_(0), - glx_pixmap_(0) { - DCHECK(!make_context_current_.is_null()); -}; - -linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture> -VaapiVideoDecodeAccelerator::TFPPicture::Create( - const base::Callback<bool(void)>& make_context_current, - const GLXFBConfig& fb_config, - Display* x_display, - int32 picture_buffer_id, - uint32 texture_id, - gfx::Size size) { - - linked_ptr<TFPPicture> tfp_picture( - new TFPPicture(make_context_current, x_display, picture_buffer_id, - texture_id, size)); - - if (!tfp_picture->Initialize(fb_config)) - tfp_picture.reset(); - - return tfp_picture; -} - -bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( - const GLXFBConfig& fb_config) { - DCHECK(CalledOnValidThread()); - if (!make_context_current_.Run()) - return false; - - XWindowAttributes win_attr; - int screen = DefaultScreen(x_display_); - XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); - //TODO(posciak): pass the depth required by libva, not the RootWindow's depth - x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), - size_.width(), size_.height(), win_attr.depth); - if (!x_pixmap_) { - LOG(ERROR) << "Failed creating an X Pixmap for TFP"; - return false; - } - - static const int pixmap_attr[] = { - GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, - GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, - GL_NONE, - }; - - glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr); - if (!glx_pixmap_) { - // x_pixmap_ will be freed in the destructor. - LOG(ERROR) << "Failed creating a GLX Pixmap for TFP"; - return false; - } - - return true; -} - -VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { - DCHECK(CalledOnValidThread()); - // Unbind surface from texture and deallocate resources. - if (glx_pixmap_ && make_context_current_.Run()) { - glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); - glXDestroyPixmap(x_display_, glx_pixmap_); - } - - if (x_pixmap_) - XFreePixmap(x_display_, x_pixmap_); - XSync(x_display_, False); // Needed to work around buggy vdpau-driver. -} - -bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { - DCHECK(CalledOnValidThread()); - DCHECK(x_pixmap_); - DCHECK(glx_pixmap_); - if (!make_context_current_.Run()) - return false; - - gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_); - glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); - - return true; -} - -VaapiVideoDecodeAccelerator::TFPPicture* - VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) { - TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id); - if (it == tfp_pictures_.end()) { +VaapiPicture* VaapiVideoDecodeAccelerator::PictureById( + int32 picture_buffer_id) { + Pictures::iterator it = pictures_.find(picture_buffer_id); + if (it == pictures_.end()) { LOG(ERROR) << "Picture id " << picture_buffer_id << " does not exist"; return NULL; } @@ -227,10 +72,8 @@ VaapiVideoDecodeAccelerator::TFPPicture* } VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( - Display* x_display, const base::Callback<bool(void)>& make_context_current) - : x_display_(x_display), - make_context_current_(make_context_current), + : make_context_current_(make_context_current), state_(kUninitialized), input_ready_(&lock_), surfaces_available_(&lock_), @@ -251,35 +94,6 @@ VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { DCHECK_EQ(message_loop_, base::MessageLoop::current()); } -class XFreeDeleter { - public: - void operator()(void* x) const { - ::XFree(x); - } -}; - -bool VaapiVideoDecodeAccelerator::InitializeFBConfig() { - const int fbconfig_attr[] = { - GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, - GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, - GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE, - GLX_Y_INVERTED_EXT, GL_TRUE, - GL_NONE, - }; - - int num_fbconfigs; - scoped_ptr<GLXFBConfig, XFreeDeleter> glx_fb_configs( - glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr, - &num_fbconfigs)); - if (!glx_fb_configs) - return false; - if (!num_fbconfigs) - return false; - - fb_config_ = glx_fb_configs.get()[0]; - return true; -} - bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, Client* client) { DCHECK_EQ(message_loop_, base::MessageLoop::current()); @@ -291,18 +105,17 @@ bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, DCHECK_EQ(state_, kUninitialized); DVLOG(2) << "Initializing VAVDA, profile: " << profile; - if (!make_context_current_.Run()) - return false; - - if (!InitializeFBConfig()) { - LOG(ERROR) << "Could not get a usable FBConfig"; +#if defined(USE_X11) + if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) { + DVLOG(1) << "HW video decode acceleration not available without " + "DesktopGL (GLX)."; return false; } +#endif // USE_X11 vaapi_wrapper_ = VaapiWrapper::Create( VaapiWrapper::kDecode, profile, - x_display_, base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); if (!vaapi_wrapper_.get()) { @@ -344,10 +157,10 @@ void VaapiVideoDecodeAccelerator::SurfaceReady( void VaapiVideoDecodeAccelerator::OutputPicture( const scoped_refptr<VASurface>& va_surface, int32 input_id, - TFPPicture* tfp_picture) { + VaapiPicture* picture) { DCHECK_EQ(message_loop_, base::MessageLoop::current()); - int32 output_id = tfp_picture->picture_buffer_id(); + int32 output_id = picture->picture_buffer_id(); TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", "input_id", input_id, @@ -356,16 +169,10 @@ void VaapiVideoDecodeAccelerator::OutputPicture( DVLOG(3) << "Outputting VASurface " << va_surface->id() << " into pixmap bound to picture buffer id " << output_id; - RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(), - "Failed binding texture to pixmap", + RETURN_AND_NOTIFY_ON_FAILURE(picture->DownloadFromSurface(va_surface), + "Failed putting surface into pixmap", PLATFORM_FAILURE, ); - RETURN_AND_NOTIFY_ON_FAILURE( - vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(), - tfp_picture->x_pixmap(), - tfp_picture->size()), - "Failed putting surface into pixmap", PLATFORM_FAILURE, ); - // Notify the client a picture is ready to be displayed. ++num_frames_at_client_; TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); @@ -375,7 +182,7 @@ void VaapiVideoDecodeAccelerator::OutputPicture( // (crbug.com/402760). if (client_) client_->PictureReady( - media::Picture(output_id, input_id, gfx::Rect(tfp_picture->size()))); + media::Picture(output_id, input_id, gfx::Rect(picture->size()))); } void VaapiVideoDecodeAccelerator::TryOutputSurface() { @@ -391,11 +198,11 @@ void VaapiVideoDecodeAccelerator::TryOutputSurface() { OutputCB output_cb = pending_output_cbs_.front(); pending_output_cbs_.pop(); - TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front()); - DCHECK(tfp_picture); + VaapiPicture* picture = PictureById(output_buffers_.front()); + DCHECK(picture); output_buffers_.pop(); - output_cb.Run(tfp_picture); + output_cb.Run(picture); if (finish_flush_pending_ && pending_output_cbs_.empty()) FinishFlush(); @@ -506,7 +313,8 @@ bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { while (!available_va_surfaces_.empty()) { scoped_refptr<VASurface> va_surface( - new VASurface(available_va_surfaces_.front(), va_surface_release_cb_)); + new VASurface(available_va_surfaces_.front(), requested_pic_size_, + va_surface_release_cb_)); available_va_surfaces_.pop_front(); decoder_->ReuseSurface(va_surface); } @@ -598,7 +406,7 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { return; if (!pending_output_cbs_.empty() || - tfp_pictures_.size() != available_va_surfaces_.size()) { + pictures_.size() != available_va_surfaces_.size()) { // Either: // 1. Not all pending pending output callbacks have been executed yet. // Wait for the client to return enough pictures and retry later. @@ -616,21 +424,22 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { available_va_surfaces_.clear(); vaapi_wrapper_->DestroySurfaces(); - for (TFPPictures::iterator iter = tfp_pictures_.begin(); - iter != tfp_pictures_.end(); ++iter) { + for (Pictures::iterator iter = pictures_.begin(); iter != pictures_.end(); + ++iter) { DVLOG(2) << "Dismissing picture id: " << iter->first; if (client_) client_->DismissPictureBuffer(iter->first); } - tfp_pictures_.clear(); + pictures_.clear(); // And ask for a new set as requested. DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: " << requested_pic_size_.ToString(); - message_loop_->PostTask(FROM_HERE, base::Bind( - &Client::ProvidePictureBuffers, client_, - requested_num_pics_, requested_pic_size_, GL_TEXTURE_2D)); + message_loop_->PostTask( + FROM_HERE, + base::Bind(&Client::ProvidePictureBuffers, client_, requested_num_pics_, + requested_pic_size_, VaapiPicture::GetGLTextureTarget())); } void VaapiVideoDecodeAccelerator::Decode( @@ -682,7 +491,7 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( DCHECK_EQ(message_loop_, base::MessageLoop::current()); base::AutoLock auto_lock(lock_); - DCHECK(tfp_pictures_.empty()); + DCHECK(pictures_.empty()); while (!output_buffers_.empty()) output_buffers_.pop(); @@ -706,17 +515,16 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( << " to texture id: " << buffers[i].texture_id() << " VASurfaceID: " << va_surface_ids[i]; - linked_ptr<TFPPicture> tfp_picture( - TFPPicture::Create(make_context_current_, fb_config_, x_display_, - buffers[i].id(), buffers[i].texture_id(), - requested_pic_size_)); + linked_ptr<VaapiPicture> picture(VaapiPicture::CreatePicture( + vaapi_wrapper_, make_context_current_, buffers[i].id(), + buffers[i].texture_id(), requested_pic_size_)); RETURN_AND_NOTIFY_ON_FAILURE( - tfp_picture.get(), "Failed assigning picture buffer to a texture.", + picture.get(), "Failed assigning picture buffer to a texture.", PLATFORM_FAILURE, ); - bool inserted = tfp_pictures_.insert(std::make_pair( - buffers[i].id(), tfp_picture)).second; + bool inserted = + pictures_.insert(std::make_pair(buffers[i].id(), picture)).second; DCHECK(inserted); output_buffers_.push(buffers[i].id()); diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h index 5d65da7..afd0a1c 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.h +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h @@ -20,7 +20,6 @@ #include "base/message_loop/message_loop.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" -#include "base/threading/non_thread_safe.h" #include "base/threading/thread.h" #include "content/common/content_export.h" #include "content/common/gpu/media/vaapi_h264_decoder.h" @@ -28,10 +27,11 @@ #include "media/base/bitstream_buffer.h" #include "media/video/picture.h" #include "media/video/video_decode_accelerator.h" -#include "ui/gl/gl_bindings.h" namespace content { +class VaapiPicture; + // Class to provide video decode acceleration for Intel systems with hardware // support for it, and on which libva is available. // Decoding tasks are performed in a separate decoding thread. @@ -44,7 +44,6 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: VaapiVideoDecodeAccelerator( - Display* x_display, const base::Callback<bool(void)>& make_context_current); virtual ~VaapiVideoDecodeAccelerator(); @@ -123,16 +122,13 @@ private: // |va_surface|. void SurfaceReady(int32 input_id, const scoped_refptr<VASurface>& va_surface); - // Represents a texture bound to an X Pixmap for output purposes. - class TFPPicture; - // Callback to be executed once we have a |va_surface| to be output and - // an available |tfp_picture| to use for output. - // Puts contents of |va_surface| into given |tfp_picture|, releases the + // an available |picture| to use for output. + // Puts contents of |va_surface| into given |picture|, releases the // surface and passes the resulting picture to client for output. void OutputPicture(const scoped_refptr<VASurface>& va_surface, int32 input_id, - TFPPicture* tfp_picture); + VaapiPicture* picture); // Try to OutputPicture() if we have both a ready surface and picture. void TryOutputSurface(); @@ -148,10 +144,8 @@ private: // Check if the surfaces have been released or post ourselves for later. void TryFinishSurfaceSetChange(); - // Client-provided X/GLX state. - Display* x_display_; + // Client-provided GL state. base::Callback<bool(void)> make_context_current_; - GLXFBConfig fb_config_; // VAVDA state. enum State { @@ -196,13 +190,13 @@ private: typedef std::queue<int32> OutputBuffers; OutputBuffers output_buffers_; - typedef std::map<int32, linked_ptr<TFPPicture> > TFPPictures; - // All allocated TFPPictures, regardless of their current state. TFPPictures - // are allocated once and destroyed at the end of decode. - TFPPictures tfp_pictures_; + typedef std::map<int32, linked_ptr<VaapiPicture>> Pictures; + // All allocated Pictures, regardless of their current state. + // Pictures are allocated once and destroyed at the end of decode. + Pictures pictures_; // Return a TFPPicture associated with given client-provided id. - TFPPicture* TFPPictureById(int32 picture_buffer_id); + VaapiPicture* PictureById(int32 picture_buffer_id); // VA Surfaces no longer in use that can be passed back to the decoder for // reuse, once it requests them. @@ -212,15 +206,15 @@ private: base::ConditionVariable surfaces_available_; // Pending output requests from the decoder. When it indicates that we should - // output a surface and we have an available TFPPicture (i.e. texture) ready - // to use, we'll execute the callback passing the TFPPicture. The callback + // output a surface and we have an available Picture (i.e. texture) ready + // to use, we'll execute the callback passing the Picture. The callback // will put the contents of the surface into the picture and return it to // the client, releasing the surface as well. - // If we don't have any available TFPPictures at the time when the decoder + // If we don't have any available Pictures at the time when the decoder // requests output, we'll store the request on pending_output_cbs_ queue for // later and run it once the client gives us more textures // via ReusePictureBuffer(). - typedef base::Callback<void(TFPPicture*)> OutputCB; + typedef base::Callback<void(VaapiPicture*)> OutputCB; std::queue<OutputCB> pending_output_cbs_; // ChildThread's message loop @@ -242,7 +236,7 @@ private: scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_; base::WeakPtr<Client> client_; - scoped_ptr<VaapiWrapper> vaapi_wrapper_; + scoped_refptr<VaapiWrapper> vaapi_wrapper_; // Comes after vaapi_wrapper_ to ensure its destructor is executed before // vaapi_wrapper_ is destroyed. diff --git a/content/common/gpu/media/vaapi_video_encode_accelerator.cc b/content/common/gpu/media/vaapi_video_encode_accelerator.cc index 19e1c08..fa3a600 100644 --- a/content/common/gpu/media/vaapi_video_encode_accelerator.cc +++ b/content/common/gpu/media/vaapi_video_encode_accelerator.cc @@ -113,8 +113,7 @@ VaapiVideoEncodeAccelerator::GetSupportedProfiles() { return profiles; std::vector<media::VideoCodecProfile> hw_profiles = - VaapiWrapper::GetSupportedEncodeProfiles( - x_display_, base::Bind(&base::DoNothing)); + VaapiWrapper::GetSupportedEncodeProfiles(base::Bind(&base::DoNothing)); media::VideoEncodeAccelerator::SupportedProfile profile; profile.max_resolution.SetSize(1920, 1088); @@ -139,12 +138,11 @@ static unsigned int Log2OfPowerOf2(unsigned int x) { return log; } -VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator(Display* x_display) +VaapiVideoEncodeAccelerator::VaapiVideoEncodeAccelerator() : profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), mb_width_(0), mb_height_(0), output_buffer_byte_size_(0), - x_display_(x_display), state_(kUninitialized), frame_num_(0), last_idr_frame_num_(0), @@ -217,9 +215,8 @@ bool VaapiVideoEncodeAccelerator::Initialize( vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kEncode, output_profile, - x_display_, base::Bind(&ReportToUMA, VAAPI_ERROR)); - if (!vaapi_wrapper_) { + if (!vaapi_wrapper_.get()) { LOG(ERROR) << "Failed initializing VAAPI"; return false; } @@ -604,12 +601,12 @@ bool VaapiVideoEncodeAccelerator::PrepareNextJob() { return false; } - current_encode_job_->input_surface = - new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); + current_encode_job_->input_surface = new VASurface( + available_va_surface_ids_.back(), coded_size_, va_surface_release_cb_); available_va_surface_ids_.pop_back(); - current_encode_job_->recon_surface = - new VASurface(available_va_surface_ids_.back(), va_surface_release_cb_); + current_encode_job_->recon_surface = new VASurface( + available_va_surface_ids_.back(), coded_size_, va_surface_release_cb_); available_va_surface_ids_.pop_back(); // Reference surfaces are needed until the job is done, but they get diff --git a/content/common/gpu/media/vaapi_video_encode_accelerator.h b/content/common/gpu/media/vaapi_video_encode_accelerator.h index 520228c..a12bb63 100644 --- a/content/common/gpu/media/vaapi_video_encode_accelerator.h +++ b/content/common/gpu/media/vaapi_video_encode_accelerator.h @@ -25,7 +25,7 @@ namespace content { class CONTENT_EXPORT VaapiVideoEncodeAccelerator : public media::VideoEncodeAccelerator { public: - explicit VaapiVideoEncodeAccelerator(Display* x_display); + VaapiVideoEncodeAccelerator(); virtual ~VaapiVideoEncodeAccelerator(); // media::VideoEncodeAccelerator implementation. @@ -151,7 +151,7 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator // VaapiWrapper is the owner of all HW resources (surfaces and buffers) // and will free them on destruction. - scoped_ptr<VaapiWrapper> vaapi_wrapper_; + scoped_refptr<VaapiWrapper> vaapi_wrapper_; // Input profile and sizes. media::VideoCodecProfile profile_; @@ -178,8 +178,6 @@ class CONTENT_EXPORT VaapiVideoEncodeAccelerator // Size in bytes required for input bitstream buffers. size_t output_buffer_byte_size_; - Display* x_display_; - // All of the members below must be accessed on the encoder_thread_, // while it is running. diff --git a/content/common/gpu/media/vaapi_wrapper.cc b/content/common/gpu/media/vaapi_wrapper.cc index 93f1b61..f554be9 100644 --- a/content/common/gpu/media/vaapi_wrapper.cc +++ b/content/common/gpu/media/vaapi_wrapper.cc @@ -13,16 +13,20 @@ #include "base/sys_info.h" // Auto-generated for dlopen libva libraries #include "content/common/gpu/media/va_stubs.h" +#include "content/common/gpu/media/vaapi_picture.h" #include "third_party/libyuv/include/libyuv.h" +#include "ui/gl/gl_bindings.h" +#if defined(USE_X11) +#include "ui/gfx/x/x11_types.h" +#endif // USE_X11 using content_common_gpu_media::kModuleVa; +#if defined(USE_X11) +using content_common_gpu_media::kModuleVa_x11; +#endif // USE_X11 using content_common_gpu_media::InitializeStubs; using content_common_gpu_media::StubPathMap; -// libva-x11 depends on libva, so dlopen libva-x11 is enough -static const base::FilePath::CharType kVaLib[] = - FILE_PATH_LITERAL("libva-x11.so.1"); - #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ do { \ LOG(ERROR) << err_msg \ @@ -123,9 +127,10 @@ static VAProfile ProfileToVAProfile( return va_profile; } -VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb) - : va_surface_id_(va_surface_id), - release_cb_(release_cb) { +VASurface::VASurface(VASurfaceID va_surface_id, + const gfx::Size& size, + const ReleaseCB& release_cb) + : va_surface_id_(va_surface_id), size_(size), release_cb_(release_cb) { DCHECK(!release_cb_.is_null()); } @@ -147,27 +152,24 @@ VaapiWrapper::~VaapiWrapper() { Deinitialize(); } -scoped_ptr<VaapiWrapper> VaapiWrapper::Create( +scoped_refptr<VaapiWrapper> VaapiWrapper::Create( CodecMode mode, media::VideoCodecProfile profile, - Display* x_display, const base::Closure& report_error_to_uma_cb) { - scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); + scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); - if (!vaapi_wrapper->Initialize( - mode, profile, x_display, report_error_to_uma_cb)) - vaapi_wrapper.reset(); + if (!vaapi_wrapper->Initialize(mode, profile, report_error_to_uma_cb)) + vaapi_wrapper = NULL; - return vaapi_wrapper.Pass(); + return vaapi_wrapper; } std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( - Display* x_display, const base::Closure& report_error_to_uma_cb) { std::vector<media::VideoCodecProfile> supported_profiles; - scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); - if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) { + scoped_refptr<VaapiWrapper> wrapper(new VaapiWrapper()); + if (!wrapper->VaInitialize(report_error_to_uma_cb)) { return supported_profiles; } @@ -202,8 +204,7 @@ void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; } -bool VaapiWrapper::VaInitialize(Display* x_display, - const base::Closure& report_error_to_uma_cb) { +bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) { static bool vaapi_functions_initialized = PostSandboxInitialization(); if (!vaapi_functions_initialized) { bool running_on_chromeos = false; @@ -224,7 +225,10 @@ bool VaapiWrapper::VaInitialize(Display* x_display, base::AutoLock auto_lock(va_lock_); - va_display_ = vaGetDisplay(x_display); +#if defined(USE_X11) + va_display_ = vaGetDisplay(gfx::GetXDisplay()); +#endif // USE_X11 + if (!vaDisplayIsValid(va_display_)) { LOG(ERROR) << "Could not get a valid VA display"; return false; @@ -321,9 +325,8 @@ bool VaapiWrapper::AreAttribsSupported( bool VaapiWrapper::Initialize(CodecMode mode, media::VideoCodecProfile profile, - Display* x_display, const base::Closure& report_error_to_uma_cb) { - if (!VaInitialize(x_display, report_error_to_uma_cb)) + if (!VaInitialize(report_error_to_uma_cb)) return false; std::vector<VAProfile> supported_va_profiles; if (!GetSupportedVaProfiles(&supported_va_profiles)) @@ -383,7 +386,7 @@ bool VaapiWrapper::VAAPIVersionLessThan(int major, int minor) { (major_version_ == major && minor_version_ < minor); } -bool VaapiWrapper::CreateSurfaces(gfx::Size size, +bool VaapiWrapper::CreateSurfaces(const gfx::Size& size, size_t num_surfaces, std::vector<VASurfaceID>* va_surfaces) { base::AutoLock auto_lock(va_lock_); @@ -593,25 +596,6 @@ bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { return result; } -bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, - Pixmap x_pixmap, - gfx::Size dest_size) { - base::AutoLock auto_lock(va_lock_); - - VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); - VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); - - // Put the data into an X Pixmap. - va_res = vaPutSurface(va_display_, - va_surface_id, - x_pixmap, - 0, 0, dest_size.width(), dest_size.height(), - 0, 0, dest_size.width(), dest_size.height(), - NULL, 0, 0); - VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); - return true; -} - bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, VAImage* image, void** mem) { @@ -752,10 +736,33 @@ bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id, return buffer_segment == NULL; } +#if defined(USE_X11) +bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, + Pixmap x_pixmap, + gfx::Size dest_size) { + base::AutoLock auto_lock(va_lock_); + + VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); + VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); + + // Put the data into an X Pixmap. + va_res = vaPutSurface(va_display_, va_surface_id, x_pixmap, 0, 0, + dest_size.width(), dest_size.height(), 0, 0, + dest_size.width(), dest_size.height(), NULL, 0, 0); + VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); + return true; +} +#endif // USE_X11 + // static bool VaapiWrapper::PostSandboxInitialization() { StubPathMap paths; - paths[kModuleVa].push_back(kVaLib); + + paths[kModuleVa].push_back("libva.so.1"); + +#if defined(USE_X11) + paths[kModuleVa_x11].push_back("libva-x11.so.1"); +#endif return InitializeStubs(paths); } diff --git a/content/common/gpu/media/vaapi_wrapper.h b/content/common/gpu/media/vaapi_wrapper.h index 4efb558..ad0e807 100644 --- a/content/common/gpu/media/vaapi_wrapper.h +++ b/content/common/gpu/media/vaapi_wrapper.h @@ -13,15 +13,17 @@ #include <set> #include <vector> -#include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" #include "content/common/content_export.h" #include "content/common/gpu/media/va_surface.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" -#include "third_party/libva/va/va_x11.h" +#include "third_party/libva/va/va.h" #include "ui/gfx/size.h" +#if defined(USE_X11) +#include "third_party/libva/va/va_x11.h" +#endif // USE_X11 namespace content { @@ -35,7 +37,8 @@ namespace content { // It is also responsible for managing and freeing VABuffers (not VASurfaces), // which are used to queue parameters and slice data to the HW codec, // as well as underlying memory for VASurfaces themselves. -class CONTENT_EXPORT VaapiWrapper { +class CONTENT_EXPORT VaapiWrapper + : public base::RefCountedThreadSafe<VaapiWrapper> { public: enum CodecMode { kDecode, @@ -44,19 +47,15 @@ class CONTENT_EXPORT VaapiWrapper { // |report_error_to_uma_cb| will be called independently from reporting // errors to clients via method return values. - static scoped_ptr<VaapiWrapper> Create( + static scoped_refptr<VaapiWrapper> Create( CodecMode mode, media::VideoCodecProfile profile, - Display* x_display, const base::Closure& report_error_to_uma_cb); // Return the supported encode profiles. static std::vector<media::VideoCodecProfile> GetSupportedEncodeProfiles( - Display* x_display, const base::Closure& report_error_to_uma_cb); - ~VaapiWrapper(); - // Create |num_surfaces| backing surfaces in driver for VASurfaces, each // of size |size|. Returns true when successful, with the created IDs in // |va_surfaces| to be managed and later wrapped in VASurfaces. @@ -64,7 +63,7 @@ class CONTENT_EXPORT VaapiWrapper { // again to free the allocated surfaces first, but is not required to do so // at destruction time, as this will be done automatically from // the destructor. - bool CreateSurfaces(gfx::Size size, + bool CreateSurfaces(const gfx::Size& size, size_t num_surfaces, std::vector<VASurfaceID>* va_surfaces); @@ -97,12 +96,6 @@ class CONTENT_EXPORT VaapiWrapper { // buffers. Return false if Execute() fails. bool ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id); - // Put data from |va_surface_id| into |x_pixmap| of size |size|, - // converting/scaling to it. - bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id, - Pixmap x_pixmap, - gfx::Size dest_size); - // Returns true if the VAAPI version is less than the specified version. bool VAAPIVersionLessThan(int major, int minor); @@ -139,16 +132,24 @@ class CONTENT_EXPORT VaapiWrapper { // Destroy all previously-allocated (and not yet destroyed) coded buffers. void DestroyCodedBuffers(); +#if defined(USE_X11) + // Put data from |va_surface_id| into |x_pixmap| of size + // |dest_size|, converting/scaling to it. + bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id, + Pixmap x_pixmap, + gfx::Size dest_size); +#endif // USE_X11 + private: + friend class base::RefCountedThreadSafe<VaapiWrapper>; VaapiWrapper(); + ~VaapiWrapper(); bool Initialize(CodecMode mode, media::VideoCodecProfile profile, - Display* x_display, - const base::Closure& report_error_to_uma_cb); + const base::Closure& report_error__to_uma_cb); void Deinitialize(); - bool VaInitialize(Display* x_display, - const base::Closure& report_error_to_uma_cb); + bool VaInitialize(const base::Closure& report_error_to_uma_cb); bool GetSupportedVaProfiles(std::vector<VAProfile>* profiles); bool IsEntrypointSupported(VAProfile va_profile, VAEntrypoint entrypoint); bool AreAttribsSupported(VAProfile va_profile, @@ -179,7 +180,7 @@ class CONTENT_EXPORT VaapiWrapper { int major_version_, minor_version_; // VA handles. - // Both valid after successful Initialize() and until Deinitialize(). + // All valid after successful Initialize() and until Deinitialize(). VADisplay va_display_; VAConfigID va_config_id_; // Created for the current set of va_surface_ids_ in CreateSurfaces() and diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc index b9fc7de5..382f7b5 100644 --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc @@ -60,9 +60,6 @@ #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" #include "content/common/gpu/media/vaapi_wrapper.h" -#if defined(USE_X11) -#include "ui/gl/gl_implementation.h" -#endif // USE_X11 #else #error The VideoAccelerator tests are not supported on this platform. #endif // OS_WIN @@ -411,17 +408,12 @@ void GLRenderingVDAClient::CreateAndStartDecoder() { } decoder_.reset(new V4L2VideoDecodeAccelerator( static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), - static_cast<EGLContext>(rendering_helper_->GetGLContext()), - weak_client, - base::Bind(&DoNothingReturnTrue), - device.Pass(), + static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()), + weak_client, base::Bind(&DoNothingReturnTrue), device.Pass(), base::MessageLoopProxy::current())); #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation()) - << "Hardware video decode does not work with OSMesa"; - decoder_.reset(new VaapiVideoDecodeAccelerator( - static_cast<Display*>(rendering_helper_->GetGLDisplay()), - base::Bind(&DoNothingReturnTrue))); + decoder_.reset( + new VaapiVideoDecodeAccelerator(base::Bind(&DoNothingReturnTrue))); #endif // OS_WIN CHECK(decoder_.get()); weak_decoder_factory_.reset( diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc index 4c57f4f..cc3779b 100644 --- a/content/common/gpu/media/video_encode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc @@ -22,13 +22,9 @@ #include "media/video/video_encode_accelerator.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_X11) -#include "ui/gfx/x/x11_types.h" -#endif - #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" -#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" #else #error The VideoEncodeAcceleratorUnittest is not supported on this platform. @@ -720,8 +716,8 @@ void VEAClient::CreateEncoder() { #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder); encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass())); -#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) - encoder_.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay())); +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + encoder_.reset(new VaapiVideoEncodeAccelerator()); #endif SetState(CS_ENCODER_SET); diff --git a/content/content_common.gypi b/content/content_common.gypi index 4944e98..f62387e 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -779,7 +779,7 @@ '<(DEPTH)/third_party/khronos', ], }], - ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', { + ['target_arch != "arm" and chromeos == 1', { 'dependencies': [ '../media/media.gyp:media', '../third_party/libyuv/libyuv.gyp:libyuv', @@ -790,6 +790,8 @@ 'common/gpu/media/va_surface.h', 'common/gpu/media/vaapi_h264_decoder.cc', 'common/gpu/media/vaapi_h264_decoder.h', + 'common/gpu/media/vaapi_picture.cc', + 'common/gpu/media/vaapi_picture.h', 'common/gpu/media/vaapi_video_decode_accelerator.cc', 'common/gpu/media/vaapi_video_decode_accelerator.h', 'common/gpu/media/vaapi_video_encode_accelerator.cc', @@ -797,10 +799,29 @@ 'common/gpu/media/vaapi_wrapper.cc', 'common/gpu/media/vaapi_wrapper.h', ], + 'conditions': [ + ['use_x11 == 1', { + 'variables': { + 'sig_files': [ + 'common/gpu/media/va.sigs', + 'common/gpu/media/va_x11.sigs', + ], + }, + 'sources': [ + 'common/gpu/media/vaapi_tfp_picture.cc', + 'common/gpu/media/vaapi_tfp_picture.h', + ], + }, { + 'variables': { + 'sig_files': [ + 'common/gpu/media/va.sigs', + ], + }, + }], + ], 'variables': { 'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py', 'extra_header': 'common/gpu/media/va_stub_header.fragment', - 'sig_files': ['common/gpu/media/va.sigs'], 'outfile_type': 'posix_stubs', 'stubs_filename_root': 'va_stubs', 'project_path': 'content/common/gpu/media', diff --git a/media/BUILD.gn b/media/BUILD.gn index 33a4799..f78c2df 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -576,7 +576,7 @@ test("media_unittests") { ] } - if (cpu_arch != "arm" && is_chromeos && use_x11) { + if (cpu_arch != "arm" && is_chromeos) { sources += [ "filters/h264_bitstream_buffer_unittest.cc" ] } diff --git a/media/media.gyp b/media/media.gyp index c16a880..1aa2556 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -697,7 +697,7 @@ ], }], # For VaapiVideoEncodeAccelerator. - ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', { + ['target_arch != "arm" and chromeos == 1', { 'sources': [ 'filters/h264_bitstream_buffer.cc', 'filters/h264_bitstream_buffer.h', diff --git a/ui/gl/gl_image_glx.cc b/ui/gl/gl_image_glx.cc index dadf494..84c4d0c 100644 --- a/ui/gl/gl_image_glx.cc +++ b/ui/gl/gl_image_glx.cc @@ -61,6 +61,8 @@ unsigned PixmapDepth(unsigned internalformat) { switch (internalformat) { case GL_RGBA: return 32u; + case GL_RGB: + return 24u; default: NOTREACHED(); return 0u; |