Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: content/common/gpu/media/vaapi_wrapper.cc

Issue 1882373004: Migrate content/common/gpu/media code to media/gpu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix several more bot-identified build issues Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/common/gpu/media/vaapi_wrapper.h"
6
7 #include <dlfcn.h>
8 #include <string.h>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "base/sys_info.h"
16 #include "build/build_config.h"
17 // Auto-generated for dlopen libva libraries
18 #include "content/common/gpu/media/va_stubs.h"
19 #include "content/common/gpu/media/vaapi_picture.h"
20 #include "third_party/libyuv/include/libyuv.h"
21 #include "ui/gl/gl_bindings.h"
22 #if defined(USE_X11)
23 #include "ui/gfx/x/x11_types.h"
24 #elif defined(USE_OZONE)
25 #include "third_party/libva/va/drm/va_drm.h"
26 #include "third_party/libva/va/va_drmcommon.h"
27 #include "ui/ozone/public/ozone_platform.h"
28 #include "ui/ozone/public/surface_factory_ozone.h"
29 #endif // USE_X11
30
31 using content_common_gpu_media::kModuleVa;
32 #if defined(USE_X11)
33 using content_common_gpu_media::kModuleVa_x11;
34 #elif defined(USE_OZONE)
35 using content_common_gpu_media::kModuleVa_drm;
36 #endif // USE_X11
37 using content_common_gpu_media::InitializeStubs;
38 using content_common_gpu_media::StubPathMap;
39
40 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \
41 do { \
42 LOG(ERROR) << err_msg \
43 << " VA error: " << vaErrorStr(va_error); \
44 report_error_to_uma_cb_.Run(); \
45 } while (0)
46
47 #define VA_LOG_ON_ERROR(va_error, err_msg) \
48 do { \
49 if ((va_error) != VA_STATUS_SUCCESS) \
50 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
51 } while (0)
52
53 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \
54 do { \
55 if ((va_error) != VA_STATUS_SUCCESS) { \
56 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
57 return (ret); \
58 } \
59 } while (0)
60
61 #if defined(USE_OZONE)
62 namespace {
63
64 uint32_t BufferFormatToVAFourCC(gfx::BufferFormat fmt) {
65 switch (fmt) {
66 case gfx::BufferFormat::BGRX_8888:
67 return VA_FOURCC_BGRX;
68 case gfx::BufferFormat::UYVY_422:
69 return VA_FOURCC_UYVY;
70 default:
71 NOTREACHED();
72 return 0;
73 }
74 }
75
76 uint32_t BufferFormatToVARTFormat(gfx::BufferFormat fmt) {
77 switch (fmt) {
78 case gfx::BufferFormat::UYVY_422:
79 return VA_RT_FORMAT_YUV422;
80 case gfx::BufferFormat::BGRX_8888:
81 return VA_RT_FORMAT_RGB32;
82 default:
83 NOTREACHED();
84 return 0;
85 }
86 }
87
88 } // namespace
89 #endif
90
91 namespace content {
92
93 // Maximum framerate of encoded profile. This value is an arbitary limit
94 // and not taken from HW documentation.
95 const int kMaxEncoderFramerate = 30;
96
97 base::LazyInstance<VaapiWrapper::VADisplayState>
98 VaapiWrapper::va_display_state_ = LAZY_INSTANCE_INITIALIZER;
99
100 base::LazyInstance<VaapiWrapper::LazyProfileInfos>
101 VaapiWrapper::profile_infos_ = LAZY_INSTANCE_INITIALIZER;
102
103 // Config attributes common for both encode and decode.
104 static const VAConfigAttrib kCommonVAConfigAttribs[] = {
105 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420},
106 };
107
108 // Attributes required for encode.
109 static const VAConfigAttrib kEncodeVAConfigAttribs[] = {
110 {VAConfigAttribRateControl, VA_RC_CBR},
111 {VAConfigAttribEncPackedHeaders,
112 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE},
113 };
114
115 struct ProfileMap {
116 media::VideoCodecProfile profile;
117 VAProfile va_profile;
118 };
119
120 // A map between VideoCodecProfile and VAProfile.
121 static const ProfileMap kProfileMap[] = {
122 {media::H264PROFILE_BASELINE, VAProfileH264Baseline},
123 {media::H264PROFILE_MAIN, VAProfileH264Main},
124 // TODO(posciak): See if we can/want support other variants of
125 // media::H264PROFILE_HIGH*.
126 {media::H264PROFILE_HIGH, VAProfileH264High},
127 {media::VP8PROFILE_ANY, VAProfileVP8Version0_3},
128 // TODO(servolk): Need to add VP9 profiles 1,2,3 here after rolling
129 // third_party/libva to 1.7. crbug.com/598118
130 {media::VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
131 };
132
133 static std::vector<VAConfigAttrib> GetRequiredAttribs(
134 VaapiWrapper::CodecMode mode) {
135 std::vector<VAConfigAttrib> required_attribs;
136 required_attribs.insert(
137 required_attribs.end(),
138 kCommonVAConfigAttribs,
139 kCommonVAConfigAttribs + arraysize(kCommonVAConfigAttribs));
140 if (mode == VaapiWrapper::kEncode) {
141 required_attribs.insert(
142 required_attribs.end(),
143 kEncodeVAConfigAttribs,
144 kEncodeVAConfigAttribs + arraysize(kEncodeVAConfigAttribs));
145 }
146 return required_attribs;
147 }
148
149 VASurface::VASurface(VASurfaceID va_surface_id,
150 const gfx::Size& size,
151 unsigned int format,
152 const ReleaseCB& release_cb)
153 : va_surface_id_(va_surface_id),
154 size_(size),
155 format_(format),
156 release_cb_(release_cb) {
157 DCHECK(!release_cb_.is_null());
158 }
159
160 VASurface::~VASurface() {
161 release_cb_.Run(va_surface_id_);
162 }
163
164 VaapiWrapper::VaapiWrapper()
165 : va_surface_format_(0),
166 va_display_(NULL),
167 va_config_id_(VA_INVALID_ID),
168 va_context_id_(VA_INVALID_ID),
169 va_vpp_config_id_(VA_INVALID_ID),
170 va_vpp_context_id_(VA_INVALID_ID),
171 va_vpp_buffer_id_(VA_INVALID_ID) {
172 va_lock_ = va_display_state_.Get().va_lock();
173 }
174
175 VaapiWrapper::~VaapiWrapper() {
176 DestroyPendingBuffers();
177 DestroyCodedBuffers();
178 DestroySurfaces();
179 DeinitializeVpp();
180 Deinitialize();
181 }
182
183 // static
184 scoped_refptr<VaapiWrapper> VaapiWrapper::Create(
185 CodecMode mode,
186 VAProfile va_profile,
187 const base::Closure& report_error_to_uma_cb) {
188 if (!profile_infos_.Get().IsProfileSupported(mode, va_profile)) {
189 DVLOG(1) << "Unsupported va_profile: " << va_profile;
190 return nullptr;
191 }
192
193 scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
194 if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) {
195 if (vaapi_wrapper->Initialize(mode, va_profile))
196 return vaapi_wrapper;
197 }
198 LOG(ERROR) << "Failed to create VaapiWrapper for va_profile: " << va_profile;
199 return nullptr;
200 }
201
202 // static
203 scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec(
204 CodecMode mode,
205 media::VideoCodecProfile profile,
206 const base::Closure& report_error_to_uma_cb) {
207 VAProfile va_profile = ProfileToVAProfile(profile, mode);
208 scoped_refptr<VaapiWrapper> vaapi_wrapper =
209 Create(mode, va_profile, report_error_to_uma_cb);
210 return vaapi_wrapper;
211 }
212
213 // static
214 media::VideoEncodeAccelerator::SupportedProfiles
215 VaapiWrapper::GetSupportedEncodeProfiles() {
216 media::VideoEncodeAccelerator::SupportedProfiles profiles;
217 std::vector<ProfileInfo> encode_profile_infos =
218 profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kEncode);
219
220 for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
221 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kEncode);
222 if (va_profile == VAProfileNone)
223 continue;
224 for (const auto& profile_info : encode_profile_infos) {
225 if (profile_info.va_profile == va_profile) {
226 media::VideoEncodeAccelerator::SupportedProfile profile;
227 profile.profile = kProfileMap[i].profile;
228 profile.max_resolution = profile_info.max_resolution;
229 profile.max_framerate_numerator = kMaxEncoderFramerate;
230 profile.max_framerate_denominator = 1;
231 profiles.push_back(profile);
232 break;
233 }
234 }
235 }
236 return profiles;
237 }
238
239 // static
240 media::VideoDecodeAccelerator::SupportedProfiles
241 VaapiWrapper::GetSupportedDecodeProfiles() {
242 media::VideoDecodeAccelerator::SupportedProfiles profiles;
243 std::vector<ProfileInfo> decode_profile_infos =
244 profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kDecode);
245
246 for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
247 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kDecode);
248 if (va_profile == VAProfileNone)
249 continue;
250 for (const auto& profile_info : decode_profile_infos) {
251 if (profile_info.va_profile == va_profile) {
252 media::VideoDecodeAccelerator::SupportedProfile profile;
253 profile.profile = kProfileMap[i].profile;
254 profile.max_resolution = profile_info.max_resolution;
255 profile.min_resolution.SetSize(16, 16);
256 profiles.push_back(profile);
257 break;
258 }
259 }
260 }
261 return profiles;
262 }
263
264 // static
265 bool VaapiWrapper::IsJpegDecodeSupported() {
266 return profile_infos_.Get().IsProfileSupported(kDecode,
267 VAProfileJPEGBaseline);
268 }
269
270 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() {
271 base::AutoLock auto_lock(*va_lock_);
272 VADisplayAttribute item = {VADisplayAttribRenderMode,
273 1, // At least support '_LOCAL_OVERLAY'.
274 -1, // The maximum possible support 'ALL'.
275 VA_RENDER_MODE_LOCAL_GPU,
276 VA_DISPLAY_ATTRIB_SETTABLE};
277
278 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1);
279 if (va_res != VA_STATUS_SUCCESS)
280 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default.";
281 }
282
283 // static
284 VAProfile VaapiWrapper::ProfileToVAProfile(
285 media::VideoCodecProfile profile, CodecMode mode) {
286 VAProfile va_profile = VAProfileNone;
287 for (size_t i = 0; i < arraysize(kProfileMap); ++i) {
288 if (kProfileMap[i].profile == profile) {
289 va_profile = kProfileMap[i].va_profile;
290 break;
291 }
292 }
293 if (!profile_infos_.Get().IsProfileSupported(mode, va_profile) &&
294 va_profile == VAProfileH264Baseline) {
295 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips
296 // the information whether the profile is constrained or not, so we have no
297 // way to know here. Try for baseline first, but if it is not supported,
298 // try constrained baseline and hope this is what it actually is
299 // (which in practice is true for a great majority of cases).
300 if (profile_infos_.Get().IsProfileSupported(
301 mode, VAProfileH264ConstrainedBaseline)) {
302 va_profile = VAProfileH264ConstrainedBaseline;
303 DVLOG(1) << "Fall back to constrained baseline profile.";
304 }
305 }
306 return va_profile;
307 }
308
309 std::vector<VaapiWrapper::ProfileInfo>
310 VaapiWrapper::GetSupportedProfileInfosForCodecModeInternal(CodecMode mode) {
311 std::vector<ProfileInfo> supported_profile_infos;
312 std::vector<VAProfile> va_profiles;
313 if (!GetSupportedVaProfiles(&va_profiles))
314 return supported_profile_infos;
315
316 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
317 VAEntrypoint entrypoint =
318 (mode == kEncode ? VAEntrypointEncSlice: VAEntrypointVLD);
319
320 base::AutoLock auto_lock(*va_lock_);
321 for (const auto& va_profile : va_profiles) {
322 if (!IsEntrypointSupported_Locked(va_profile, entrypoint))
323 continue;
324 if (!AreAttribsSupported_Locked(va_profile, entrypoint, required_attribs))
325 continue;
326 ProfileInfo profile_info;
327 if (!GetMaxResolution_Locked(va_profile,
328 entrypoint,
329 required_attribs,
330 &profile_info.max_resolution)) {
331 LOG(ERROR) << "GetMaxResolution failed for va_profile " << va_profile
332 << " and entrypoint " << entrypoint;
333 continue;
334 }
335 profile_info.va_profile = va_profile;
336 supported_profile_infos.push_back(profile_info);
337 }
338 return supported_profile_infos;
339 }
340
341 bool VaapiWrapper::VaInitialize(const base::Closure& report_error_to_uma_cb) {
342 static bool vaapi_functions_initialized = PostSandboxInitialization();
343 if (!vaapi_functions_initialized) {
344 bool running_on_chromeos = false;
345 #if defined(OS_CHROMEOS)
346 // When chrome runs on linux with chromeos=1, do not log error message
347 // without VAAPI libraries.
348 running_on_chromeos = base::SysInfo::IsRunningOnChromeOS();
349 #endif
350 static const char kErrorMsg[] = "Failed to initialize VAAPI libs";
351 if (running_on_chromeos)
352 LOG(ERROR) << kErrorMsg;
353 else
354 DVLOG(1) << kErrorMsg;
355 return false;
356 }
357
358 report_error_to_uma_cb_ = report_error_to_uma_cb;
359
360 base::AutoLock auto_lock(*va_lock_);
361
362 VADisplayState* va_display_state = &va_display_state_.Get();
363 if (!va_display_state) {
364 LOG(ERROR) << "Failed to allocate VA display state";
365 return false;
366 }
367
368 if (!va_display_state->Initialize())
369 return false;
370
371 va_display_ = va_display_state->va_display();
372 return true;
373 }
374
375 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) {
376 base::AutoLock auto_lock(*va_lock_);
377 // Query the driver for supported profiles.
378 int max_profiles = vaMaxNumProfiles(va_display_);
379 std::vector<VAProfile> supported_profiles(
380 base::checked_cast<size_t>(max_profiles));
381
382 int num_supported_profiles;
383 VAStatus va_res = vaQueryConfigProfiles(
384 va_display_, &supported_profiles[0], &num_supported_profiles);
385 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false);
386 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) {
387 LOG(ERROR) << "vaQueryConfigProfiles returned: " << num_supported_profiles;
388 return false;
389 }
390
391 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles));
392 *profiles = supported_profiles;
393 return true;
394 }
395
396 bool VaapiWrapper::IsEntrypointSupported_Locked(VAProfile va_profile,
397 VAEntrypoint entrypoint) {
398 va_lock_->AssertAcquired();
399 // Query the driver for supported entrypoints.
400 int max_entrypoints = vaMaxNumEntrypoints(va_display_);
401 std::vector<VAEntrypoint> supported_entrypoints(
402 base::checked_cast<size_t>(max_entrypoints));
403
404 int num_supported_entrypoints;
405 VAStatus va_res = vaQueryConfigEntrypoints(va_display_,
406 va_profile,
407 &supported_entrypoints[0],
408 &num_supported_entrypoints);
409 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false);
410 if (num_supported_entrypoints < 0 ||
411 num_supported_entrypoints > max_entrypoints) {
412 LOG(ERROR) << "vaQueryConfigEntrypoints returned: "
413 << num_supported_entrypoints;
414 return false;
415 }
416
417 if (std::find(supported_entrypoints.begin(),
418 supported_entrypoints.end(),
419 entrypoint) == supported_entrypoints.end()) {
420 DVLOG(1) << "Unsupported entrypoint";
421 return false;
422 }
423 return true;
424 }
425
426 bool VaapiWrapper::AreAttribsSupported_Locked(
427 VAProfile va_profile,
428 VAEntrypoint entrypoint,
429 const std::vector<VAConfigAttrib>& required_attribs) {
430 va_lock_->AssertAcquired();
431 // Query the driver for required attributes.
432 std::vector<VAConfigAttrib> attribs = required_attribs;
433 for (size_t i = 0; i < required_attribs.size(); ++i)
434 attribs[i].value = 0;
435
436 VAStatus va_res = vaGetConfigAttributes(
437 va_display_, va_profile, entrypoint, &attribs[0], attribs.size());
438 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
439
440 for (size_t i = 0; i < required_attribs.size(); ++i) {
441 if (attribs[i].type != required_attribs[i].type ||
442 (attribs[i].value & required_attribs[i].value) !=
443 required_attribs[i].value) {
444 DVLOG(1) << "Unsupported value " << required_attribs[i].value
445 << " for attribute type " << required_attribs[i].type;
446 return false;
447 }
448 }
449 return true;
450 }
451
452 bool VaapiWrapper::GetMaxResolution_Locked(
453 VAProfile va_profile,
454 VAEntrypoint entrypoint,
455 std::vector<VAConfigAttrib>& required_attribs,
456 gfx::Size* resolution) {
457 va_lock_->AssertAcquired();
458 VAConfigID va_config_id;
459 VAStatus va_res = vaCreateConfig(
460 va_display_,
461 va_profile,
462 entrypoint,
463 &required_attribs[0],
464 required_attribs.size(),
465 &va_config_id);
466 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
467
468 // Calls vaQuerySurfaceAttributes twice. The first time is to get the number
469 // of attributes to prepare the space and the second time is to get all
470 // attributes.
471 unsigned int num_attribs;
472 va_res = vaQuerySurfaceAttributes(
473 va_display_, va_config_id, nullptr, &num_attribs);
474 VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false);
475 if (!num_attribs)
476 return false;
477
478 std::vector<VASurfaceAttrib> attrib_list(
479 base::checked_cast<size_t>(num_attribs));
480
481 va_res = vaQuerySurfaceAttributes(
482 va_display_, va_config_id, &attrib_list[0], &num_attribs);
483 VA_SUCCESS_OR_RETURN(va_res, "vaQuerySurfaceAttributes failed", false);
484
485 resolution->SetSize(0, 0);
486 for (const auto& attrib : attrib_list) {
487 if (attrib.type == VASurfaceAttribMaxWidth)
488 resolution->set_width(attrib.value.value.i);
489 else if (attrib.type == VASurfaceAttribMaxHeight)
490 resolution->set_height(attrib.value.value.i);
491 }
492 if (resolution->IsEmpty()) {
493 LOG(ERROR) << "Codec resolution " << resolution->ToString()
494 << " cannot be zero.";
495 return false;
496 }
497 return true;
498 }
499
500 bool VaapiWrapper::Initialize(CodecMode mode, VAProfile va_profile) {
501 TryToSetVADisplayAttributeToLocalGPU();
502
503 VAEntrypoint entrypoint =
504 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD);
505 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
506 base::AutoLock auto_lock(*va_lock_);
507 VAStatus va_res = vaCreateConfig(va_display_,
508 va_profile,
509 entrypoint,
510 &required_attribs[0],
511 required_attribs.size(),
512 &va_config_id_);
513 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
514
515 return true;
516 }
517
518 void VaapiWrapper::Deinitialize() {
519 base::AutoLock auto_lock(*va_lock_);
520
521 if (va_config_id_ != VA_INVALID_ID) {
522 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_);
523 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
524 }
525
526 VADisplayState* va_display_state = &va_display_state_.Get();
527 if (va_display_state) {
528 VAStatus va_res = VA_STATUS_SUCCESS;
529 va_display_state->Deinitialize(&va_res);
530 VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
531 }
532
533 va_config_id_ = VA_INVALID_ID;
534 va_display_ = NULL;
535 }
536
537 bool VaapiWrapper::CreateSurfaces(unsigned int va_format,
538 const gfx::Size& size,
539 size_t num_surfaces,
540 std::vector<VASurfaceID>* va_surfaces) {
541 base::AutoLock auto_lock(*va_lock_);
542 DVLOG(2) << "Creating " << num_surfaces << " surfaces";
543
544 DCHECK(va_surfaces->empty());
545 DCHECK(va_surface_ids_.empty());
546 DCHECK_EQ(va_surface_format_, 0u);
547 va_surface_ids_.resize(num_surfaces);
548
549 // Allocate surfaces in driver.
550 VAStatus va_res =
551 vaCreateSurfaces(va_display_, va_format, size.width(), size.height(),
552 &va_surface_ids_[0], va_surface_ids_.size(), NULL, 0);
553
554 VA_LOG_ON_ERROR(va_res, "vaCreateSurfaces failed");
555 if (va_res != VA_STATUS_SUCCESS) {
556 va_surface_ids_.clear();
557 return false;
558 }
559
560 // And create a context associated with them.
561 va_res = vaCreateContext(va_display_, va_config_id_,
562 size.width(), size.height(), VA_PROGRESSIVE,
563 &va_surface_ids_[0], va_surface_ids_.size(),
564 &va_context_id_);
565
566 VA_LOG_ON_ERROR(va_res, "vaCreateContext failed");
567 if (va_res != VA_STATUS_SUCCESS) {
568 DestroySurfaces();
569 return false;
570 }
571
572 *va_surfaces = va_surface_ids_;
573 va_surface_format_ = va_format;
574 return true;
575 }
576
577 void VaapiWrapper::DestroySurfaces() {
578 base::AutoLock auto_lock(*va_lock_);
579 DVLOG(2) << "Destroying " << va_surface_ids_.size() << " surfaces";
580
581 if (va_context_id_ != VA_INVALID_ID) {
582 VAStatus va_res = vaDestroyContext(va_display_, va_context_id_);
583 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed");
584 }
585
586 if (!va_surface_ids_.empty()) {
587 VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_ids_[0],
588 va_surface_ids_.size());
589 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed");
590 }
591
592 va_surface_ids_.clear();
593 va_context_id_ = VA_INVALID_ID;
594 va_surface_format_ = 0;
595 }
596
597 scoped_refptr<VASurface> VaapiWrapper::CreateUnownedSurface(
598 unsigned int va_format,
599 const gfx::Size& size,
600 const std::vector<VASurfaceAttrib>& va_attribs) {
601 base::AutoLock auto_lock(*va_lock_);
602
603 std::vector<VASurfaceAttrib> attribs(va_attribs);
604 VASurfaceID va_surface_id;
605 VAStatus va_res =
606 vaCreateSurfaces(va_display_, va_format, size.width(), size.height(),
607 &va_surface_id, 1, &attribs[0], attribs.size());
608
609 scoped_refptr<VASurface> va_surface;
610 VA_SUCCESS_OR_RETURN(va_res, "Failed to create unowned VASurface",
611 va_surface);
612
613 // This is safe to use Unretained() here, because the VDA takes care
614 // of the destruction order. All the surfaces will be destroyed
615 // before VaapiWrapper.
616 va_surface = new VASurface(
617 va_surface_id, size, va_format,
618 base::Bind(&VaapiWrapper::DestroyUnownedSurface, base::Unretained(this)));
619
620 return va_surface;
621 }
622
623 #if defined(USE_OZONE)
624 scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
625 const scoped_refptr<ui::NativePixmap>& pixmap) {
626 // Get the dmabuf of the created buffer.
627 int dmabuf_fd = pixmap->GetDmaBufFd();
628 if (dmabuf_fd < 0) {
629 LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
630 return nullptr;
631 }
632 int dmabuf_pitch = pixmap->GetDmaBufPitch();
633 gfx::Size pixmap_size = pixmap->GetBufferSize();
634
635 // Create a VASurface out of the created buffer using the dmabuf.
636 VASurfaceAttribExternalBuffers va_attrib_extbuf;
637 memset(&va_attrib_extbuf, 0, sizeof(va_attrib_extbuf));
638 va_attrib_extbuf.pixel_format =
639 BufferFormatToVAFourCC(pixmap->GetBufferFormat());
640 va_attrib_extbuf.width = pixmap_size.width();
641 va_attrib_extbuf.height = pixmap_size.height();
642 va_attrib_extbuf.data_size = pixmap_size.height() * dmabuf_pitch;
643 va_attrib_extbuf.num_planes = 1;
644 va_attrib_extbuf.pitches[0] = dmabuf_pitch;
645 va_attrib_extbuf.offsets[0] = 0;
646 va_attrib_extbuf.buffers = reinterpret_cast<unsigned long*>(&dmabuf_fd);
647 va_attrib_extbuf.num_buffers = 1;
648 va_attrib_extbuf.flags = 0;
649 va_attrib_extbuf.private_data = NULL;
650
651 std::vector<VASurfaceAttrib> va_attribs;
652 va_attribs.resize(2);
653
654 va_attribs[0].type = VASurfaceAttribMemoryType;
655 va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
656 va_attribs[0].value.type = VAGenericValueTypeInteger;
657 va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
658
659 va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
660 va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
661 va_attribs[1].value.type = VAGenericValueTypePointer;
662 va_attribs[1].value.value.p = &va_attrib_extbuf;
663
664 scoped_refptr<VASurface> va_surface =
665 CreateUnownedSurface(BufferFormatToVARTFormat(pixmap->GetBufferFormat()),
666 pixmap_size, va_attribs);
667 if (!va_surface) {
668 LOG(ERROR) << "Failed to create VASurface for an Ozone NativePixmap";
669 return nullptr;
670 }
671
672 return va_surface;
673 }
674
675 bool VaapiWrapper::ProcessPixmap(
676 const scoped_refptr<ui::NativePixmap>& source_pixmap,
677 scoped_refptr<ui::NativePixmap> target_pixmap) {
678 scoped_refptr<VASurface> va_surface = CreateVASurfaceForPixmap(source_pixmap);
679 if (!va_surface) {
680 LOG(ERROR) << "Failed creating VA Surface for source_pixmap";
681 return false;
682 }
683
684 scoped_refptr<VASurface> processed_va_surface =
685 CreateVASurfaceForPixmap(target_pixmap);
686 if (!processed_va_surface) {
687 LOG(ERROR) << "Failed creating processed VA Surface for pixmap";
688 return false;
689 }
690
691 if (!BlitSurface(va_surface, processed_va_surface)) {
692 LOG(ERROR) << "Failed scaling NativePixmap";
693 return false;
694 }
695
696 return true;
697 }
698
699 #endif
700
701 void VaapiWrapper::DestroyUnownedSurface(VASurfaceID va_surface_id) {
702 base::AutoLock auto_lock(*va_lock_);
703
704 VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_id, 1);
705 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces on surface failed");
706 }
707
708 bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
709 size_t size,
710 void* buffer) {
711 base::AutoLock auto_lock(*va_lock_);
712
713 VABufferID buffer_id;
714 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_,
715 va_buffer_type, size,
716 1, buffer, &buffer_id);
717 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
718
719 switch (va_buffer_type) {
720 case VASliceParameterBufferType:
721 case VASliceDataBufferType:
722 case VAEncSliceParameterBufferType:
723 pending_slice_bufs_.push_back(buffer_id);
724 break;
725
726 default:
727 pending_va_bufs_.push_back(buffer_id);
728 break;
729 }
730
731 return true;
732 }
733
734 bool VaapiWrapper::SubmitVAEncMiscParamBuffer(
735 VAEncMiscParameterType misc_param_type,
736 size_t size,
737 void* buffer) {
738 base::AutoLock auto_lock(*va_lock_);
739
740 VABufferID buffer_id;
741 VAStatus va_res = vaCreateBuffer(va_display_,
742 va_context_id_,
743 VAEncMiscParameterBufferType,
744 sizeof(VAEncMiscParameterBuffer) + size,
745 1,
746 NULL,
747 &buffer_id);
748 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
749
750 void* data_ptr = NULL;
751 va_res = vaMapBuffer(va_display_, buffer_id, &data_ptr);
752 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
753 if (va_res != VA_STATUS_SUCCESS) {
754 vaDestroyBuffer(va_display_, buffer_id);
755 return false;
756 }
757
758 DCHECK(data_ptr);
759
760 VAEncMiscParameterBuffer* misc_param =
761 reinterpret_cast<VAEncMiscParameterBuffer*>(data_ptr);
762 misc_param->type = misc_param_type;
763 memcpy(misc_param->data, buffer, size);
764 va_res = vaUnmapBuffer(va_display_, buffer_id);
765 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
766
767 pending_va_bufs_.push_back(buffer_id);
768 return true;
769 }
770
771 void VaapiWrapper::DestroyPendingBuffers() {
772 base::AutoLock auto_lock(*va_lock_);
773
774 for (const auto& pending_va_buf : pending_va_bufs_) {
775 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_buf);
776 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
777 }
778
779 for (const auto& pending_slice_buf : pending_slice_bufs_) {
780 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_buf);
781 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
782 }
783
784 pending_va_bufs_.clear();
785 pending_slice_bufs_.clear();
786 }
787
788 bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) {
789 base::AutoLock auto_lock(*va_lock_);
790 VAStatus va_res = vaCreateBuffer(va_display_,
791 va_context_id_,
792 VAEncCodedBufferType,
793 size,
794 1,
795 NULL,
796 buffer_id);
797 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a coded buffer", false);
798
799 const auto is_new_entry = coded_buffers_.insert(*buffer_id).second;
800 DCHECK(is_new_entry);
801 return true;
802 }
803
804 void VaapiWrapper::DestroyCodedBuffers() {
805 base::AutoLock auto_lock(*va_lock_);
806
807 for (std::set<VABufferID>::const_iterator iter = coded_buffers_.begin();
808 iter != coded_buffers_.end();
809 ++iter) {
810 VAStatus va_res = vaDestroyBuffer(va_display_, *iter);
811 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
812 }
813
814 coded_buffers_.clear();
815 }
816
817 bool VaapiWrapper::Execute(VASurfaceID va_surface_id) {
818 base::AutoLock auto_lock(*va_lock_);
819
820 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
821 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
822 DVLOG(4) << "Target VA surface " << va_surface_id;
823
824 // Get ready to execute for given surface.
825 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_,
826 va_surface_id);
827 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false);
828
829 if (pending_va_bufs_.size() > 0) {
830 // Commit parameter and slice buffers.
831 va_res = vaRenderPicture(va_display_,
832 va_context_id_,
833 &pending_va_bufs_[0],
834 pending_va_bufs_.size());
835 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false);
836 }
837
838 if (pending_slice_bufs_.size() > 0) {
839 va_res = vaRenderPicture(va_display_,
840 va_context_id_,
841 &pending_slice_bufs_[0],
842 pending_slice_bufs_.size());
843 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false);
844 }
845
846 // Instruct HW codec to start processing committed buffers.
847 // Does not block and the job is not finished after this returns.
848 va_res = vaEndPicture(va_display_, va_context_id_);
849 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false);
850
851 return true;
852 }
853
854 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
855 bool result = Execute(va_surface_id);
856 DestroyPendingBuffers();
857 return result;
858 }
859
860 #if defined(USE_X11)
861 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
862 Pixmap x_pixmap,
863 gfx::Size dest_size) {
864 base::AutoLock auto_lock(*va_lock_);
865
866 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
867 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
868
869 // Put the data into an X Pixmap.
870 va_res = vaPutSurface(va_display_,
871 va_surface_id,
872 x_pixmap,
873 0, 0, dest_size.width(), dest_size.height(),
874 0, 0, dest_size.width(), dest_size.height(),
875 NULL, 0, 0);
876 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false);
877 return true;
878 }
879 #endif // USE_X11
880
881 bool VaapiWrapper::GetDerivedVaImage(VASurfaceID va_surface_id,
882 VAImage* image,
883 void** mem) {
884 base::AutoLock auto_lock(*va_lock_);
885
886 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
887 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
888
889 // Derive a VAImage from the VASurface
890 va_res = vaDeriveImage(va_display_, va_surface_id, image);
891 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed");
892 if (va_res != VA_STATUS_SUCCESS)
893 return false;
894
895 // Map the VAImage into memory
896 va_res = vaMapBuffer(va_display_, image->buf, mem);
897 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
898 if (va_res == VA_STATUS_SUCCESS)
899 return true;
900
901 va_res = vaDestroyImage(va_display_, image->image_id);
902 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
903
904 return false;
905 }
906
907 bool VaapiWrapper::GetVaImage(VASurfaceID va_surface_id,
908 VAImageFormat* format,
909 const gfx::Size& size,
910 VAImage* image,
911 void** mem) {
912 base::AutoLock auto_lock(*va_lock_);
913
914 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
915 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
916
917 va_res =
918 vaCreateImage(va_display_, format, size.width(), size.height(), image);
919 VA_SUCCESS_OR_RETURN(va_res, "vaCreateImage failed", false);
920
921 va_res = vaGetImage(va_display_, va_surface_id, 0, 0, size.width(),
922 size.height(), image->image_id);
923 VA_LOG_ON_ERROR(va_res, "vaGetImage failed");
924
925 if (va_res == VA_STATUS_SUCCESS) {
926 // Map the VAImage into memory
927 va_res = vaMapBuffer(va_display_, image->buf, mem);
928 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
929 }
930
931 if (va_res != VA_STATUS_SUCCESS) {
932 va_res = vaDestroyImage(va_display_, image->image_id);
933 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
934 return false;
935 }
936
937 return true;
938 }
939
940 void VaapiWrapper::ReturnVaImage(VAImage* image) {
941 base::AutoLock auto_lock(*va_lock_);
942
943 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf);
944 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
945
946 va_res = vaDestroyImage(va_display_, image->image_id);
947 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
948 }
949
950 static void DestroyVAImage(VADisplay va_display, VAImage image) {
951 if (image.image_id != VA_INVALID_ID)
952 vaDestroyImage(va_display, image.image_id);
953 }
954
955 bool VaapiWrapper::UploadVideoFrameToSurface(
956 const scoped_refptr<media::VideoFrame>& frame,
957 VASurfaceID va_surface_id) {
958 base::AutoLock auto_lock(*va_lock_);
959
960 VAImage image;
961 VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image);
962 VA_SUCCESS_OR_RETURN(va_res, "vaDeriveImage failed", false);
963 base::ScopedClosureRunner vaimage_deleter(
964 base::Bind(&DestroyVAImage, va_display_, image));
965
966 if (image.format.fourcc != VA_FOURCC_NV12) {
967 LOG(ERROR) << "Unsupported image format: " << image.format.fourcc;
968 return false;
969 }
970
971 if (gfx::Rect(image.width, image.height) < gfx::Rect(frame->coded_size())) {
972 LOG(ERROR) << "Buffer too small to fit the frame.";
973 return false;
974 }
975
976 void* image_ptr = NULL;
977 va_res = vaMapBuffer(va_display_, image.buf, &image_ptr);
978 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false);
979 DCHECK(image_ptr);
980
981 int ret = 0;
982 {
983 base::AutoUnlock auto_unlock(*va_lock_);
984 ret = libyuv::I420ToNV12(
985 frame->data(media::VideoFrame::kYPlane),
986 frame->stride(media::VideoFrame::kYPlane),
987 frame->data(media::VideoFrame::kUPlane),
988 frame->stride(media::VideoFrame::kUPlane),
989 frame->data(media::VideoFrame::kVPlane),
990 frame->stride(media::VideoFrame::kVPlane),
991 static_cast<uint8_t*>(image_ptr) + image.offsets[0], image.pitches[0],
992 static_cast<uint8_t*>(image_ptr) + image.offsets[1], image.pitches[1],
993 image.width, image.height);
994 }
995
996 va_res = vaUnmapBuffer(va_display_, image.buf);
997 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
998
999 return ret == 0;
1000 }
1001
1002 bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
1003 VASurfaceID sync_surface_id,
1004 uint8_t* target_ptr,
1005 size_t target_size,
1006 size_t* coded_data_size) {
1007 base::AutoLock auto_lock(*va_lock_);
1008
1009 VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id);
1010 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
1011
1012 VACodedBufferSegment* buffer_segment = NULL;
1013 va_res = vaMapBuffer(
1014 va_display_, buffer_id, reinterpret_cast<void**>(&buffer_segment));
1015 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false);
1016 DCHECK(target_ptr);
1017
1018 {
1019 base::AutoUnlock auto_unlock(*va_lock_);
1020 *coded_data_size = 0;
1021
1022 while (buffer_segment) {
1023 DCHECK(buffer_segment->buf);
1024
1025 if (buffer_segment->size > target_size) {
1026 LOG(ERROR) << "Insufficient output buffer size";
1027 break;
1028 }
1029
1030 memcpy(target_ptr, buffer_segment->buf, buffer_segment->size);
1031
1032 target_ptr += buffer_segment->size;
1033 *coded_data_size += buffer_segment->size;
1034 target_size -= buffer_segment->size;
1035
1036 buffer_segment =
1037 reinterpret_cast<VACodedBufferSegment*>(buffer_segment->next);
1038 }
1039 }
1040
1041 va_res = vaUnmapBuffer(va_display_, buffer_id);
1042 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
1043
1044 va_res = vaDestroyBuffer(va_display_, buffer_id);
1045 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
1046
1047 const auto was_found = coded_buffers_.erase(buffer_id);
1048 DCHECK(was_found);
1049
1050 return buffer_segment == NULL;
1051 }
1052
1053 bool VaapiWrapper::BlitSurface(
1054 const scoped_refptr<VASurface>& va_surface_src,
1055 const scoped_refptr<VASurface>& va_surface_dest) {
1056 base::AutoLock auto_lock(*va_lock_);
1057
1058 // Initialize the post processing engine if not already done.
1059 if (va_vpp_buffer_id_ == VA_INVALID_ID) {
1060 if (!InitializeVpp_Locked())
1061 return false;
1062 }
1063
1064 VAProcPipelineParameterBuffer* pipeline_param;
1065 VA_SUCCESS_OR_RETURN(vaMapBuffer(va_display_, va_vpp_buffer_id_,
1066 reinterpret_cast<void**>(&pipeline_param)),
1067 "Couldn't map vpp buffer", false);
1068
1069 memset(pipeline_param, 0, sizeof *pipeline_param);
1070 const gfx::Size src_size = va_surface_src->size();
1071 const gfx::Size dest_size = va_surface_dest->size();
1072
1073 VARectangle input_region;
1074 input_region.x = input_region.y = 0;
1075 input_region.width = src_size.width();
1076 input_region.height = src_size.height();
1077 pipeline_param->surface_region = &input_region;
1078 pipeline_param->surface = va_surface_src->id();
1079 pipeline_param->surface_color_standard = VAProcColorStandardNone;
1080
1081 VARectangle output_region;
1082 output_region.x = output_region.y = 0;
1083 output_region.width = dest_size.width();
1084 output_region.height = dest_size.height();
1085 pipeline_param->output_region = &output_region;
1086 pipeline_param->output_background_color = 0xff000000;
1087 pipeline_param->output_color_standard = VAProcColorStandardNone;
1088 pipeline_param->filter_flags = VA_FILTER_SCALING_HQ;
1089
1090 VA_SUCCESS_OR_RETURN(vaUnmapBuffer(va_display_, va_vpp_buffer_id_),
1091 "Couldn't unmap vpp buffer", false);
1092
1093 VA_SUCCESS_OR_RETURN(
1094 vaBeginPicture(va_display_, va_vpp_context_id_, va_surface_dest->id()),
1095 "Couldn't begin picture", false);
1096
1097 VA_SUCCESS_OR_RETURN(
1098 vaRenderPicture(va_display_, va_vpp_context_id_, &va_vpp_buffer_id_, 1),
1099 "Couldn't render picture", false);
1100
1101 VA_SUCCESS_OR_RETURN(vaEndPicture(va_display_, va_vpp_context_id_),
1102 "Couldn't end picture", false);
1103
1104 return true;
1105 }
1106
1107 bool VaapiWrapper::InitializeVpp_Locked() {
1108 va_lock_->AssertAcquired();
1109
1110 VA_SUCCESS_OR_RETURN(
1111 vaCreateConfig(va_display_, VAProfileNone, VAEntrypointVideoProc, NULL, 0,
1112 &va_vpp_config_id_),
1113 "Couldn't create config", false);
1114
1115 // The size of the picture for the context is irrelevant in the case
1116 // of the VPP, just passing 1x1.
1117 VA_SUCCESS_OR_RETURN(vaCreateContext(va_display_, va_vpp_config_id_, 1, 1, 0,
1118 NULL, 0, &va_vpp_context_id_),
1119 "Couldn't create context", false);
1120
1121 VA_SUCCESS_OR_RETURN(vaCreateBuffer(va_display_, va_vpp_context_id_,
1122 VAProcPipelineParameterBufferType,
1123 sizeof(VAProcPipelineParameterBuffer), 1,
1124 NULL, &va_vpp_buffer_id_),
1125 "Couldn't create buffer", false);
1126
1127 return true;
1128 }
1129
1130 void VaapiWrapper::DeinitializeVpp() {
1131 base::AutoLock auto_lock(*va_lock_);
1132
1133 if (va_vpp_buffer_id_ != VA_INVALID_ID) {
1134 vaDestroyBuffer(va_display_, va_vpp_buffer_id_);
1135 va_vpp_buffer_id_ = VA_INVALID_ID;
1136 }
1137 if (va_vpp_context_id_ != VA_INVALID_ID) {
1138 vaDestroyContext(va_display_, va_vpp_context_id_);
1139 va_vpp_context_id_ = VA_INVALID_ID;
1140 }
1141 if (va_vpp_config_id_ != VA_INVALID_ID) {
1142 vaDestroyConfig(va_display_, va_vpp_config_id_);
1143 va_vpp_config_id_ = VA_INVALID_ID;
1144 }
1145 }
1146
1147 // static
1148 void VaapiWrapper::PreSandboxInitialization() {
1149 #if defined(USE_OZONE)
1150 const char kDriRenderNode0Path[] = "/dev/dri/renderD128";
1151 base::File drm_file = base::File(
1152 base::FilePath::FromUTF8Unsafe(kDriRenderNode0Path),
1153 base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE);
1154 if (drm_file.IsValid())
1155 va_display_state_.Get().SetDrmFd(drm_file.GetPlatformFile());
1156 #endif
1157 }
1158
1159 // static
1160 bool VaapiWrapper::PostSandboxInitialization() {
1161 StubPathMap paths;
1162
1163 paths[kModuleVa].push_back("libva.so.1");
1164
1165 #if defined(USE_X11)
1166 paths[kModuleVa_x11].push_back("libva-x11.so.1");
1167 #elif defined(USE_OZONE)
1168 paths[kModuleVa_drm].push_back("libva-drm.so.1");
1169 #endif
1170
1171 return InitializeStubs(paths);
1172 }
1173
1174 VaapiWrapper::LazyProfileInfos::LazyProfileInfos() {
1175 static_assert(arraysize(supported_profiles_) == kCodecModeMax,
1176 "The array size of supported profile is incorrect.");
1177 scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
1178 if (!vaapi_wrapper->VaInitialize(base::Bind(&base::DoNothing)))
1179 return;
1180 for (size_t i = 0; i < kCodecModeMax; ++i) {
1181 supported_profiles_[i] =
1182 vaapi_wrapper->GetSupportedProfileInfosForCodecModeInternal(
1183 static_cast<CodecMode>(i));
1184 }
1185 }
1186
1187 VaapiWrapper::LazyProfileInfos::~LazyProfileInfos() {
1188 }
1189
1190 std::vector<VaapiWrapper::ProfileInfo>
1191 VaapiWrapper::LazyProfileInfos::GetSupportedProfileInfosForCodecMode(
1192 CodecMode mode) {
1193 return supported_profiles_[mode];
1194 }
1195
1196 bool VaapiWrapper::LazyProfileInfos::IsProfileSupported(
1197 CodecMode mode, VAProfile va_profile) {
1198 for (const auto& profile : supported_profiles_[mode]) {
1199 if (profile.va_profile == va_profile)
1200 return true;
1201 }
1202 return false;
1203 }
1204
1205 VaapiWrapper::VADisplayState::VADisplayState()
1206 : refcount_(0),
1207 va_display_(nullptr),
1208 major_version_(-1),
1209 minor_version_(-1),
1210 va_initialized_(false) {}
1211
1212 VaapiWrapper::VADisplayState::~VADisplayState() {}
1213
1214 bool VaapiWrapper::VADisplayState::Initialize() {
1215 va_lock_.AssertAcquired();
1216 if (refcount_++ == 0) {
1217 #if defined(USE_X11)
1218 va_display_ = vaGetDisplay(gfx::GetXDisplay());
1219 #elif defined(USE_OZONE)
1220 va_display_ = vaGetDisplayDRM(drm_fd_.get());
1221 #endif // USE_X11
1222
1223 if (!vaDisplayIsValid(va_display_)) {
1224 LOG(ERROR) << "Could not get a valid VA display";
1225 return false;
1226 }
1227
1228 VAStatus va_res =
1229 vaInitialize(va_display_, &major_version_, &minor_version_);
1230 if (va_res != VA_STATUS_SUCCESS) {
1231 LOG(WARNING) << "vaInitialize failed: " << vaErrorStr(va_res);
1232 return false;
1233 }
1234
1235 va_initialized_ = true;
1236 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_;
1237 }
1238
1239 if (VAAPIVersionLessThan(0, 34)) {
1240 LOG(ERROR) << "VAAPI version < 0.34 is not supported.";
1241 return false;
1242 }
1243 return true;
1244 }
1245
1246 void VaapiWrapper::VADisplayState::Deinitialize(VAStatus* status) {
1247 va_lock_.AssertAcquired();
1248 if (--refcount_ > 0)
1249 return;
1250
1251 // Must check if vaInitialize completed successfully, to work around a bug in
1252 // libva. The bug was fixed upstream:
1253 // http://lists.freedesktop.org/archives/libva/2013-July/001807.html
1254 // TODO(mgiuca): Remove this check, and the |va_initialized_| variable, once
1255 // the fix has rolled out sufficiently.
1256 if (va_initialized_ && va_display_) {
1257 *status = vaTerminate(va_display_);
1258 }
1259 va_initialized_ = false;
1260 va_display_ = nullptr;
1261 }
1262
1263 #if defined(USE_OZONE)
1264 void VaapiWrapper::VADisplayState::SetDrmFd(base::PlatformFile fd) {
1265 drm_fd_.reset(HANDLE_EINTR(dup(fd)));
1266 }
1267 #endif // USE_OZONE
1268
1269 bool VaapiWrapper::VADisplayState::VAAPIVersionLessThan(int major, int minor) {
1270 return (major_version_ < major) ||
1271 (major_version_ == major && minor_version_ < minor);
1272 }
1273
1274 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698