Index: content/common/gpu/media/vaapi_wrapper.cc |
diff --git a/content/common/gpu/media/vaapi_wrapper.cc b/content/common/gpu/media/vaapi_wrapper.cc |
index 588fee3981e59072c6118996099258acaa51e82b..13f5854a7d7c8232a3ed17bc9a133663c7ebff49 100644 |
--- a/content/common/gpu/media/vaapi_wrapper.cc |
+++ b/content/common/gpu/media/vaapi_wrapper.cc |
@@ -8,12 +8,14 @@ |
#include "base/bind.h" |
#include "base/callback_helpers.h" |
+#include "base/command_line.h" |
#include "base/logging.h" |
#include "base/numerics/safe_conversions.h" |
#include "base/sys_info.h" |
// Auto-generated for dlopen libva libraries |
#include "content/common/gpu/media/va_stubs.h" |
#include "content/common/gpu/media/vaapi_picture.h" |
+#include "content/public/common/content_switches.h" |
#include "third_party/libyuv/include/libyuv.h" |
#include "ui/gl/gl_bindings.h" |
#if defined(USE_X11) |
@@ -56,6 +58,13 @@ using content_common_gpu_media::StubPathMap; |
namespace content { |
+// Maximum framerate of encoded profile. This value is an arbitary limit |
+// and not taken from HW documentation. |
+const int kMaxEncoderFramerate = 30; |
+ |
+base::LazyInstance<VaapiWrapper::LazyProfileInfos> |
+ VaapiWrapper::profile_infos_ = LAZY_INSTANCE_INITIALIZER; |
+ |
// Config attributes common for both encode and decode. |
static const VAConfigAttrib kCommonVAConfigAttribs[] = { |
{VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, |
@@ -98,41 +107,6 @@ static std::vector<VAConfigAttrib> GetRequiredAttribs( |
return required_attribs; |
} |
-// Maps Profile enum values to VaProfile values. |
-static VAProfile ProfileToVAProfile( |
- media::VideoCodecProfile profile, |
- const std::vector<VAProfile>& supported_profiles) { |
- |
- VAProfile va_profile = VAProfileNone; |
- for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
- if (kProfileMap[i].profile == profile) { |
- va_profile = kProfileMap[i].va_profile; |
- break; |
- } |
- } |
- |
- bool supported = std::find(supported_profiles.begin(), |
- supported_profiles.end(), |
- va_profile) != supported_profiles.end(); |
- |
- if (!supported && va_profile == VAProfileH264Baseline) { |
- // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips |
- // the information whether the profile is constrained or not, so we have no |
- // way to know here. Try for baseline first, but if it is not supported, |
- // try constrained baseline and hope this is what it actually is |
- // (which in practice is true for a great majority of cases). |
- if (std::find(supported_profiles.begin(), |
- supported_profiles.end(), |
- VAProfileH264ConstrainedBaseline) != |
- supported_profiles.end()) { |
- va_profile = VAProfileH264ConstrainedBaseline; |
- DVLOG(1) << "Falling back to constrained baseline profile."; |
- } |
- } |
- |
- return va_profile; |
-} |
- |
VASurface::VASurface(VASurfaceID va_surface_id, |
const gfx::Size& size, |
const ReleaseCB& release_cb) |
@@ -162,6 +136,7 @@ VaapiWrapper::~VaapiWrapper() { |
Deinitialize(); |
} |
+// static |
scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
CodecMode mode, |
VAProfile va_profile, |
@@ -170,12 +145,16 @@ scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
if (!vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) |
return nullptr; |
- if (!vaapi_wrapper->Initialize(mode, va_profile)) |
+ |
+ if (!vaapi_wrapper->Initialize(mode, va_profile)) { |
+ DVLOG(1) << "Unsupported va profile: " << va_profile; |
Pawel Osciak
2015/03/08 00:58:24
Initialize() may fail for other reasons too. Perha
henryhsu
2015/03/09 03:56:52
Done.
|
return nullptr; |
+ } |
return vaapi_wrapper.Pass(); |
} |
+// static |
scoped_ptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( |
CodecMode mode, |
media::VideoCodecProfile profile, |
@@ -185,42 +164,50 @@ scoped_ptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( |
if (!vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) |
return nullptr; |
- std::vector<VAProfile> supported_va_profiles; |
- if (!vaapi_wrapper->GetSupportedVaProfiles(&supported_va_profiles)) |
+ VAProfile va_profile = ProfileToVAProfile(profile, mode); |
+ if (!vaapi_wrapper->Initialize(mode, va_profile)) { |
+ DVLOG(1) << "Initialize failed. Profile: " << profile; |
return nullptr; |
- |
- VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles); |
- if (!vaapi_wrapper->Initialize(mode, va_profile)) |
- return nullptr; |
- |
+ } |
return vaapi_wrapper.Pass(); |
} |
-std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles( |
- const base::Closure& report_error_to_uma_cb) { |
- std::vector<media::VideoCodecProfile> supported_profiles; |
- |
- scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper()); |
- if (!wrapper->VaInitialize(report_error_to_uma_cb)) { |
- return supported_profiles; |
- } |
- |
- std::vector<VAProfile> va_profiles; |
- if (!wrapper->GetSupportedVaProfiles(&va_profiles)) |
- return supported_profiles; |
- |
- std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(kEncode); |
- for (size_t i = 0; i < arraysize(kProfileMap); i++) { |
- VAProfile va_profile = |
- ProfileToVAProfile(kProfileMap[i].profile, va_profiles); |
- if (va_profile != VAProfileNone && |
- wrapper->IsEntrypointSupported(va_profile, VAEntrypointEncSlice) && |
- wrapper->AreAttribsSupported( |
- va_profile, VAEntrypointEncSlice, required_attribs)) { |
- supported_profiles.push_back(kProfileMap[i].profile); |
+// static |
+std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
+VaapiWrapper::GetSupportedEncodeProfiles() { |
+ std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles; |
+ const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
+ if (cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode)) |
+ return profiles; |
+ |
+ std::vector<ProfileInfo> encode_profile_infos = |
+ profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kEncode); |
+ |
+ for (size_t i = 0; i < arraysize(kProfileMap); ++i) { |
+ VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kEncode); |
+ if (va_profile == VAProfileNone) |
+ continue; |
+ for (const auto& profile_info : encode_profile_infos) { |
+ if (profile_info.va_profile == va_profile) { |
+ media::VideoEncodeAccelerator::SupportedProfile profile; |
+ profile.profile = kProfileMap[i].profile; |
+ profile.max_resolution = profile_info.max_resolution; |
+ profile.max_framerate_numerator = kMaxEncoderFramerate; |
+ profile.max_framerate_denominator = 1; |
+ profiles.push_back(profile); |
+ } |
Pawel Osciak
2015/03/08 00:58:24
Could we break here?
henryhsu
2015/03/09 03:56:52
Done.
|
} |
} |
- return supported_profiles; |
+ return profiles; |
+} |
+ |
+// static |
+std::vector<VaapiWrapper::ProfileInfo> |
+VaapiWrapper::GetSupportedProfileInfosForCodecMode(CodecMode mode) { |
+ scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
+ if (!vaapi_wrapper->VaInitialize(base::Bind(&base::DoNothing))) |
+ return std::vector<ProfileInfo>(); |
+ return vaapi_wrapper->GetSupportedProfileInfosForCodecModeInternal(mode); |
} |
void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
@@ -236,6 +223,70 @@ void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
} |
+// static |
+VAProfile VaapiWrapper::ProfileToVAProfile( |
+ media::VideoCodecProfile profile, CodecMode mode) { |
+ VAProfile va_profile = VAProfileNone; |
+ for (size_t i = 0; i < arraysize(kProfileMap); ++i) { |
+ if (kProfileMap[i].profile == profile) { |
+ va_profile = kProfileMap[i].va_profile; |
+ break; |
+ } |
+ } |
+ if (!profile_infos_.Get().IsProfileSupported(mode, va_profile) && |
+ va_profile == VAProfileH264Baseline) { |
+ // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips |
+ // the information whether the profile is constrained or not, so we have no |
+ // way to know here. Try for baseline first, but if it is not supported, |
+ // try constrained baseline and hope this is what it actually is |
+ // (which in practice is true for a great majority of cases). |
+ if (profile_infos_.Get().IsProfileSupported( |
+ mode, VAProfileH264ConstrainedBaseline)) { |
+ va_profile = VAProfileH264ConstrainedBaseline; |
+ DVLOG(1) << "Fall back to constrained baseline profile."; |
+ } |
+ } |
+ return va_profile; |
+} |
+ |
+std::vector<VaapiWrapper::ProfileInfo> |
+VaapiWrapper::GetSupportedProfileInfosForCodecModeInternal(CodecMode mode) { |
+ std::vector<ProfileInfo> supported_profile_infos; |
+ std::vector<VAProfile> va_profiles; |
+ if (!GetSupportedVaProfiles(&va_profiles)) |
+ return supported_profile_infos; |
+ |
+ std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); |
+ VAEntrypoint entrypoint = |
+ (mode == kEncode ? VAEntrypointEncSlice: VAEntrypointVLD); |
+ |
+ base::AutoLock auto_lock(va_lock_); |
+ for (const auto& va_profile : va_profiles) { |
+ if (!IsEntrypointSupported(va_profile, entrypoint)) |
+ continue; |
+ if (!AreAttribsSupported(va_profile, entrypoint, required_attribs)) |
+ continue; |
+ VAConfigID config_id; |
+ VAStatus va_res = vaCreateConfig( |
+ va_display_, |
+ va_profile, |
+ entrypoint, |
+ &required_attribs[0], |
+ required_attribs.size(), |
+ &config_id); |
+ if (va_res != VA_STATUS_SUCCESS) { |
+ LOG_VA_ERROR_AND_REPORT(va_res, "vaCreateConfig failed"); |
+ continue; |
+ } |
+ ProfileInfo profile_info; |
+ if (!GetMaxResolutionForVAConfigID(config_id, &profile_info.max_resolution)) |
Pawel Osciak
2015/03/08 00:58:24
I think we should LOG(ERROR) here, failure here ma
henryhsu
2015/03/09 03:56:52
Done.
|
+ continue; |
+ profile_info.va_profile = va_profile; |
+ supported_profile_infos.push_back(profile_info); |
+ } |
+ return supported_profile_infos; |
+} |
+ |
bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) { |
static bool vaapi_functions_initialized = PostSandboxInitialization(); |
if (!vaapi_functions_initialized) { |
@@ -306,7 +357,7 @@ bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) { |
bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile, |
VAEntrypoint entrypoint) { |
- base::AutoLock auto_lock(va_lock_); |
+ va_lock_.AssertAcquired(); |
// Query the driver for supported entrypoints. |
int max_entrypoints = vaMaxNumEntrypoints(va_display_); |
std::vector<VAEntrypoint> supported_entrypoints( |
@@ -338,7 +389,7 @@ bool VaapiWrapper::AreAttribsSupported( |
VAProfile va_profile, |
VAEntrypoint entrypoint, |
const std::vector<VAConfigAttrib>& required_attribs) { |
- base::AutoLock auto_lock(va_lock_); |
+ va_lock_.AssertAcquired(); |
// Query the driver for required attributes. |
std::vector<VAConfigAttrib> attribs = required_attribs; |
for (size_t i = 0; i < required_attribs.size(); ++i) |
@@ -360,21 +411,52 @@ bool VaapiWrapper::AreAttribsSupported( |
return true; |
} |
-bool VaapiWrapper::Initialize(CodecMode mode, VAProfile va_profile) { |
- if (va_profile == VAProfileNone) { |
- DVLOG(1) << "Unsupported profile"; |
+bool VaapiWrapper::GetMaxResolutionForVAConfigID(VAConfigID va_config_id, |
+ gfx::Size* resolution) { |
+ va_lock_.AssertAcquired(); |
+ unsigned int num_attribs; |
+ |
+ // Calls vaQuerySurfaceAttributes twice. The first time is to get the number |
+ // of attributes to prepare the space and the second time is to get all |
+ // attributes. |
+ VAStatus va_res; |
+ va_res = vaQuerySurfaceAttributes( |
+ va_display_, va_config_id, NULL, &num_attribs); |
Pawel Osciak
2015/03/08 00:58:24
s/NULL/nullptr/
henryhsu
2015/03/09 03:56:52
Done.
|
+ VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false); |
+ if (!num_attribs) |
return false; |
+ |
+ std::vector<VASurfaceAttrib> attrib_list( |
+ base::checked_cast<size_t>(num_attribs)); |
+ |
+ va_res = vaQuerySurfaceAttributes( |
+ va_display_, va_config_id, &attrib_list[0], &num_attribs); |
+ VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false); |
+ |
+ resolution->SetSize(0, 0); |
+ for (size_t i = 0; i < num_attribs; i++) { |
Pawel Osciak
2015/03/08 00:58:24
for (const auto& attrib : attrib_list)
henryhsu
2015/03/09 03:56:52
Done.
|
+ if (attrib_list[i].type == VASurfaceAttribMaxWidth) |
+ resolution->set_width(attrib_list[i].value.value.i); |
+ else if (attrib_list[i].type == VASurfaceAttribMaxHeight) |
+ resolution->set_height(attrib_list[i].value.value.i); |
} |
- VAEntrypoint entrypoint = |
- (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); |
- if (!IsEntrypointSupported(va_profile, entrypoint)) |
+ if (resolution->IsEmpty()) { |
+ LOG(ERROR) << "Codec resolution " << resolution->ToString() |
+ << " cannot be zero."; |
return false; |
- std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); |
- if (!AreAttribsSupported(va_profile, entrypoint, required_attribs)) |
+ } |
+ return true; |
+} |
+ |
+bool VaapiWrapper::Initialize(CodecMode mode, VAProfile va_profile) { |
+ if (!profile_infos_.Get().IsProfileSupported(mode, va_profile)) |
return false; |
TryToSetVADisplayAttributeToLocalGPU(); |
+ VAEntrypoint entrypoint = |
+ (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); |
+ std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode); |
base::AutoLock auto_lock(va_lock_); |
VAStatus va_res = vaCreateConfig(va_display_, |
va_profile, |
@@ -573,13 +655,13 @@ bool VaapiWrapper::SubmitVAEncMiscParamBuffer( |
void VaapiWrapper::DestroyPendingBuffers() { |
base::AutoLock auto_lock(va_lock_); |
- for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { |
- VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); |
+ for (const auto& pending_va_buf : pending_va_bufs_) { |
+ VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_buf); |
VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
} |
- for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { |
- VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); |
+ for (const auto& pending_slice_buf : pending_slice_bufs_) { |
+ VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_buf); |
VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
} |
@@ -959,4 +1041,30 @@ bool VaapiWrapper::PostSandboxInitialization() { |
return InitializeStubs(paths); |
} |
+VaapiWrapper::LazyProfileInfos::LazyProfileInfos() { |
+ for (size_t i = 0; i < kCodecModeMax; ++i) { |
Pawel Osciak
2015/03/08 00:58:24
Ok, but let's at least do static_assert(arraysize(
henryhsu
2015/03/09 03:56:52
Done.
|
+ supported_profiles_[i] = |
+ VaapiWrapper::GetSupportedProfileInfosForCodecMode( |
+ static_cast<CodecMode>(i)); |
+ } |
+} |
+ |
+VaapiWrapper::LazyProfileInfos::~LazyProfileInfos() { |
+} |
+ |
+std::vector<VaapiWrapper::ProfileInfo> |
+VaapiWrapper::LazyProfileInfos::GetSupportedProfileInfosForCodecMode( |
+ CodecMode mode) { |
+ return supported_profiles_[mode]; |
+} |
+ |
+bool VaapiWrapper::LazyProfileInfos::IsProfileSupported( |
+ CodecMode mode, VAProfile va_profile) { |
+ for (const auto& profile : supported_profiles_[mode]) { |
+ if (profile.va_profile == va_profile) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
} // namespace content |