OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/vaapi_wrapper.h" | 5 #include "content/common/gpu/media/vaapi_wrapper.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
13 #include "base/sys_info.h" | 13 #include "base/sys_info.h" |
14 // Auto-generated for dlopen libva libraries | 14 // Auto-generated for dlopen libva libraries |
15 #include "content/common/gpu/media/va_stubs.h" | 15 #include "content/common/gpu/media/va_stubs.h" |
16 #include "content/common/gpu/media/vaapi_picture.h" | |
17 #include "third_party/libyuv/include/libyuv.h" | 16 #include "third_party/libyuv/include/libyuv.h" |
18 #include "ui/gl/gl_bindings.h" | |
19 #if defined(USE_X11) | |
20 #include "ui/gfx/x/x11_types.h" | |
21 #endif // USE_X11 | |
22 | 17 |
23 using content_common_gpu_media::kModuleVa; | 18 using content_common_gpu_media::kModuleVa; |
24 #if defined(USE_X11) | |
25 using content_common_gpu_media::kModuleVa_x11; | |
26 #endif // USE_X11 | |
27 using content_common_gpu_media::InitializeStubs; | 19 using content_common_gpu_media::InitializeStubs; |
28 using content_common_gpu_media::StubPathMap; | 20 using content_common_gpu_media::StubPathMap; |
29 | 21 |
| 22 // libva-x11 depends on libva, so dlopen libva-x11 is enough |
| 23 static const base::FilePath::CharType kVaLib[] = |
| 24 FILE_PATH_LITERAL("libva-x11.so.1"); |
| 25 |
30 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ | 26 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ |
31 do { \ | 27 do { \ |
32 LOG(ERROR) << err_msg \ | 28 LOG(ERROR) << err_msg \ |
33 << " VA error: " << vaErrorStr(va_error); \ | 29 << " VA error: " << vaErrorStr(va_error); \ |
34 report_error_to_uma_cb_.Run(); \ | 30 report_error_to_uma_cb_.Run(); \ |
35 } while (0) | 31 } while (0) |
36 | 32 |
37 #define VA_LOG_ON_ERROR(va_error, err_msg) \ | 33 #define VA_LOG_ON_ERROR(va_error, err_msg) \ |
38 do { \ | 34 do { \ |
39 if ((va_error) != VA_STATUS_SUCCESS) \ | 35 if ((va_error) != VA_STATUS_SUCCESS) \ |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 VAProfileH264ConstrainedBaseline) != | 116 VAProfileH264ConstrainedBaseline) != |
121 supported_profiles.end()) { | 117 supported_profiles.end()) { |
122 va_profile = VAProfileH264ConstrainedBaseline; | 118 va_profile = VAProfileH264ConstrainedBaseline; |
123 DVLOG(1) << "Falling back to constrained baseline profile."; | 119 DVLOG(1) << "Falling back to constrained baseline profile."; |
124 } | 120 } |
125 } | 121 } |
126 | 122 |
127 return va_profile; | 123 return va_profile; |
128 } | 124 } |
129 | 125 |
130 VASurface::VASurface(VASurfaceID va_surface_id, | 126 VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb) |
131 const gfx::Size& size, | 127 : va_surface_id_(va_surface_id), |
132 const ReleaseCB& release_cb) | 128 release_cb_(release_cb) { |
133 : va_surface_id_(va_surface_id), size_(size), release_cb_(release_cb) { | |
134 DCHECK(!release_cb_.is_null()); | 129 DCHECK(!release_cb_.is_null()); |
135 } | 130 } |
136 | 131 |
137 VASurface::~VASurface() { | 132 VASurface::~VASurface() { |
138 release_cb_.Run(va_surface_id_); | 133 release_cb_.Run(va_surface_id_); |
139 } | 134 } |
140 | 135 |
141 VaapiWrapper::VaapiWrapper() | 136 VaapiWrapper::VaapiWrapper() |
142 : va_display_(NULL), | 137 : va_display_(NULL), |
143 va_config_id_(VA_INVALID_ID), | 138 va_config_id_(VA_INVALID_ID), |
144 va_context_id_(VA_INVALID_ID), | 139 va_context_id_(VA_INVALID_ID), |
145 va_initialized_(false) { | 140 va_initialized_(false) { |
146 } | 141 } |
147 | 142 |
148 VaapiWrapper::~VaapiWrapper() { | 143 VaapiWrapper::~VaapiWrapper() { |
149 DestroyPendingBuffers(); | 144 DestroyPendingBuffers(); |
150 DestroyCodedBuffers(); | 145 DestroyCodedBuffers(); |
151 DestroySurfaces(); | 146 DestroySurfaces(); |
152 Deinitialize(); | 147 Deinitialize(); |
153 } | 148 } |
154 | 149 |
155 scoped_refptr<VaapiWrapper> VaapiWrapper::Create( | 150 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
156 CodecMode mode, | 151 CodecMode mode, |
157 media::VideoCodecProfile profile, | 152 media::VideoCodecProfile profile, |
| 153 Display* x_display, |
158 const base::Closure& report_error_to_uma_cb) { | 154 const base::Closure& report_error_to_uma_cb) { |
159 scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 155 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
160 | 156 |
161 if (!vaapi_wrapper->Initialize(mode, profile, report_error_to_uma_cb)) | 157 if (!vaapi_wrapper->Initialize( |
162 vaapi_wrapper = NULL; | 158 mode, profile, x_display, report_error_to_uma_cb)) |
| 159 vaapi_wrapper.reset(); |
163 | 160 |
164 return vaapi_wrapper; | 161 return vaapi_wrapper.Pass(); |
165 } | 162 } |
166 | 163 |
167 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( | 164 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( |
| 165 Display* x_display, |
168 const base::Closure& report_error_to_uma_cb) { | 166 const base::Closure& report_error_to_uma_cb) { |
169 std::vector<media::VideoCodecProfile> supported_profiles; | 167 std::vector<media::VideoCodecProfile> supported_profiles; |
170 | 168 |
171 scoped_refptr<VaapiWrapper> wrapper(new VaapiWrapper()); | 169 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); |
172 if (!wrapper->VaInitialize(report_error_to_uma_cb)) { | 170 if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) { |
173 return supported_profiles; | 171 return supported_profiles; |
174 } | 172 } |
175 | 173 |
176 std::vector<VAProfile> va_profiles; | 174 std::vector<VAProfile> va_profiles; |
177 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) | 175 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) |
178 return supported_profiles; | 176 return supported_profiles; |
179 | 177 |
180 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); | 178 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); |
181 for (size_t i = 0; i < arraysize(kProfileMap); i++) { | 179 for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
182 VAProfile va_profile = | 180 VAProfile va_profile = |
(...skipping 14 matching lines...) Expand all Loading... |
197 1, // At least support '_LOCAL_OVERLAY'. | 195 1, // At least support '_LOCAL_OVERLAY'. |
198 -1, // The maximum possible support 'ALL'. | 196 -1, // The maximum possible support 'ALL'. |
199 VA_RENDER_MODE_LOCAL_GPU, | 197 VA_RENDER_MODE_LOCAL_GPU, |
200 VA_DISPLAY_ATTRIB_SETTABLE}; | 198 VA_DISPLAY_ATTRIB_SETTABLE}; |
201 | 199 |
202 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 200 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
203 if (va_res != VA_STATUS_SUCCESS) | 201 if (va_res != VA_STATUS_SUCCESS) |
204 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 202 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
205 } | 203 } |
206 | 204 |
207 bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) { | 205 bool VaapiWrapper::VaInitialize(Display* x_display, |
| 206 const base::Closure& report_error_to_uma_cb) { |
208 static bool vaapi_functions_initialized = PostSandboxInitialization(); | 207 static bool vaapi_functions_initialized = PostSandboxInitialization(); |
209 if (!vaapi_functions_initialized) { | 208 if (!vaapi_functions_initialized) { |
210 bool running_on_chromeos = false; | 209 bool running_on_chromeos = false; |
211 #if defined(OS_CHROMEOS) | 210 #if defined(OS_CHROMEOS) |
212 // When chrome runs on linux with chromeos=1, do not log error message | 211 // When chrome runs on linux with chromeos=1, do not log error message |
213 // without VAAPI libraries. | 212 // without VAAPI libraries. |
214 running_on_chromeos = base::SysInfo::IsRunningOnChromeOS(); | 213 running_on_chromeos = base::SysInfo::IsRunningOnChromeOS(); |
215 #endif | 214 #endif |
216 static const char kErrorMsg[] = "Failed to initialize VAAPI libs"; | 215 static const char kErrorMsg[] = "Failed to initialize VAAPI libs"; |
217 if (running_on_chromeos) | 216 if (running_on_chromeos) |
218 LOG(ERROR) << kErrorMsg; | 217 LOG(ERROR) << kErrorMsg; |
219 else | 218 else |
220 DVLOG(1) << kErrorMsg; | 219 DVLOG(1) << kErrorMsg; |
221 return false; | 220 return false; |
222 } | 221 } |
223 | 222 |
224 report_error_to_uma_cb_ = report_error_to_uma_cb; | 223 report_error_to_uma_cb_ = report_error_to_uma_cb; |
225 | 224 |
226 base::AutoLock auto_lock(va_lock_); | 225 base::AutoLock auto_lock(va_lock_); |
227 | 226 |
228 #if defined(USE_X11) | 227 va_display_ = vaGetDisplay(x_display); |
229 va_display_ = vaGetDisplay(gfx::GetXDisplay()); | |
230 #endif // USE_X11 | |
231 | |
232 if (!vaDisplayIsValid(va_display_)) { | 228 if (!vaDisplayIsValid(va_display_)) { |
233 LOG(ERROR) << "Could not get a valid VA display"; | 229 LOG(ERROR) << "Could not get a valid VA display"; |
234 return false; | 230 return false; |
235 } | 231 } |
236 | 232 |
237 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); | 233 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); |
238 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); | 234 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); |
239 va_initialized_ = true; | 235 va_initialized_ = true; |
240 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; | 236 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; |
241 | 237 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 DVLOG(1) << "Unsupported value " << required_attribs[i].value | 314 DVLOG(1) << "Unsupported value " << required_attribs[i].value |
319 << " for attribute type " << required_attribs[i].type; | 315 << " for attribute type " << required_attribs[i].type; |
320 return false; | 316 return false; |
321 } | 317 } |
322 } | 318 } |
323 return true; | 319 return true; |
324 } | 320 } |
325 | 321 |
326 bool VaapiWrapper::Initialize(CodecMode mode, | 322 bool VaapiWrapper::Initialize(CodecMode mode, |
327 media::VideoCodecProfile profile, | 323 media::VideoCodecProfile profile, |
| 324 Display* x_display, |
328 const base::Closure& report_error_to_uma_cb) { | 325 const base::Closure& report_error_to_uma_cb) { |
329 if (!VaInitialize(report_error_to_uma_cb)) | 326 if (!VaInitialize(x_display, report_error_to_uma_cb)) |
330 return false; | 327 return false; |
331 std::vector<VAProfile> supported_va_profiles; | 328 std::vector<VAProfile> supported_va_profiles; |
332 if (!GetSupportedVaProfiles(&supported_va_profiles)) | 329 if (!GetSupportedVaProfiles(&supported_va_profiles)) |
333 return false; | 330 return false; |
334 VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles); | 331 VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles); |
335 if (va_profile == VAProfileNone) { | 332 if (va_profile == VAProfileNone) { |
336 DVLOG(1) << "Unsupported profile"; | 333 DVLOG(1) << "Unsupported profile"; |
337 return false; | 334 return false; |
338 } | 335 } |
339 VAEntrypoint entrypoint = | 336 VAEntrypoint entrypoint = |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 va_config_id_ = VA_INVALID_ID; | 376 va_config_id_ = VA_INVALID_ID; |
380 va_display_ = NULL; | 377 va_display_ = NULL; |
381 va_initialized_ = false; | 378 va_initialized_ = false; |
382 } | 379 } |
383 | 380 |
384 bool VaapiWrapper::VAAPIVersionLessThan(int major, int minor) { | 381 bool VaapiWrapper::VAAPIVersionLessThan(int major, int minor) { |
385 return (major_version_ < major) || | 382 return (major_version_ < major) || |
386 (major_version_ == major && minor_version_ < minor); | 383 (major_version_ == major && minor_version_ < minor); |
387 } | 384 } |
388 | 385 |
389 bool VaapiWrapper::CreateSurfaces(const gfx::Size& size, | 386 bool VaapiWrapper::CreateSurfaces(gfx::Size size, |
390 size_t num_surfaces, | 387 size_t num_surfaces, |
391 std::vector<VASurfaceID>* va_surfaces) { | 388 std::vector<VASurfaceID>* va_surfaces) { |
392 base::AutoLock auto_lock(va_lock_); | 389 base::AutoLock auto_lock(va_lock_); |
393 DVLOG(2) << "Creating " << num_surfaces << " surfaces"; | 390 DVLOG(2) << "Creating " << num_surfaces << " surfaces"; |
394 | 391 |
395 DCHECK(va_surfaces->empty()); | 392 DCHECK(va_surfaces->empty()); |
396 DCHECK(va_surface_ids_.empty()); | 393 DCHECK(va_surface_ids_.empty()); |
397 va_surface_ids_.resize(num_surfaces); | 394 va_surface_ids_.resize(num_surfaces); |
398 | 395 |
399 // Allocate surfaces in driver. | 396 // Allocate surfaces in driver. |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 | 586 |
590 return true; | 587 return true; |
591 } | 588 } |
592 | 589 |
593 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { | 590 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { |
594 bool result = Execute(va_surface_id); | 591 bool result = Execute(va_surface_id); |
595 DestroyPendingBuffers(); | 592 DestroyPendingBuffers(); |
596 return result; | 593 return result; |
597 } | 594 } |
598 | 595 |
| 596 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, |
| 597 Pixmap x_pixmap, |
| 598 gfx::Size dest_size) { |
| 599 base::AutoLock auto_lock(va_lock_); |
| 600 |
| 601 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
| 602 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
| 603 |
| 604 // Put the data into an X Pixmap. |
| 605 va_res = vaPutSurface(va_display_, |
| 606 va_surface_id, |
| 607 x_pixmap, |
| 608 0, 0, dest_size.width(), dest_size.height(), |
| 609 0, 0, dest_size.width(), dest_size.height(), |
| 610 NULL, 0, 0); |
| 611 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); |
| 612 return true; |
| 613 } |
| 614 |
599 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, | 615 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, |
600 VAImage* image, | 616 VAImage* image, |
601 void** mem) { | 617 void** mem) { |
602 base::AutoLock auto_lock(va_lock_); | 618 base::AutoLock auto_lock(va_lock_); |
603 | 619 |
604 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 620 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
605 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 621 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
606 | 622 |
607 // Derive a VAImage from the VASurface | 623 // Derive a VAImage from the VASurface |
608 va_res = vaDeriveImage(va_display_, va_surface_id, image); | 624 va_res = vaDeriveImage(va_display_, va_surface_id, image); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | 745 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
730 | 746 |
731 va_res = vaDestroyBuffer(va_display_, buffer_id); | 747 va_res = vaDestroyBuffer(va_display_, buffer_id); |
732 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 748 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
733 | 749 |
734 DCHECK(coded_buffers_.erase(buffer_id)); | 750 DCHECK(coded_buffers_.erase(buffer_id)); |
735 | 751 |
736 return buffer_segment == NULL; | 752 return buffer_segment == NULL; |
737 } | 753 } |
738 | 754 |
739 #if defined(USE_X11) | |
740 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, | |
741 Pixmap x_pixmap, | |
742 gfx::Size dest_size) { | |
743 base::AutoLock auto_lock(va_lock_); | |
744 | |
745 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | |
746 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | |
747 | |
748 // Put the data into an X Pixmap. | |
749 va_res = vaPutSurface(va_display_, va_surface_id, x_pixmap, 0, 0, | |
750 dest_size.width(), dest_size.height(), 0, 0, | |
751 dest_size.width(), dest_size.height(), NULL, 0, 0); | |
752 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); | |
753 return true; | |
754 } | |
755 #endif // USE_X11 | |
756 | |
757 // static | 755 // static |
758 bool VaapiWrapper::PostSandboxInitialization() { | 756 bool VaapiWrapper::PostSandboxInitialization() { |
759 StubPathMap paths; | 757 StubPathMap paths; |
760 | 758 paths[kModuleVa].push_back(kVaLib); |
761 paths[kModuleVa].push_back("libva.so.1"); | |
762 | |
763 #if defined(USE_X11) | |
764 paths[kModuleVa_x11].push_back("libva-x11.so.1"); | |
765 #endif | |
766 | 759 |
767 return InitializeStubs(paths); | 760 return InitializeStubs(paths); |
768 } | 761 } |
769 | 762 |
770 } // namespace content | 763 } // namespace content |
OLD | NEW |