Chromium Code Reviews| 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 static std::vector<VAConfigAttrib> GetRequiredAttribs( | |
| 61 VaapiWrapper::CodecMode mode) { | |
| 62 std::vector<VAConfigAttrib> required_attribs; | |
| 63 required_attribs.insert( | |
| 64 required_attribs.end(), | |
| 65 kCommonVAConfigAttribs, | |
| 66 kCommonVAConfigAttribs + arraysize(kCommonVAConfigAttribs)); | |
| 67 if (mode == VaapiWrapper::kEncode) { | |
| 68 required_attribs.insert( | |
| 69 required_attribs.end(), | |
| 70 kEncodeVAConfigAttribs, | |
| 71 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs)); | |
| 72 } | |
| 73 return required_attribs; | |
| 74 } | |
| 75 | |
| 60 // Maps Profile enum values to VaProfile values. | 76 // Maps Profile enum values to VaProfile values. |
| 61 static VAProfile ProfileToVAProfile( | 77 static VAProfile ProfileToVAProfile( |
| 62 media::VideoCodecProfile profile, | 78 media::VideoCodecProfile profile, |
| 63 const std::vector<VAProfile>& supported_profiles) { | 79 const std::vector<VAProfile>& supported_profiles) { |
| 64 | 80 |
| 65 VAProfile va_profile = VAProfileNone; | 81 VAProfile va_profile = VAProfileNone; |
| 66 | 82 |
| 67 switch (profile) { | 83 switch (profile) { |
| 68 case media::H264PROFILE_BASELINE: | 84 case media::H264PROFILE_BASELINE: |
| 69 va_profile = VAProfileH264Baseline; | 85 va_profile = VAProfileH264Baseline; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 const base::Closure& report_error_to_uma_cb) { | 148 const base::Closure& report_error_to_uma_cb) { |
| 133 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 149 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
| 134 | 150 |
| 135 if (!vaapi_wrapper->Initialize( | 151 if (!vaapi_wrapper->Initialize( |
| 136 mode, profile, x_display, report_error_to_uma_cb)) | 152 mode, profile, x_display, report_error_to_uma_cb)) |
| 137 vaapi_wrapper.reset(); | 153 vaapi_wrapper.reset(); |
| 138 | 154 |
| 139 return vaapi_wrapper.Pass(); | 155 return vaapi_wrapper.Pass(); |
| 140 } | 156 } |
| 141 | 157 |
| 158 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedProfiles( | |
| 159 Display* x_display, | |
| 160 const base::Closure& report_error_to_uma_cb) { | |
| 161 std::vector<media::VideoCodecProfile> supported_profiles; | |
| 162 media::VideoCodecProfile profiles[3] = {media::H264PROFILE_BASELINE, | |
|
Pawel Osciak
2014/09/26 07:15:12
Ideally we'd like to use all va_profiles and use s
wuchengli
2014/09/26 09:02:28
GetSupportedProfiles is called when GPU process st
| |
| 163 media::H264PROFILE_MAIN, | |
| 164 media::H264PROFILE_HIGH}; | |
| 165 | |
| 166 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); | |
| 167 std::vector<VAProfile> va_profiles; | |
| 168 if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) { | |
| 169 return supported_profiles; | |
| 170 } | |
| 171 if (!wrapper->GetSupportedVaProfiles(&va_profiles)) | |
| 172 return supported_profiles; | |
| 173 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); | |
| 174 for (size_t i = 0; i < arraysize(profiles); i++) { | |
| 175 VAProfile va_profile = ProfileToVAProfile(profiles[i], va_profiles); | |
|
Pawel Osciak
2014/09/26 07:15:12
We have this chunk of code duplicated here and in
wuchengli
2014/09/26 09:02:28
Done.
vaCreateConfig needs VA profile, entrypoint
| |
| 176 if (va_profile != VAProfileNone && | |
| 177 wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) && | |
| 178 wrapper->IsAttribSupported( | |
| 179 va_profile, VAEntrypointEncSlice, required_attribs)) { | |
| 180 supported_profiles.push_back(profiles[i]); | |
| 181 } | |
| 182 } | |
| 183 return supported_profiles; | |
| 184 } | |
| 185 | |
| 142 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { | 186 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
| 143 VADisplayAttribute item = {VADisplayAttribRenderMode, | 187 VADisplayAttribute item = {VADisplayAttribRenderMode, |
| 144 1, // At least support '_LOCAL_OVERLAY'. | 188 1, // At least support '_LOCAL_OVERLAY'. |
| 145 -1, // The maximum possible support 'ALL'. | 189 -1, // The maximum possible support 'ALL'. |
| 146 VA_RENDER_MODE_LOCAL_GPU, | 190 VA_RENDER_MODE_LOCAL_GPU, |
| 147 VA_DISPLAY_ATTRIB_SETTABLE}; | 191 VA_DISPLAY_ATTRIB_SETTABLE}; |
| 148 | 192 |
| 149 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 193 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
| 150 if (va_res != VA_STATUS_SUCCESS) | 194 if (va_res != VA_STATUS_SUCCESS) |
| 151 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 195 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
| 152 } | 196 } |
| 153 | 197 |
| 154 bool VaapiWrapper::Initialize(CodecMode mode, | 198 bool VaapiWrapper::VaInitialize(Display* x_display, |
| 155 media::VideoCodecProfile profile, | 199 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(); | 200 static bool vaapi_functions_initialized = PostSandboxInitialization(); |
| 159 if (!vaapi_functions_initialized) { | 201 if (!vaapi_functions_initialized) { |
| 160 DVLOG(1) << "Failed to initialize VAAPI libs"; | 202 DVLOG(1) << "Failed to initialize VAAPI libs"; |
| 161 return false; | 203 return false; |
| 162 } | 204 } |
| 163 | 205 |
| 164 report_error_to_uma_cb_ = report_error_to_uma_cb; | 206 report_error_to_uma_cb_ = report_error_to_uma_cb; |
| 165 | 207 |
| 166 base::AutoLock auto_lock(va_lock_); | 208 base::AutoLock auto_lock(va_lock_); |
| 167 | 209 |
| 168 va_display_ = vaGetDisplay(x_display); | 210 va_display_ = vaGetDisplay(x_display); |
| 169 if (!vaDisplayIsValid(va_display_)) { | 211 if (!vaDisplayIsValid(va_display_)) { |
| 170 DVLOG(1) << "Could not get a valid VA display"; | 212 DVLOG(1) << "Could not get a valid VA display"; |
| 171 return false; | 213 return false; |
| 172 } | 214 } |
| 173 | 215 |
| 174 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); | 216 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_); |
| 175 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); | 217 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); |
| 176 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; | 218 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; |
| 177 | 219 |
| 178 if (VAAPIVersionLessThan(0, 34)) { | 220 if (VAAPIVersionLessThan(0, 34)) { |
| 179 DVLOG(1) << "VAAPI version < 0.34 is not supported."; | 221 DVLOG(1) << "VAAPI version < 0.34 is not supported."; |
| 180 return false; | 222 return false; |
| 181 } | 223 } |
| 224 return true; | |
| 225 } | |
| 182 | 226 |
| 227 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) { | |
| 228 base::AutoLock auto_lock(va_lock_); | |
| 183 // Query the driver for supported profiles. | 229 // Query the driver for supported profiles. |
| 184 int max_profiles = vaMaxNumProfiles(va_display_); | 230 int max_profiles = vaMaxNumProfiles(va_display_); |
| 185 std::vector<VAProfile> supported_profiles( | 231 std::vector<VAProfile> supported_profiles( |
| 186 base::checked_cast<size_t>(max_profiles)); | 232 base::checked_cast<size_t>(max_profiles)); |
| 187 | 233 |
| 188 int num_supported_profiles; | 234 int num_supported_profiles; |
| 189 va_res = vaQueryConfigProfiles( | 235 VAStatus va_res = vaQueryConfigProfiles( |
| 190 va_display_, &supported_profiles[0], &num_supported_profiles); | 236 va_display_, &supported_profiles[0], &num_supported_profiles); |
| 191 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false); | 237 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false); |
| 192 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) { | 238 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) { |
| 193 DVLOG(1) << "vaQueryConfigProfiles returned: " << num_supported_profiles; | 239 DVLOG(1) << "vaQueryConfigProfiles returned: " << num_supported_profiles; |
| 194 return false; | 240 return false; |
| 195 } | 241 } |
| 196 | 242 |
| 197 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); | 243 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); |
| 244 *profiles = supported_profiles; | |
| 245 return true; | |
| 246 } | |
| 198 | 247 |
| 199 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); | 248 bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile, |
| 200 if (va_profile == VAProfileNone) { | 249 VAEntrypoint entrypoint) { |
| 201 DVLOG(1) << "Unsupported profile"; | 250 base::AutoLock auto_lock(va_lock_); |
| 202 return false; | |
| 203 } | |
| 204 | |
| 205 // Query the driver for supported entrypoints. | 251 // Query the driver for supported entrypoints. |
| 206 int max_entrypoints = vaMaxNumEntrypoints(va_display_); | 252 int max_entrypoints = vaMaxNumEntrypoints(va_display_); |
| 207 std::vector<VAEntrypoint> supported_entrypoints( | 253 std::vector<VAEntrypoint> supported_entrypoints( |
| 208 base::checked_cast<size_t>(max_entrypoints)); | 254 base::checked_cast<size_t>(max_entrypoints)); |
| 209 | 255 |
| 210 int num_supported_entrypoints; | 256 int num_supported_entrypoints; |
| 211 va_res = vaQueryConfigEntrypoints(va_display_, | 257 VAStatus va_res = vaQueryConfigEntrypoints(va_display_, |
| 212 va_profile, | 258 va_profile, |
| 213 &supported_entrypoints[0], | 259 &supported_entrypoints[0], |
| 214 &num_supported_entrypoints); | 260 &num_supported_entrypoints); |
| 215 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false); | 261 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false); |
| 216 if (num_supported_entrypoints < 0 || | 262 if (num_supported_entrypoints < 0 || |
| 217 num_supported_entrypoints > max_entrypoints) { | 263 num_supported_entrypoints > max_entrypoints) { |
| 218 DVLOG(1) << "vaQueryConfigEntrypoints returned: " | 264 DVLOG(1) << "vaQueryConfigEntrypoints returned: " |
| 219 << num_supported_entrypoints; | 265 << num_supported_entrypoints; |
| 220 return false; | 266 return false; |
| 221 } | 267 } |
| 222 | 268 |
| 223 VAEntrypoint entrypoint = | |
| 224 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); | |
| 225 | |
| 226 if (std::find(supported_entrypoints.begin(), | 269 if (std::find(supported_entrypoints.begin(), |
| 227 supported_entrypoints.end(), | 270 supported_entrypoints.end(), |
| 228 entrypoint) == supported_entrypoints.end()) { | 271 entrypoint) == supported_entrypoints.end()) { |
| 229 DVLOG(1) << "Unsupported entrypoint"; | 272 DVLOG(1) << "Unsupported entrypoint"; |
| 230 return false; | 273 return false; |
| 231 } | 274 } |
| 275 return true; | |
| 276 } | |
| 232 | 277 |
| 278 bool VaapiWrapper::IsAttribSupported( | |
| 279 VAProfile va_profile, | |
| 280 VAEntrypoint entrypoint, | |
| 281 const std::vector<VAConfigAttrib>& required_attribs) { | |
| 282 base::AutoLock auto_lock(va_lock_); | |
| 233 // Query the driver for required attributes. | 283 // 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; | 284 std::vector<VAConfigAttrib> attribs = required_attribs; |
| 247 for (size_t i = 0; i < required_attribs.size(); ++i) | 285 for (size_t i = 0; i < required_attribs.size(); ++i) |
| 248 attribs[i].value = 0; | 286 attribs[i].value = 0; |
| 249 | 287 |
| 250 va_res = vaGetConfigAttributes( | 288 VAStatus va_res = vaGetConfigAttributes( |
| 251 va_display_, va_profile, entrypoint, &attribs[0], attribs.size()); | 289 va_display_, va_profile, entrypoint, &attribs[0], attribs.size()); |
| 252 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); | 290 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); |
| 253 | 291 |
| 254 for (size_t i = 0; i < required_attribs.size(); ++i) { | 292 for (size_t i = 0; i < required_attribs.size(); ++i) { |
| 255 if (attribs[i].type != required_attribs[i].type || | 293 if (attribs[i].type != required_attribs[i].type || |
| 256 (attribs[i].value & required_attribs[i].value) != | 294 (attribs[i].value & required_attribs[i].value) != |
| 257 required_attribs[i].value) { | 295 required_attribs[i].value) { |
| 258 DVLOG(1) << "Unsupported value " << required_attribs[i].value | 296 DVLOG(1) << "Unsupported value " << required_attribs[i].value |
| 259 << " for attribute type " << required_attribs[i].type; | 297 << " for attribute type " << required_attribs[i].type; |
| 260 return false; | 298 return false; |
| 261 } | 299 } |
| 262 } | 300 } |
| 301 return true; | |
| 302 } | |
| 303 | |
| 304 bool VaapiWrapper::Initialize(CodecMode mode, | |
| 305 media::VideoCodecProfile profile, | |
| 306 Display* x_display, | |
| 307 const base::Closure& report_error_to_uma_cb) { | |
| 308 if (!VaInitialize(x_display, report_error_to_uma_cb)) | |
| 309 return false; | |
| 310 std::vector<VAProfile> supported_profiles; | |
| 311 if (!GetSupportedVaProfiles(&supported_profiles)) | |
| 312 return false; | |
| 313 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); | |
| 314 if (va_profile == VAProfileNone) { | |
| 315 DVLOG(1) << "Unsupported profile"; | |
| 316 return false; | |
| 317 } | |
| 318 VAEntrypoint entrypoint = | |
| 319 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); | |
| 320 if (!IsEntrypointSupported(va_profile, entrypoint)) | |
| 321 return false; | |
| 322 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); | |
| 323 if (!IsAttribSupported(va_profile, entrypoint, required_attribs)) | |
| 324 return false; | |
| 263 | 325 |
| 264 TryToSetVADisplayAttributeToLocalGPU(); | 326 TryToSetVADisplayAttributeToLocalGPU(); |
| 265 | 327 |
| 266 va_res = vaCreateConfig(va_display_, | 328 VAStatus va_res = vaCreateConfig(va_display_, |
|
kcwu
2014/09/26 07:50:45
va_lock_ for this?
wuchengli
2014/09/26 09:02:28
Done. Thanks for catching this.
| |
| 267 va_profile, | 329 va_profile, |
| 268 entrypoint, | 330 entrypoint, |
| 269 &required_attribs[0], | 331 &required_attribs[0], |
| 270 required_attribs.size(), | 332 required_attribs.size(), |
| 271 &va_config_id_); | 333 &va_config_id_); |
| 272 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | 334 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); |
| 273 | 335 |
| 274 return true; | 336 return true; |
| 275 } | 337 } |
| 276 | 338 |
| 277 void VaapiWrapper::Deinitialize() { | 339 void VaapiWrapper::Deinitialize() { |
| 278 base::AutoLock auto_lock(va_lock_); | 340 base::AutoLock auto_lock(va_lock_); |
| 279 | 341 |
| 280 if (va_config_id_ != VA_INVALID_ID) { | 342 if (va_config_id_ != VA_INVALID_ID) { |
| 281 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 343 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 667 | 729 |
| 668 // static | 730 // static |
| 669 bool VaapiWrapper::PostSandboxInitialization() { | 731 bool VaapiWrapper::PostSandboxInitialization() { |
| 670 StubPathMap paths; | 732 StubPathMap paths; |
| 671 paths[kModuleVa].push_back(kVaLib); | 733 paths[kModuleVa].push_back(kVaLib); |
| 672 | 734 |
| 673 return InitializeStubs(paths); | 735 return InitializeStubs(paths); |
| 674 } | 736 } |
| 675 | 737 |
| 676 } // namespace content | 738 } // namespace content |
| OLD | NEW |