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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, | 50 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, |
51 }; | 51 }; |
52 | 52 |
53 // Attributes required for encode. | 53 // Attributes required for encode. |
54 static const VAConfigAttrib kEncodeVAConfigAttribs[] = { | 54 static const VAConfigAttrib kEncodeVAConfigAttribs[] = { |
55 {VAConfigAttribRateControl, VA_RC_CBR}, | 55 {VAConfigAttribRateControl, VA_RC_CBR}, |
56 {VAConfigAttribEncPackedHeaders, | 56 {VAConfigAttribEncPackedHeaders, |
57 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE}, | 57 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE}, |
58 }; | 58 }; |
59 | 59 |
| 60 struct ProfileMap { |
| 61 media::VideoCodecProfile profile; |
| 62 VAProfile va_profile; |
| 63 }; |
| 64 |
| 65 // A map between VideoCodecProfile and VAProfile. |
| 66 static const ProfileMap kProfileMap[] = { |
| 67 {media::H264PROFILE_BASELINE, VAProfileH264Baseline}, |
| 68 {media::H264PROFILE_MAIN, VAProfileH264Main}, |
| 69 // TODO(posciak): See if we can/want support other variants of |
| 70 // media::H264PROFILE_HIGH*. |
| 71 {media::H264PROFILE_HIGH, VAProfileH264High}, |
| 72 }; |
| 73 |
| 74 static std::vector<VAConfigAttrib> GetRequiredAttribs( |
| 75 VaapiWrapper::CodecMode mode) { |
| 76 std::vector<VAConfigAttrib> required_attribs; |
| 77 required_attribs.insert( |
| 78 required_attribs.end(), |
| 79 kCommonVAConfigAttribs, |
| 80 kCommonVAConfigAttribs + arraysize(kCommonVAConfigAttribs)); |
| 81 if (mode == VaapiWrapper::kEncode) { |
| 82 required_attribs.insert( |
| 83 required_attribs.end(), |
| 84 kEncodeVAConfigAttribs, |
| 85 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs)); |
| 86 } |
| 87 return required_attribs; |
| 88 } |
| 89 |
60 // Maps Profile enum values to VaProfile values. | 90 // Maps Profile enum values to VaProfile values. |
61 static VAProfile ProfileToVAProfile( | 91 static VAProfile ProfileToVAProfile( |
62 media::VideoCodecProfile profile, | 92 media::VideoCodecProfile profile, |
63 const std::vector<VAProfile>& supported_profiles) { | 93 const std::vector<VAProfile>& supported_profiles) { |
64 | 94 |
65 VAProfile va_profile = VAProfileNone; | 95 VAProfile va_profile = VAProfileNone; |
66 | 96 for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
67 switch (profile) { | 97 if (kProfileMap[i].profile == profile) { |
68 case media::H264PROFILE_BASELINE: | 98 va_profile = kProfileMap[i].va_profile; |
69 va_profile = VAProfileH264Baseline; | |
70 break; | 99 break; |
71 case media::H264PROFILE_MAIN: | 100 } |
72 va_profile = VAProfileH264Main; | |
73 break; | |
74 // TODO(posciak): See if we can/want support other variants | |
75 // of media::H264PROFILE_HIGH*. | |
76 case media::H264PROFILE_HIGH: | |
77 va_profile = VAProfileH264High; | |
78 break; | |
79 default: | |
80 break; | |
81 } | 101 } |
82 | 102 |
83 bool supported = std::find(supported_profiles.begin(), | 103 bool supported = std::find(supported_profiles.begin(), |
84 supported_profiles.end(), | 104 supported_profiles.end(), |
85 va_profile) != supported_profiles.end(); | 105 va_profile) != supported_profiles.end(); |
86 | 106 |
87 if (!supported && va_profile == VAProfileH264Baseline) { | 107 if (!supported && va_profile == VAProfileH264Baseline) { |
88 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips | 108 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips |
89 // the information whether the profile is constrained or not, so we have no | 109 // the information whether the profile is constrained or not, so we have no |
90 // way to know here. Try for baseline first, but if it is not supported, | 110 // way to know here. Try for baseline first, but if it is not supported, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 const base::Closure& report_error_to_uma_cb) { | 152 const base::Closure& report_error_to_uma_cb) { |
133 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 153 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
134 | 154 |
135 if (!vaapi_wrapper->Initialize( | 155 if (!vaapi_wrapper->Initialize( |
136 mode, profile, x_display, report_error_to_uma_cb)) | 156 mode, profile, x_display, report_error_to_uma_cb)) |
137 vaapi_wrapper.reset(); | 157 vaapi_wrapper.reset(); |
138 | 158 |
139 return vaapi_wrapper.Pass(); | 159 return vaapi_wrapper.Pass(); |
140 } | 160 } |
141 | 161 |
| 162 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( |
| 163 Display* x_display, |
| 164 const base::Closure& report_error_to_uma_cb) { |
| 165 std::vector<media::VideoCodecProfile> supported_profiles; |
| 166 |
| 167 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); |
| 168 if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) { |
| 169 return supported_profiles; |
| 170 } |
| 171 |
| 172 std::vector<VAProfile> va_profiles; |
| 173 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) |
| 174 return supported_profiles; |
| 175 |
| 176 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); |
| 177 for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
| 178 VAProfile va_profile = |
| 179 ProfileToVAProfile(kProfileMap[i].profile, va_profiles); |
| 180 if (va_profile != VAProfileNone && |
| 181 wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) && |
| 182 wrapper->AreAttribsSupported( |
| 183 va_profile, VAEntrypointEncSlice, required_attribs)) { |
| 184 supported_profiles.push_back(kProfileMap[i].profile); |
| 185 } |
| 186 } |
| 187 return supported_profiles; |
| 188 } |
| 189 |
142 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { | 190 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
| 191 base::AutoLock auto_lock(va_lock_); |
143 VADisplayAttribute item = {VADisplayAttribRenderMode, | 192 VADisplayAttribute item = {VADisplayAttribRenderMode, |
144 1, // At least support '_LOCAL_OVERLAY'. | 193 1, // At least support '_LOCAL_OVERLAY'. |
145 -1, // The maximum possible support 'ALL'. | 194 -1, // The maximum possible support 'ALL'. |
146 VA_RENDER_MODE_LOCAL_GPU, | 195 VA_RENDER_MODE_LOCAL_GPU, |
147 VA_DISPLAY_ATTRIB_SETTABLE}; | 196 VA_DISPLAY_ATTRIB_SETTABLE}; |
148 | 197 |
149 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 198 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
150 if (va_res != VA_STATUS_SUCCESS) | 199 if (va_res != VA_STATUS_SUCCESS) |
151 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 200 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
152 } | 201 } |
153 | 202 |
154 bool VaapiWrapper::Initialize(CodecMode mode, | 203 bool VaapiWrapper::VaInitialize(Display* x_display, |
155 media::VideoCodecProfile profile, | 204 const base::Closure& report_error_to_uma_cb) { |
156 Display* x_display, | |
157 const base::Closure& report_error_to_uma_cb) { | |
158 static bool vaapi_functions_initialized = PostSandboxInitialization(); | 205 static bool vaapi_functions_initialized = PostSandboxInitialization(); |
159 if (!vaapi_functions_initialized) { | 206 if (!vaapi_functions_initialized) { |
160 DVLOG(1) << "Failed to initialize VAAPI libs"; | 207 DVLOG(1) << "Failed to initialize VAAPI libs"; |
161 return false; | 208 return false; |
162 } | 209 } |
163 | 210 |
164 report_error_to_uma_cb_ = report_error_to_uma_cb; | 211 report_error_to_uma_cb_ = report_error_to_uma_cb; |
165 | 212 |
166 base::AutoLock auto_lock(va_lock_); | 213 base::AutoLock auto_lock(va_lock_); |
167 | 214 |
168 va_display_ = vaGetDisplay(x_display); | 215 va_display_ = vaGetDisplay(x_display); |
169 if (!vaDisplayIsValid(va_display_)) { | 216 if (!vaDisplayIsValid(va_display_)) { |
170 DVLOG(1) << "Could not get a valid VA display"; | 217 DVLOG(1) << "Could not get a valid VA display"; |
171 return false; | 218 return false; |
172 } | 219 } |
173 | 220 |
174 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); | 221 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); |
175 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); | 222 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); |
176 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; | 223 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; |
177 | 224 |
178 if (VAAPIVersionLessThan(0, 34)) { | 225 if (VAAPIVersionLessThan(0, 34)) { |
179 DVLOG(1) << "VAAPI version < 0.34 is not supported."; | 226 DVLOG(1) << "VAAPI version < 0.34 is not supported."; |
180 return false; | 227 return false; |
181 } | 228 } |
| 229 return true; |
| 230 } |
182 | 231 |
| 232 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) { |
| 233 base::AutoLock auto_lock(va_lock_); |
183 // Query the driver for supported profiles. | 234 // Query the driver for supported profiles. |
184 int max_profiles = vaMaxNumProfiles(va_display_); | 235 int max_profiles = vaMaxNumProfiles(va_display_); |
185 std::vector<VAProfile> supported_profiles( | 236 std::vector<VAProfile> supported_profiles( |
186 base::checked_cast<size_t>(max_profiles)); | 237 base::checked_cast<size_t>(max_profiles)); |
187 | 238 |
188 int num_supported_profiles; | 239 int num_supported_profiles; |
189 va_res = vaQueryConfigProfiles( | 240 VAStatus va_res = vaQueryConfigProfiles( |
190 va_display_, &supported_profiles[0], &num_supported_profiles); | 241 va_display_, &supported_profiles[0], &num_supported_profiles); |
191 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false); | 242 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false); |
192 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) { | 243 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) { |
193 DVLOG(1) << "vaQueryConfigProfiles returned: " << num_supported_profiles; | 244 DVLOG(1) << "vaQueryConfigProfiles returned: " << num_supported_profiles; |
194 return false; | 245 return false; |
195 } | 246 } |
196 | 247 |
197 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); | 248 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); |
| 249 *profiles = supported_profiles; |
| 250 return true; |
| 251 } |
198 | 252 |
199 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); | 253 bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile, |
200 if (va_profile == VAProfileNone) { | 254 VAEntrypoint entrypoint) { |
201 DVLOG(1) << "Unsupported profile"; | 255 base::AutoLock auto_lock(va_lock_); |
202 return false; | |
203 } | |
204 | |
205 // Query the driver for supported entrypoints. | 256 // Query the driver for supported entrypoints. |
206 int max_entrypoints = vaMaxNumEntrypoints(va_display_); | 257 int max_entrypoints = vaMaxNumEntrypoints(va_display_); |
207 std::vector<VAEntrypoint> supported_entrypoints( | 258 std::vector<VAEntrypoint> supported_entrypoints( |
208 base::checked_cast<size_t>(max_entrypoints)); | 259 base::checked_cast<size_t>(max_entrypoints)); |
209 | 260 |
210 int num_supported_entrypoints; | 261 int num_supported_entrypoints; |
211 va_res = vaQueryConfigEntrypoints(va_display_, | 262 VAStatus va_res = vaQueryConfigEntrypoints(va_display_, |
212 va_profile, | 263 va_profile, |
213 &supported_entrypoints[0], | 264 &supported_entrypoints[0], |
214 &num_supported_entrypoints); | 265 &num_supported_entrypoints); |
215 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false); | 266 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false); |
216 if (num_supported_entrypoints < 0 || | 267 if (num_supported_entrypoints < 0 || |
217 num_supported_entrypoints > max_entrypoints) { | 268 num_supported_entrypoints > max_entrypoints) { |
218 DVLOG(1) << "vaQueryConfigEntrypoints returned: " | 269 DVLOG(1) << "vaQueryConfigEntrypoints returned: " |
219 << num_supported_entrypoints; | 270 << num_supported_entrypoints; |
220 return false; | 271 return false; |
221 } | 272 } |
222 | 273 |
223 VAEntrypoint entrypoint = | |
224 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); | |
225 | |
226 if (std::find(supported_entrypoints.begin(), | 274 if (std::find(supported_entrypoints.begin(), |
227 supported_entrypoints.end(), | 275 supported_entrypoints.end(), |
228 entrypoint) == supported_entrypoints.end()) { | 276 entrypoint) == supported_entrypoints.end()) { |
229 DVLOG(1) << "Unsupported entrypoint"; | 277 DVLOG(1) << "Unsupported entrypoint"; |
230 return false; | 278 return false; |
231 } | 279 } |
| 280 return true; |
| 281 } |
232 | 282 |
| 283 bool VaapiWrapper::AreAttribsSupported( |
| 284 VAProfile va_profile, |
| 285 VAEntrypoint entrypoint, |
| 286 const std::vector<VAConfigAttrib>& required_attribs) { |
| 287 base::AutoLock auto_lock(va_lock_); |
233 // Query the driver for required attributes. | 288 // Query the driver for required attributes. |
234 std::vector<VAConfigAttrib> required_attribs; | |
235 required_attribs.insert( | |
236 required_attribs.end(), | |
237 kCommonVAConfigAttribs, | |
238 kCommonVAConfigAttribs + arraysize(kCommonVAConfigAttribs)); | |
239 if (mode == kEncode) { | |
240 required_attribs.insert( | |
241 required_attribs.end(), | |
242 kEncodeVAConfigAttribs, | |
243 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs)); | |
244 } | |
245 | |
246 std::vector<VAConfigAttrib> attribs = required_attribs; | 289 std::vector<VAConfigAttrib> attribs = required_attribs; |
247 for (size_t i = 0; i < required_attribs.size(); ++i) | 290 for (size_t i = 0; i < required_attribs.size(); ++i) |
248 attribs[i].value = 0; | 291 attribs[i].value = 0; |
249 | 292 |
250 va_res = vaGetConfigAttributes( | 293 VAStatus va_res = vaGetConfigAttributes( |
251 va_display_, va_profile, entrypoint, &attribs[0], attribs.size()); | 294 va_display_, va_profile, entrypoint, &attribs[0], attribs.size()); |
252 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); | 295 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); |
253 | 296 |
254 for (size_t i = 0; i < required_attribs.size(); ++i) { | 297 for (size_t i = 0; i < required_attribs.size(); ++i) { |
255 if (attribs[i].type != required_attribs[i].type || | 298 if (attribs[i].type != required_attribs[i].type || |
256 (attribs[i].value & required_attribs[i].value) != | 299 (attribs[i].value & required_attribs[i].value) != |
257 required_attribs[i].value) { | 300 required_attribs[i].value) { |
258 DVLOG(1) << "Unsupported value " << required_attribs[i].value | 301 DVLOG(1) << "Unsupported value " << required_attribs[i].value |
259 << " for attribute type " << required_attribs[i].type; | 302 << " for attribute type " << required_attribs[i].type; |
260 return false; | 303 return false; |
261 } | 304 } |
262 } | 305 } |
| 306 return true; |
| 307 } |
| 308 |
| 309 bool VaapiWrapper::Initialize(CodecMode mode, |
| 310 media::VideoCodecProfile profile, |
| 311 Display* x_display, |
| 312 const base::Closure& report_error_to_uma_cb) { |
| 313 if (!VaInitialize(x_display, report_error_to_uma_cb)) |
| 314 return false; |
| 315 std::vector<VAProfile> supported_va_profiles; |
| 316 if (!GetSupportedVaProfiles(&supported_va_profiles)) |
| 317 return false; |
| 318 VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles); |
| 319 if (va_profile == VAProfileNone) { |
| 320 DVLOG(1) << "Unsupported profile"; |
| 321 return false; |
| 322 } |
| 323 VAEntrypoint entrypoint = |
| 324 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); |
| 325 if (!IsEntrypointSupported(va_profile, entrypoint)) |
| 326 return false; |
| 327 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); |
| 328 if (!AreAttribsSupported(va_profile, entrypoint, required_attribs)) |
| 329 return false; |
263 | 330 |
264 TryToSetVADisplayAttributeToLocalGPU(); | 331 TryToSetVADisplayAttributeToLocalGPU(); |
265 | 332 |
266 va_res = vaCreateConfig(va_display_, | 333 base::AutoLock auto_lock(va_lock_); |
267 va_profile, | 334 VAStatus va_res = vaCreateConfig(va_display_, |
268 entrypoint, | 335 va_profile, |
269 &required_attribs[0], | 336 entrypoint, |
270 required_attribs.size(), | 337 &required_attribs[0], |
271 &va_config_id_); | 338 required_attribs.size(), |
| 339 &va_config_id_); |
272 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | 340 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); |
273 | 341 |
274 return true; | 342 return true; |
275 } | 343 } |
276 | 344 |
277 void VaapiWrapper::Deinitialize() { | 345 void VaapiWrapper::Deinitialize() { |
278 base::AutoLock auto_lock(va_lock_); | 346 base::AutoLock auto_lock(va_lock_); |
279 | 347 |
280 if (va_config_id_ != VA_INVALID_ID) { | 348 if (va_config_id_ != VA_INVALID_ID) { |
281 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 349 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 | 735 |
668 // static | 736 // static |
669 bool VaapiWrapper::PostSandboxInitialization() { | 737 bool VaapiWrapper::PostSandboxInitialization() { |
670 StubPathMap paths; | 738 StubPathMap paths; |
671 paths[kModuleVa].push_back(kVaLib); | 739 paths[kModuleVa].push_back(kVaLib); |
672 | 740 |
673 return InitializeStubs(paths); | 741 return InitializeStubs(paths); |
674 } | 742 } |
675 | 743 |
676 } // namespace content | 744 } // namespace content |
OLD | NEW |