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" |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 if (mode == VaapiWrapper::kEncode) { | 92 if (mode == VaapiWrapper::kEncode) { |
93 required_attribs.insert( | 93 required_attribs.insert( |
94 required_attribs.end(), | 94 required_attribs.end(), |
95 kEncodeVAConfigAttribs, | 95 kEncodeVAConfigAttribs, |
96 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs)); | 96 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs)); |
97 } | 97 } |
98 return required_attribs; | 98 return required_attribs; |
99 } | 99 } |
100 | 100 |
101 // Maps Profile enum values to VaProfile values. | 101 // Maps Profile enum values to VaProfile values. |
102 static VAProfile ProfileToVAProfile( | 102 static VAProfile ProfileToVAProfile(media::VideoCodecProfile profile) { |
103 media::VideoCodecProfile profile, | |
104 const std::vector<VAProfile>& supported_profiles) { | |
105 | |
106 VAProfile va_profile = VAProfileNone; | 103 VAProfile va_profile = VAProfileNone; |
107 for (size_t i = 0; i < arraysize(kProfileMap); i++) { | 104 for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
108 if (kProfileMap[i].profile == profile) { | 105 if (kProfileMap[i].profile == profile) { |
109 va_profile = kProfileMap[i].va_profile; | 106 va_profile = kProfileMap[i].va_profile; |
110 break; | 107 break; |
111 } | 108 } |
112 } | 109 } |
| 110 return va_profile; |
| 111 } |
113 | 112 |
| 113 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips |
| 114 // the information whether the profile is constrained or not, so we have no |
| 115 // way to know here. Try for baseline first, but if it is not supported, |
| 116 // try constrained baseline and hope this is what it actually is |
| 117 // (which in practice is true for a great majority of cases). |
| 118 static VAProfile FallbackVaProfileIfNecessary( |
| 119 VAProfile va_profile, |
| 120 const std::vector<VAProfile>& supported_profiles) { |
114 bool supported = std::find(supported_profiles.begin(), | 121 bool supported = std::find(supported_profiles.begin(), |
115 supported_profiles.end(), | 122 supported_profiles.end(), |
116 va_profile) != supported_profiles.end(); | 123 va_profile) != supported_profiles.end(); |
117 | 124 |
118 if (!supported && va_profile == VAProfileH264Baseline) { | 125 if (!supported && va_profile == VAProfileH264Baseline) { |
119 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips | |
120 // the information whether the profile is constrained or not, so we have no | |
121 // way to know here. Try for baseline first, but if it is not supported, | |
122 // try constrained baseline and hope this is what it actually is | |
123 // (which in practice is true for a great majority of cases). | |
124 if (std::find(supported_profiles.begin(), | 126 if (std::find(supported_profiles.begin(), |
125 supported_profiles.end(), | 127 supported_profiles.end(), |
126 VAProfileH264ConstrainedBaseline) != | 128 VAProfileH264ConstrainedBaseline) != |
127 supported_profiles.end()) { | 129 supported_profiles.end()) { |
128 va_profile = VAProfileH264ConstrainedBaseline; | 130 va_profile = VAProfileH264ConstrainedBaseline; |
129 DVLOG(1) << "Falling back to constrained baseline profile."; | 131 DVLOG(1) << "Falling back to constrained baseline profile."; |
130 } | 132 } |
131 } | 133 } |
132 | 134 |
133 return va_profile; | 135 return va_profile; |
(...skipping 23 matching lines...) Expand all Loading... |
157 VaapiWrapper::~VaapiWrapper() { | 159 VaapiWrapper::~VaapiWrapper() { |
158 DestroyPendingBuffers(); | 160 DestroyPendingBuffers(); |
159 DestroyCodedBuffers(); | 161 DestroyCodedBuffers(); |
160 DestroySurfaces(); | 162 DestroySurfaces(); |
161 DeinitializeVpp(); | 163 DeinitializeVpp(); |
162 Deinitialize(); | 164 Deinitialize(); |
163 } | 165 } |
164 | 166 |
165 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( | 167 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
166 CodecMode mode, | 168 CodecMode mode, |
| 169 VAProfile va_profile, |
| 170 const base::Closure& report_error_to_uma_cb) { |
| 171 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
| 172 |
| 173 if (!vaapi_wrapper->Initialize(mode, va_profile, false, |
| 174 report_error_to_uma_cb)) |
| 175 return nullptr; |
| 176 |
| 177 return vaapi_wrapper.Pass(); |
| 178 } |
| 179 |
| 180 scoped_ptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( |
| 181 CodecMode mode, |
167 media::VideoCodecProfile profile, | 182 media::VideoCodecProfile profile, |
168 const base::Closure& report_error_to_uma_cb) { | 183 const base::Closure& report_error_to_uma_cb) { |
169 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 184 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
170 | 185 |
171 if (!vaapi_wrapper->Initialize(mode, profile, report_error_to_uma_cb)) | 186 VAProfile va_profile = ProfileToVAProfile(profile); |
172 vaapi_wrapper.reset(); | 187 if (!vaapi_wrapper->Initialize(mode, va_profile, true, |
| 188 report_error_to_uma_cb)) |
| 189 return nullptr; |
173 | 190 |
174 return vaapi_wrapper.Pass(); | 191 return vaapi_wrapper.Pass(); |
175 } | 192 } |
176 | 193 |
177 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( | 194 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( |
178 const base::Closure& report_error_to_uma_cb) { | 195 const base::Closure& report_error_to_uma_cb) { |
179 std::vector<media::VideoCodecProfile> supported_profiles; | 196 std::vector<media::VideoCodecProfile> supported_profiles; |
180 | 197 |
181 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); | 198 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); |
182 if (!wrapper->VaInitialize(report_error_to_uma_cb)) { | 199 if (!wrapper->VaInitialize(report_error_to_uma_cb)) { |
183 return supported_profiles; | 200 return supported_profiles; |
184 } | 201 } |
185 | 202 |
186 std::vector<VAProfile> va_profiles; | 203 std::vector<VAProfile> va_profiles; |
187 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) | 204 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) |
188 return supported_profiles; | 205 return supported_profiles; |
189 | 206 |
190 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); | 207 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); |
191 for (size_t i = 0; i < arraysize(kProfileMap); i++) { | 208 for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
192 VAProfile va_profile = | 209 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile); |
193 ProfileToVAProfile(kProfileMap[i].profile, va_profiles); | 210 va_profile = FallbackVaProfileIfNecessary(va_profile, va_profiles); |
194 if (va_profile != VAProfileNone && | 211 if (va_profile != VAProfileNone && |
195 wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) && | 212 wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) && |
196 wrapper->AreAttribsSupported( | 213 wrapper->AreAttribsSupported( |
197 va_profile, VAEntrypointEncSlice, required_attribs)) { | 214 va_profile, VAEntrypointEncSlice, required_attribs)) { |
198 supported_profiles.push_back(kProfileMap[i].profile); | 215 supported_profiles.push_back(kProfileMap[i].profile); |
199 } | 216 } |
200 } | 217 } |
201 return supported_profiles; | 218 return supported_profiles; |
202 } | 219 } |
203 | 220 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 required_attribs[i].value) { | 349 required_attribs[i].value) { |
333 DVLOG(1) << "Unsupported value " << required_attribs[i].value | 350 DVLOG(1) << "Unsupported value " << required_attribs[i].value |
334 << " for attribute type " << required_attribs[i].type; | 351 << " for attribute type " << required_attribs[i].type; |
335 return false; | 352 return false; |
336 } | 353 } |
337 } | 354 } |
338 return true; | 355 return true; |
339 } | 356 } |
340 | 357 |
341 bool VaapiWrapper::Initialize(CodecMode mode, | 358 bool VaapiWrapper::Initialize(CodecMode mode, |
342 media::VideoCodecProfile profile, | 359 VAProfile va_profile, |
| 360 bool va_profile_degraded, |
343 const base::Closure& report_error_to_uma_cb) { | 361 const base::Closure& report_error_to_uma_cb) { |
344 if (!VaInitialize(report_error_to_uma_cb)) | 362 if (!VaInitialize(report_error_to_uma_cb)) |
345 return false; | 363 return false; |
346 std::vector<VAProfile> supported_va_profiles; | 364 if (va_profile_degraded) { |
347 if (!GetSupportedVaProfiles(&supported_va_profiles)) | 365 std::vector<VAProfile> supported_va_profiles; |
348 return false; | 366 if (!GetSupportedVaProfiles(&supported_va_profiles)) |
349 VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles); | 367 return false; |
| 368 va_profile = |
| 369 FallbackVaProfileIfNecessary(va_profile, supported_va_profiles); |
| 370 } |
350 if (va_profile == VAProfileNone) { | 371 if (va_profile == VAProfileNone) { |
351 DVLOG(1) << "Unsupported profile"; | 372 DVLOG(1) << "Unsupported profile"; |
352 return false; | 373 return false; |
353 } | 374 } |
354 VAEntrypoint entrypoint = | 375 VAEntrypoint entrypoint = |
355 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); | 376 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); |
356 if (!IsEntrypointSupported(va_profile, entrypoint)) | 377 if (!IsEntrypointSupported(va_profile, entrypoint)) |
357 return false; | 378 return false; |
358 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); | 379 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); |
359 if (!AreAttribsSupported(va_profile, entrypoint, required_attribs)) | 380 if (!AreAttribsSupported(va_profile, entrypoint, required_attribs)) |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 va_surface_id, | 679 va_surface_id, |
659 x_pixmap, | 680 x_pixmap, |
660 0, 0, dest_size.width(), dest_size.height(), | 681 0, 0, dest_size.width(), dest_size.height(), |
661 0, 0, dest_size.width(), dest_size.height(), | 682 0, 0, dest_size.width(), dest_size.height(), |
662 NULL, 0, 0); | 683 NULL, 0, 0); |
663 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); | 684 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); |
664 return true; | 685 return true; |
665 } | 686 } |
666 #endif // USE_X11 | 687 #endif // USE_X11 |
667 | 688 |
668 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, | 689 bool VaapiWrapper::GetDerivedVaImage(VASurfaceID va_surface_id, |
669 VAImage* image, | 690 VAImage* image, |
670 void** mem) { | 691 void** mem) { |
671 base::AutoLock auto_lock(va_lock_); | 692 base::AutoLock auto_lock(va_lock_); |
672 | 693 |
673 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 694 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
674 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 695 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
675 | 696 |
676 // Derive a VAImage from the VASurface | 697 // Derive a VAImage from the VASurface |
677 va_res = vaDeriveImage(va_display_, va_surface_id, image); | 698 va_res = vaDeriveImage(va_display_, va_surface_id, image); |
678 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); | 699 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); |
679 if (va_res != VA_STATUS_SUCCESS) | 700 if (va_res != VA_STATUS_SUCCESS) |
680 return false; | 701 return false; |
681 | 702 |
682 // Map the VAImage into memory | 703 // Map the VAImage into memory |
683 va_res = vaMapBuffer(va_display_, image->buf, mem); | 704 va_res = vaMapBuffer(va_display_, image->buf, mem); |
684 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); | 705 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
685 if (va_res == VA_STATUS_SUCCESS) | 706 if (va_res == VA_STATUS_SUCCESS) |
686 return true; | 707 return true; |
687 | 708 |
688 va_res = vaDestroyImage(va_display_, image->image_id); | 709 va_res = vaDestroyImage(va_display_, image->image_id); |
689 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); | 710 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); |
690 | 711 |
691 return false; | 712 return false; |
692 } | 713 } |
693 | 714 |
694 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { | 715 bool VaapiWrapper::GetVaImage(VASurfaceID va_surface_id, |
| 716 VAImageFormat* format, |
| 717 const gfx::Size& size, |
| 718 VAImage* image, |
| 719 void** mem) { |
| 720 base::AutoLock auto_lock(va_lock_); |
| 721 |
| 722 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
| 723 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
| 724 |
| 725 va_res = |
| 726 vaCreateImage(va_display_, format, size.width(), size.height(), image); |
| 727 VA_SUCCESS_OR_RETURN(va_res, "vaCreateImage failed", false); |
| 728 |
| 729 va_res = vaGetImage(va_display_, va_surface_id, 0, 0, size.width(), |
| 730 size.height(), image->image_id); |
| 731 VA_LOG_ON_ERROR(va_res, "vaGetImage failed"); |
| 732 |
| 733 if (va_res == VA_STATUS_SUCCESS) { |
| 734 // Map the VAImage into memory |
| 735 va_res = vaMapBuffer(va_display_, image->buf, mem); |
| 736 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
| 737 } |
| 738 |
| 739 if (va_res != VA_STATUS_SUCCESS) { |
| 740 va_res = vaDestroyImage(va_display_, image->image_id); |
| 741 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); |
| 742 return false; |
| 743 } |
| 744 |
| 745 return true; |
| 746 } |
| 747 |
| 748 void VaapiWrapper::ReturnVaImage(VAImage* image) { |
695 base::AutoLock auto_lock(va_lock_); | 749 base::AutoLock auto_lock(va_lock_); |
696 | 750 |
697 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf); | 751 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf); |
698 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | 752 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
699 | 753 |
700 va_res = vaDestroyImage(va_display_, image->image_id); | 754 va_res = vaDestroyImage(va_display_, image->image_id); |
701 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); | 755 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); |
702 } | 756 } |
703 | 757 |
704 static void DestroyVAImage(VADisplay va_display, VAImage image) { | 758 static void DestroyVAImage(VADisplay va_display, VAImage image) { |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
906 #if defined(USE_X11) | 960 #if defined(USE_X11) |
907 paths[kModuleVa_x11].push_back("libva-x11.so.1"); | 961 paths[kModuleVa_x11].push_back("libva-x11.so.1"); |
908 #elif defined(USE_OZONE) | 962 #elif defined(USE_OZONE) |
909 paths[kModuleVa_drm].push_back("libva-drm.so.1"); | 963 paths[kModuleVa_drm].push_back("libva-drm.so.1"); |
910 #endif | 964 #endif |
911 | 965 |
912 return InitializeStubs(paths); | 966 return InitializeStubs(paths); |
913 } | 967 } |
914 | 968 |
915 } // namespace content | 969 } // namespace content |
OLD | NEW |