Index: content/common/gpu/media/vaapi_picture_provider_drm.cc |
diff --git a/content/common/gpu/media/vaapi_picture_provider_drm.cc b/content/common/gpu/media/vaapi_picture_provider_drm.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d71096caacecbe5ff6bf1d64ceb28d761372dcc1 |
--- /dev/null |
+++ b/content/common/gpu/media/vaapi_picture_provider_drm.cc |
@@ -0,0 +1,274 @@ |
+// Copyright (c) 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_provider_drm.h" |
+#include "third_party/libva/va/drm/va_drm.h" |
+#include "third_party/libva/va/va_drmcommon.h" |
+#include "third_party/libva/va/va_vpp.h" |
+#include "ui/gl/gl_bindings.h" |
+#include "ui/gl/gl_image.h" |
+#include "ui/gl/gl_image_egl.h" |
+#include "ui/gl/scoped_binders.h" |
+#include "ui/ozone/public/native_pixmap.h" |
+#include "ui/ozone/public/ozone_platform.h" |
+#include "ui/ozone/public/surface_factory_ozone.h" |
+ |
+namespace content { |
+ |
+#define LOG_VA_ERROR_AND_RETURN(input, err_msg) \ |
+ do { \ |
+ VAStatus va_status = input; \ |
+ if (va_status != VA_STATUS_SUCCESS) { \ |
+ DVLOG(1) << err_msg << " : " << vaErrorStr(va_status); \ |
+ return false; \ |
+ } \ |
+ } while (0) |
+ |
+class DrmPicture : public VaapiPictureProvider::Picture { |
+ public: |
+ DrmPicture(DrmVaapiPictureProvider* provider, |
+ VADisplay va_display, |
+ const base::Callback<bool(void)> make_context_current, |
+ int32 picture_buffer_id, |
+ uint32 texture_id, |
+ const gfx::Size& size) |
+ : Picture(picture_buffer_id, texture_id, size), |
+ provider_(provider), |
+ va_display_(va_display), |
+ make_context_current_(make_context_current), |
+ va_surface_(VA_INVALID_SURFACE) {} |
+ |
+ virtual ~DrmPicture() { |
+ if (gl_image_ && make_context_current_.Run()) { |
+ // ReleaseTexImage on a GLImageEGL does nothing, to deassociate |
+ // the renderer's texture from the image, just set the storage |
+ // of that texture to NULL |
+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id()); |
+ glTexImage2D(GL_TEXTURE_2D, |
+ 0, |
+ GL_RGBA, |
+ size().width(), |
+ size().height(), |
+ 0, |
+ GL_RGBA, |
+ GL_UNSIGNED_BYTE, |
+ NULL); |
+ |
+ gl_image_->Destroy(true); |
+ |
+ CHECK_EQ(glGetError(), GL_NO_ERROR); |
Pawel Osciak
2014/10/08 08:17:22
I think this is not critical enough to crash the p
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
|
+ } |
+ |
+ if (va_surface_ != VA_INVALID_SURFACE) |
+ vaDestroySurfaces(va_display_, &va_surface_, 1); |
+ } |
+ |
+ bool Initialize() { |
+ VASurfaceAttrib va_attribs[2]; |
+ VASurfaceAttribExternalBuffers va_attrib_extbuf; |
+ |
+ ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance(); |
+ ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone(); |
+ |
+ pixmap_ = |
+ factory->CreateNativePixmap(size(), ui::SurfaceFactoryOzone::RGBA_8888); |
Pawel Osciak
2014/10/08 08:17:22
Check for NULL?
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
|
+ unsigned long buffer_fd = pixmap_->GetDmaBufFd(); |
Pawel Osciak
2014/10/08 08:17:22
fd is an int... We should also check for -1.
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
|
+ |
+ va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX; |
+ va_attrib_extbuf.width = size().width(); |
+ va_attrib_extbuf.height = size().height(); |
+ va_attrib_extbuf.data_size = size().height() * pixmap_->GetStride(); |
+ va_attrib_extbuf.num_planes = 1; |
+ va_attrib_extbuf.pitches[0] = pixmap_->GetStride(); |
+ va_attrib_extbuf.offsets[0] = 0; |
+ va_attrib_extbuf.buffers = &buffer_fd; |
+ va_attrib_extbuf.num_buffers = 1; |
+ va_attrib_extbuf.flags = 0; |
+ va_attrib_extbuf.private_data = NULL; |
+ |
+ va_attribs[0].type = VASurfaceAttribMemoryType; |
+ va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; |
+ va_attribs[0].value.type = VAGenericValueTypeInteger; |
+ va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; |
+ |
+ va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor; |
+ va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; |
+ va_attribs[1].value.type = VAGenericValueTypePointer; |
+ va_attribs[1].value.value.p = &va_attrib_extbuf; |
+ |
+ LOG_VA_ERROR_AND_RETURN(vaCreateSurfaces(va_display_, |
+ VA_RT_FORMAT_RGB32, |
+ size().width(), |
+ size().height(), |
+ &va_surface_, |
+ 1, |
+ va_attribs, |
+ arraysize(va_attribs)), |
+ "Couldn't create surface"); |
+ |
+ if (!make_context_current_.Run()) |
+ return false; |
+ |
+ gl_image_ = new gfx::GLImageEGL(size()); |
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; |
+ if (!gl_image_->Initialize( |
+ EGL_NATIVE_PIXMAP_KHR, pixmap_->GetEGLClientBuffer(), attrs)) |
+ return false; |
+ |
+ return true; |
+ } |
+ |
+ virtual bool PutSurface(VASurfaceID va_surface_id) OVERRIDE { |
+ if (!provider_->PutSurfaceIntoPicture(va_surface_id, va_surface_, size())) |
+ return false; |
+ |
+ if (!make_context_current_.Run()) |
+ return false; |
+ |
+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id()); |
+ return gl_image_->BindTexImage(GL_TEXTURE_2D); |
+ } |
+ |
+ private: |
+ DrmVaapiPictureProvider* provider_; |
+ VADisplay va_display_; |
+ base::Callback<bool(void)> make_context_current_; |
+ VASurfaceID va_surface_; |
+ scoped_refptr<ui::NativePixmap> pixmap_; |
+ scoped_refptr<gfx::GLImageEGL> gl_image_; |
+}; |
+ |
+DrmVaapiPictureProvider::DrmVaapiPictureProvider( |
+ VADisplay va_display, |
+ const base::Callback<bool(void)> make_context_current) |
+ : make_context_current_(make_context_current), |
+ va_display_(va_display), |
+ vpp_config_(VA_INVALID_ID), |
+ vpp_context_(VA_INVALID_ID), |
+ vpp_buffer_(VA_INVALID_ID) { |
+} |
+ |
+DrmVaapiPictureProvider::~DrmVaapiPictureProvider() { |
+ DeinitializeVpp(); |
+} |
+ |
+scoped_ptr<VaapiPictureProvider::Picture> |
+DrmVaapiPictureProvider::CreatePicture(int32 picture_buffer_id, |
+ uint32 texture_id, |
+ const gfx::Size& size) { |
+ DrmPicture* drm_picture = new DrmPicture(this, |
Pawel Osciak
2014/10/08 08:17:22
Could we create a scoped_ptr directly here?
scoped
llandwerlin-old
2014/10/08 09:31:18
The problem is that I can't access the Initialize
Pawel Osciak
2014/10/26 13:06:46
Could you pass fb_config_ to the constructor of TF
llandwerlin-old
2014/10/29 13:52:47
Acknowledged.
|
+ va_display_, |
+ make_context_current_, |
+ picture_buffer_id, |
+ texture_id, |
+ size); |
+ scoped_ptr<VaapiPictureProvider::Picture> picture(drm_picture); |
Pawel Osciak
2014/10/08 08:17:22
Do we need the qualifier here if we are child of V
llandwerlin-old
2014/10/08 09:31:18
I'll check, thanks.
llandwerlin-old
2014/10/13 16:53:00
Yep, we do...
|
+ |
+ if (!drm_picture->Initialize()) |
+ picture.reset(); |
+ |
+ return picture.Pass(); |
+} |
+ |
+bool DrmVaapiPictureProvider::PutSurfaceIntoPicture( |
+ VASurfaceID va_surface_id_src, |
+ VASurfaceID va_surface_id_dest, |
+ const gfx::Size& dest_size) { |
+ VAProcPipelineParameterBuffer* pipeline_param; |
+ VARectangle input_region, output_region; |
+ |
+ LOG_VA_ERROR_AND_RETURN( |
+ vaMapBuffer(va_display_, vpp_buffer_, (void**)&pipeline_param), |
+ "Couldn't map buffer"); |
+ |
+ memset(pipeline_param, 0, sizeof *pipeline_param); |
+ |
+ input_region.x = input_region.y = 0; |
+ input_region.width = coded_picture_size_.width(); |
+ input_region.height = coded_picture_size_.height(); |
+ pipeline_param->surface_region = &input_region; |
+ pipeline_param->surface = va_surface_id_src; |
+ pipeline_param->surface_color_standard = VAProcColorStandardNone; |
+ |
+ output_region.x = output_region.y = 0; |
+ output_region.width = dest_size.width(); |
+ output_region.height = dest_size.height(); |
+ pipeline_param->output_region = &output_region; |
+ pipeline_param->output_background_color = 0xff000000; |
+ pipeline_param->output_color_standard = VAProcColorStandardNone; |
+ |
+ LOG_VA_ERROR_AND_RETURN(vaUnmapBuffer(va_display_, vpp_buffer_), |
+ "Couldn't unmap buffer"); |
+ |
+ LOG_VA_ERROR_AND_RETURN( |
+ vaBeginPicture(va_display_, vpp_context_, va_surface_id_dest), |
+ "Couldn't begin picture"); |
+ |
+ LOG_VA_ERROR_AND_RETURN( |
+ vaRenderPicture(va_display_, vpp_context_, &vpp_buffer_, 1), |
+ "Couldn't render picture"); |
+ |
+ LOG_VA_ERROR_AND_RETURN(vaEndPicture(va_display_, vpp_context_), |
+ "Couldn't end picture"); |
+ return true; |
+} |
+ |
+bool DrmVaapiPictureProvider::SetCodedSurfacesSize(const gfx::Size& size) { |
Pawel Osciak
2014/10/08 08:17:22
I realized, could we just do this on PutSurfaceInt
llandwerlin-old
2014/10/08 09:31:18
Acknowledged.
|
+ DeinitializeVpp(); |
+ return InitializeVpp(size); |
+} |
+ |
+bool DrmVaapiPictureProvider::Initialize() { |
+ return true; |
+} |
+ |
+bool DrmVaapiPictureProvider::InitializeVpp(const gfx::Size& size) { |
+ LOG_VA_ERROR_AND_RETURN(vaCreateConfig(va_display_, |
+ VAProfileNone, |
+ VAEntrypointVideoProc, |
+ NULL, |
+ 0, |
+ &vpp_config_), |
+ "Couldn't create config"); |
+ |
+ LOG_VA_ERROR_AND_RETURN(vaCreateContext(va_display_, |
+ vpp_config_, |
+ size.width(), |
+ size.height(), |
+ 0, |
+ NULL, |
+ 0, |
+ &vpp_context_), |
+ "Couldn't create context"); |
+ |
+ LOG_VA_ERROR_AND_RETURN(vaCreateBuffer(va_display_, |
+ vpp_context_, |
+ VAProcPipelineParameterBufferType, |
+ sizeof(VAProcPipelineParameterBuffer), |
+ 1, |
+ NULL, |
+ &vpp_buffer_), |
+ "Couldn't create buffer"); |
+ |
+ coded_picture_size_ = size; |
+ |
+ return true; |
+} |
+ |
+void DrmVaapiPictureProvider::DeinitializeVpp() { |
+ if (vpp_buffer_ != VA_INVALID_ID) { |
+ vaDestroyBuffer(va_display_, vpp_buffer_); |
+ vpp_buffer_ = VA_INVALID_ID; |
+ } |
+ if (vpp_context_ != VA_INVALID_ID) { |
+ vaDestroyContext(va_display_, vpp_context_); |
+ vpp_context_ = VA_INVALID_ID; |
+ } |
+ if (vpp_config_ != VA_INVALID_ID) { |
+ vaDestroyConfig(va_display_, vpp_config_); |
+ vpp_config_ = VA_INVALID_ID; |
+ } |
+} |
+ |
+} // namespace |