Chromium Code Reviews| Index: content/common/gpu/media/vaapi_video_decode_accelerator.cc |
| diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
| index afcfc8a3b0632f2d316fe393c44595f04a1ef714..e8aa207142e913dc52df14aa4290842dfc2c8e79 100644 |
| --- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
| +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
| @@ -2,6 +2,12 @@ |
| // 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_video_decode_accelerator.h" |
| + |
| +#if !defined(USE_X11) |
| +#include <gbm.h> |
| +#endif |
| + |
| #include "base/bind.h" |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| @@ -11,10 +17,12 @@ |
| #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_video_decode_accelerator.h" |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/video/picture.h" |
| #include "ui/gl/gl_bindings.h" |
| +#if !defined(USE_X11) |
| +#include "ui/gl/gl_surface_egl.h" |
| +#endif |
| #include "ui/gl/scoped_binders.h" |
| static void ReportToUMA( |
| @@ -74,8 +82,13 @@ class VaapiVideoDecodeAccelerator::TFPPicture : public base::NonThreadSafe { |
| static linked_ptr<TFPPicture> Create( |
| const base::Callback<bool(void)>& make_context_current, |
| +#if defined(USE_X11) |
| const GLXFBConfig& fb_config, |
| Display* x_display, |
| +#else |
| + int fd, |
| + VaapiWrapper* va_wrapper, |
| +#endif |
| int32 picture_buffer_id, |
| uint32 texture_id, |
| gfx::Size size); |
| @@ -87,81 +100,129 @@ class VaapiVideoDecodeAccelerator::TFPPicture : public base::NonThreadSafe { |
| gfx::Size size() { |
| return size_; |
| } |
| - |
| +#if defined(USE_X11) |
| int x_pixmap() { |
| return x_pixmap_; |
| } |
| // Bind texture to pixmap. Needs to be called every frame. |
| bool Bind(); |
| +#else |
| + // Upload vaimage data to texture. Needs to be called every frame. |
| + bool Upload(VASurfaceID id); |
| +#endif |
| private: |
| TFPPicture(const base::Callback<bool(void)>& make_context_current, |
| +#if defined(USE_X11) |
| Display* x_display, |
| +#else |
| + int fd, |
| + VaapiWrapper* va_wrapper, |
| +#endif |
| int32 picture_buffer_id, |
| uint32 texture_id, |
| gfx::Size size); |
| +#if defined(USE_X11) |
| bool Initialize(const GLXFBConfig& fb_config); |
| base::Callback<bool(void)> make_context_current_; |
| Display* x_display_; |
| +#else |
| + bool Initialize(); |
| + |
| + base::Callback<bool(void)> make_context_current_; |
| + |
| + VaapiWrapper* va_wrapper_; |
| +#endif |
| // Output id for the client. |
| int32 picture_buffer_id_; |
| uint32 texture_id_; |
| gfx::Size size_; |
| - |
| +#if defined(USE_X11) |
| // Pixmaps bound to this texture. |
| Pixmap x_pixmap_; |
| GLXPixmap glx_pixmap_; |
| - |
| +#else |
| + VAImage va_image_; |
| +#endif |
| DISALLOW_COPY_AND_ASSIGN(TFPPicture); |
| }; |
| VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture( |
| const base::Callback<bool(void)>& make_context_current, |
| +#if defined(USE_X11) |
| Display* x_display, |
| +#else |
| + int fd, |
| + VaapiWrapper* va_wrapper, |
| +#endif |
| int32 picture_buffer_id, |
| uint32 texture_id, |
| gfx::Size size) |
| : make_context_current_(make_context_current), |
| +#if defined(USE_X11) |
| x_display_(x_display), |
| + x_pixmap_(0), |
| + glx_pixmap_(0), |
| +#else |
| + va_wrapper_(va_wrapper), |
| +#endif |
| picture_buffer_id_(picture_buffer_id), |
| texture_id_(texture_id), |
| - size_(size), |
| - x_pixmap_(0), |
| - glx_pixmap_(0) { |
| + size_(size) { |
| DCHECK(!make_context_current_.is_null()); |
| }; |
| linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture> |
| VaapiVideoDecodeAccelerator::TFPPicture::Create( |
| const base::Callback<bool(void)>& make_context_current, |
| +#if defined(USE_X11) |
| const GLXFBConfig& fb_config, |
| Display* x_display, |
| +#else |
| + int fd, |
| + VaapiWrapper* va_wrapper, |
| +#endif |
| 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)); |
| - |
| + new TFPPicture(make_context_current, |
| +#if defined(USE_X11) |
| + x_display, |
| +#else |
| + fd, |
| + va_wrapper, |
| +#endif |
| + picture_buffer_id, |
| + texture_id, |
| + size)); |
| +#if defined(USE_X11) |
| if (!tfp_picture->Initialize(fb_config)) |
| +#else |
| + if (!tfp_picture->Initialize()) |
| +#endif |
| tfp_picture.reset(); |
| return tfp_picture; |
| } |
| +#if defined(USE_X11) |
| bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( |
| const GLXFBConfig& fb_config) { |
| +#else |
| +bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize() { |
| +#endif |
| DCHECK(CalledOnValidThread()); |
| if (!make_context_current_.Run()) |
| return false; |
| - |
| +#if defined(USE_X11) |
| XWindowAttributes win_attr; |
| int screen = DefaultScreen(x_display_); |
| XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); |
| @@ -185,12 +246,18 @@ bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( |
| DVLOG(1) << "Failed creating a GLX Pixmap for TFP"; |
| return false; |
| } |
| - |
| +#else |
| + if (!va_wrapper_->CreateRGBImage(size_, &va_image_)) { |
| + DVLOG(1) << "Failed to create VAImage"; |
| + return false; |
| + } |
| +#endif |
| return true; |
| } |
| VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { |
| DCHECK(CalledOnValidThread()); |
| +#if defined(USE_X11) |
| // Unbind surface from texture and deallocate resources. |
| if (glx_pixmap_ && make_context_current_.Run()) { |
| glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); |
| @@ -200,8 +267,13 @@ VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { |
| if (x_pixmap_) |
| XFreePixmap(x_display_, x_pixmap_); |
| XSync(x_display_, False); // Needed to work around buggy vdpau-driver. |
| +#else |
| + if (va_wrapper_) |
| + va_wrapper_->DestroyImage(&va_image_); |
| +#endif |
| } |
| +#if defined(USE_X11) |
| bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(x_pixmap_); |
| @@ -214,6 +286,35 @@ bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { |
| return true; |
| } |
| +#else |
| +bool VaapiVideoDecodeAccelerator::TFPPicture::Upload(VASurfaceID surface) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!make_context_current_.Run()) |
| + return false; |
| + |
| + |
| + if (!va_wrapper_->PutSurfaceIntoImage(surface, &va_image_)) { |
| + DVLOG(1) << "Failed to put va surface to image"; |
| + return false; |
| + } |
| + |
| + void* buffer = NULL; |
| + if (!va_wrapper_->MapImage(&va_image_, &buffer)) { |
| + DVLOG(1) << "Failed to map VAImage"; |
| + return false; |
| + } |
| + |
| + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), |
| + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
|
marcheu
2014/08/07 01:26:25
This is a synchronous, CPU-side copy. This copy do
vignatti (out of this project)
2014/08/12 08:19:02
FYI point taken. We are working on that.
|
| + |
| + va_wrapper_->UnmapImage(&va_image_); |
| + |
| + return true; |
| +} |
| +#endif |
| VaapiVideoDecodeAccelerator::TFPPicture* |
| VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) { |
| @@ -227,9 +328,15 @@ VaapiVideoDecodeAccelerator::TFPPicture* |
| } |
| VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
| +#if defined(USE_X11) |
| Display* x_display, |
| +#endif |
| const base::Callback<bool(void)>& make_context_current) |
| +#if defined(USE_X11) |
| : x_display_(x_display), |
| +#else |
| + : fd_(0), |
| +#endif |
| make_context_current_(make_context_current), |
| state_(kUninitialized), |
| input_ready_(&lock_), |
| @@ -249,8 +356,12 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
| VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { |
| DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| +#if !defined(USE_X11) |
| + fd_ = 0; |
| +#endif |
| } |
| +#if defined(USE_X11) |
| class XFreeDeleter { |
| public: |
| void operator()(void* x) const { |
| @@ -279,6 +390,7 @@ bool VaapiVideoDecodeAccelerator::InitializeFBConfig() { |
| fb_config_ = glx_fb_configs.get()[0]; |
| return true; |
| } |
| +#endif |
| bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
| Client* client) { |
| @@ -294,15 +406,30 @@ bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
| if (!make_context_current_.Run()) |
| return false; |
| +#if defined(USE_X11) |
| if (!InitializeFBConfig()) { |
| DVLOG(1) << "Could not get a usable FBConfig"; |
| return false; |
| } |
| +#else |
| + gbm_device* device = NULL; |
| + device = reinterpret_cast<gbm_device*>( |
| + gfx::GetPlatformDefaultEGLNativeDisplay()); |
| + fd_ = gbm_device_get_fd(device); |
| + if (!fd_) { |
| + DVLOG(1) << "Could not get a usable DRM device"; |
| + return false; |
| + } |
| +#endif |
| vaapi_wrapper_ = VaapiWrapper::Create( |
| VaapiWrapper::kDecode, |
| profile, |
| +#if defined(USE_X11) |
| x_display_, |
| +#else |
| + fd_, |
| +#endif |
| base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); |
| if (!vaapi_wrapper_.get()) { |
| @@ -355,7 +482,7 @@ void VaapiVideoDecodeAccelerator::OutputPicture( |
| DVLOG(3) << "Outputting VASurface " << va_surface->id() |
| << " into pixmap bound to picture buffer id " << output_id; |
| - |
| +#if defined(USE_X11) |
| RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(), |
| "Failed binding texture to pixmap", |
| PLATFORM_FAILURE, ); |
| @@ -365,7 +492,11 @@ void VaapiVideoDecodeAccelerator::OutputPicture( |
| tfp_picture->x_pixmap(), |
| tfp_picture->size()), |
| "Failed putting surface into pixmap", PLATFORM_FAILURE, ); |
| - |
| +#else |
| + RETURN_AND_NOTIFY_ON_FAILURE( |
| + tfp_picture->Upload(va_surface->id()), |
| + "Failed putting surface into pixmap", PLATFORM_FAILURE, ); |
| +#endif |
| // 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_); |
| @@ -437,9 +568,8 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { |
| // Will only wait if it is expected that in current state new buffers will |
| // be queued from the client via Decode(). The state can change during wait. |
| - while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) { |
| + while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) |
| input_ready_.Wait(); |
| - } |
| // We could have got woken up in a different state or never got to sleep |
| // due to current state; check for that. |
| @@ -494,9 +624,8 @@ bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { |
| DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); |
| while (available_va_surfaces_.empty() && |
| - (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { |
| + (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) |
| surfaces_available_.Wait(); |
| - } |
| if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) |
| return false; |
| @@ -704,8 +833,16 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( |
| << " 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(), |
| + TFPPicture::Create(make_context_current_, |
| +#if defined(USE_X11) |
| + fb_config_, |
| + x_display_, |
| +#else |
| + fd_, |
| + vaapi_wrapper_.get(), |
| +#endif |
| + buffers[i].id(), |
| + buffers[i].texture_id(), |
| requested_pic_size_)); |
| RETURN_AND_NOTIFY_ON_FAILURE( |