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.
5 #include "content/common/gpu/media/vaapi_wrapper.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "base/numerics/safe_conversions.h"
13 // Auto-generated for dlopen libva libraries
14 #include "content/common/gpu/media/va_stubs.h"
15 #include "third_party/libyuv/include/libyuv.h"
17 using content_common_gpu_media::kModuleVa;
18 using content_common_gpu_media::InitializeStubs;
19 using content_common_gpu_media::StubPathMap;
21 // libva-x11 depends on libva, so dlopen libva-x11 is enough
22 static const base::FilePath::CharType kVaLib[] =
23 FILE_PATH_LITERAL("libva-x11.so.1");
25 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \
28 << " VA error: " << vaErrorStr(va_error); \
29 report_error_to_uma_cb_.Run(); \
32 #define VA_LOG_ON_ERROR(va_error, err_msg) \
34 if ((va_error) != VA_STATUS_SUCCESS) \
35 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
38 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \
40 if ((va_error) != VA_STATUS_SUCCESS) { \
41 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
48 // Config attributes common for both encode and decode.
49 static const VAConfigAttrib kCommonVAConfigAttribs[] = {
50 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420},
53 // Attributes required for encode.
54 static const VAConfigAttrib kEncodeVAConfigAttribs[] = {
55 {VAConfigAttribRateControl, VA_RC_CBR},
56 {VAConfigAttribEncPackedHeaders,
57 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE},
61 media::VideoCodecProfile profile;
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},
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));
87 return required_attribs;
90 // Maps Profile enum values to VaProfile values.
91 static VAProfile ProfileToVAProfile(
92 media::VideoCodecProfile profile,
93 const std::vector<VAProfile>& supported_profiles) {
95 VAProfile va_profile = VAProfileNone;
96 for (size_t i = 0; i < arraysize(kProfileMap); i++) {
97 if (kProfileMap[i].profile == profile) {
98 va_profile = kProfileMap[i].va_profile;
103 bool supported = std::find(supported_profiles.begin(),
104 supported_profiles.end(),
105 va_profile) != supported_profiles.end();
107 if (!supported && va_profile == VAProfileH264Baseline) {
108 // crbug.com/345569: media::ProfileIDToVideoCodecProfile() currently strips
109 // the information whether the profile is constrained or not, so we have no
110 // way to know here. Try for baseline first, but if it is not supported,
111 // try constrained baseline and hope this is what it actually is
112 // (which in practice is true for a great majority of cases).
113 if (std::find(supported_profiles.begin(),
114 supported_profiles.end(),
115 VAProfileH264ConstrainedBaseline) !=
116 supported_profiles.end()) {
117 va_profile = VAProfileH264ConstrainedBaseline;
118 DVLOG(1) << "Falling back to constrained baseline profile.";
125 VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb)
126 : va_surface_id_(va_surface_id),
127 release_cb_(release_cb) {
128 DCHECK(!release_cb_.is_null());
131 VASurface::~VASurface() {
132 release_cb_.Run(va_surface_id_);
135 VaapiWrapper::VaapiWrapper()
137 va_config_id_(VA_INVALID_ID),
138 va_context_id_(VA_INVALID_ID) {
141 VaapiWrapper::~VaapiWrapper() {
142 DestroyPendingBuffers();
143 DestroyCodedBuffers();
148 scoped_ptr<VaapiWrapper> VaapiWrapper::Create(
150 media::VideoCodecProfile profile,
152 const base::Closure& report_error_to_uma_cb) {
153 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
155 if (!vaapi_wrapper->Initialize(
156 mode, profile, x_display, report_error_to_uma_cb))
157 vaapi_wrapper.reset();
159 return vaapi_wrapper.Pass();
162 std::vector<media::VideoCodecProfile> VaapiWrapper::GetSupportedEncodeProfiles(
164 const base::Closure& report_error_to_uma_cb) {
165 std::vector<media::VideoCodecProfile> supported_profiles;
167 scoped_ptr<VaapiWrapper> wrapper(new VaapiWrapper());
168 if (!wrapper->VaInitialize(x_display, report_error_to_uma_cb)) {
169 return supported_profiles;
172 std::vector<VAProfile> va_profiles;
173 if (!wrapper->GetSupportedVaProfiles(&va_profiles))
174 return supported_profiles;
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);
187 return supported_profiles;
190 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() {
191 base::AutoLock auto_lock(va_lock_);
192 VADisplayAttribute item = {VADisplayAttribRenderMode,
193 1, // At least support '_LOCAL_OVERLAY'.
194 -1, // The maximum possible support 'ALL'.
195 VA_RENDER_MODE_LOCAL_GPU,
196 VA_DISPLAY_ATTRIB_SETTABLE};
198 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1);
199 if (va_res != VA_STATUS_SUCCESS)
200 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default.";
203 bool VaapiWrapper::VaInitialize(Display* x_display,
204 const base::Closure& report_error_to_uma_cb) {
205 static bool vaapi_functions_initialized = PostSandboxInitialization();
206 if (!vaapi_functions_initialized) {
207 DVLOG(1) << "Failed to initialize VAAPI libs";
211 report_error_to_uma_cb_ = report_error_to_uma_cb;
213 base::AutoLock auto_lock(va_lock_);
215 va_display_ = vaGetDisplay(x_display);
216 if (!vaDisplayIsValid(va_display_)) {
217 DVLOG(1) << "Could not get a valid VA display";
221 VAStatus va_res = vaInitialize(va_display_, &major_version_, &minor_version_);
222 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
223 DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_;
225 if (VAAPIVersionLessThan(0, 34)) {
226 DVLOG(1) << "VAAPI version < 0.34 is not supported.";
232 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) {
233 base::AutoLock auto_lock(va_lock_);
234 // Query the driver for supported profiles.
235 int max_profiles = vaMaxNumProfiles(va_display_);
236 std::vector<VAProfile> supported_profiles(
237 base::checked_cast<size_t>(max_profiles));
239 int num_supported_profiles;
240 VAStatus va_res = vaQueryConfigProfiles(
241 va_display_, &supported_profiles[0], &num_supported_profiles);
242 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigProfiles failed", false);
243 if (num_supported_profiles < 0 || num_supported_profiles > max_profiles) {
244 DVLOG(1) << "vaQueryConfigProfiles returned: " << num_supported_profiles;
248 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles));
249 *profiles = supported_profiles;
253 bool VaapiWrapper::IsEntrypointSupported(VAProfile va_profile,
254 VAEntrypoint entrypoint) {
255 base::AutoLock auto_lock(va_lock_);
256 // Query the driver for supported entrypoints.
257 int max_entrypoints = vaMaxNumEntrypoints(va_display_);
258 std::vector<VAEntrypoint> supported_entrypoints(
259 base::checked_cast<size_t>(max_entrypoints));
261 int num_supported_entrypoints;
262 VAStatus va_res = vaQueryConfigEntrypoints(va_display_,
264 &supported_entrypoints[0],
265 &num_supported_entrypoints);
266 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false);
267 if (num_supported_entrypoints < 0 ||
268 num_supported_entrypoints > max_entrypoints) {
269 DVLOG(1) << "vaQueryConfigEntrypoints returned: "
270 << num_supported_entrypoints;
274 if (std::find(supported_entrypoints.begin(),
275 supported_entrypoints.end(),
276 entrypoint) == supported_entrypoints.end()) {
277 DVLOG(1) << "Unsupported entrypoint";
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_);
288 // Query the driver for required attributes.
289 std::vector<VAConfigAttrib> attribs = required_attribs;
290 for (size_t i = 0; i < required_attribs.size(); ++i)
291 attribs[i].value = 0;
293 VAStatus va_res = vaGetConfigAttributes(
294 va_display_, va_profile, entrypoint, &attribs[0], attribs.size());
295 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
297 for (size_t i = 0; i < required_attribs.size(); ++i) {
298 if (attribs[i].type != required_attribs[i].type ||
299 (attribs[i].value & required_attribs[i].value) !=
300 required_attribs[i].value) {
301 DVLOG(1) << "Unsupported value " << required_attribs[i].value
302 << " for attribute type " << required_attribs[i].type;
309 bool VaapiWrapper::Initialize(CodecMode mode,
310 media::VideoCodecProfile profile,
312 const base::Closure& report_error_to_uma_cb) {
313 if (!VaInitialize(x_display, report_error_to_uma_cb))
315 std::vector<VAProfile> supported_va_profiles;
316 if (!GetSupportedVaProfiles(&supported_va_profiles))
318 VAProfile va_profile = ProfileToVAProfile(profile, supported_va_profiles);
319 if (va_profile == VAProfileNone) {
320 DVLOG(1) << "Unsupported profile";
323 VAEntrypoint entrypoint =
324 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD);
325 if (!IsEntrypointSupported(va_profile, entrypoint))
327 std::vector<VAConfigAttrib> required_attribs = GetRequiredAttribs(mode);
328 if (!AreAttribsSupported(va_profile, entrypoint, required_attribs))
331 TryToSetVADisplayAttributeToLocalGPU();
333 base::AutoLock auto_lock(va_lock_);
334 VAStatus va_res = vaCreateConfig(va_display_,
337 &required_attribs[0],
338 required_attribs.size(),
340 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
345 void VaapiWrapper::Deinitialize() {
346 base::AutoLock auto_lock(va_lock_);
348 if (va_config_id_ != VA_INVALID_ID) {
349 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_);
350 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
354 VAStatus va_res = vaTerminate(va_display_);
355 VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
358 va_config_id_ = VA_INVALID_ID;
362 bool VaapiWrapper::VAAPIVersionLessThan(int major, int minor) {
363 return (major_version_ < major) ||
364 (major_version_ == major && minor_version_ < minor);
367 bool VaapiWrapper::CreateSurfaces(gfx::Size size,
369 std::vector<VASurfaceID>* va_surfaces) {
370 base::AutoLock auto_lock(va_lock_);
371 DVLOG(2) << "Creating " << num_surfaces << " surfaces";
373 DCHECK(va_surfaces->empty());
374 DCHECK(va_surface_ids_.empty());
375 va_surface_ids_.resize(num_surfaces);
377 // Allocate surfaces in driver.
378 VAStatus va_res = vaCreateSurfaces(va_display_,
380 size.width(), size.height(),
382 va_surface_ids_.size(),
385 VA_LOG_ON_ERROR(va_res, "vaCreateSurfaces failed");
386 if (va_res != VA_STATUS_SUCCESS) {
387 va_surface_ids_.clear();
391 // And create a context associated with them.
392 va_res = vaCreateContext(va_display_, va_config_id_,
393 size.width(), size.height(), VA_PROGRESSIVE,
394 &va_surface_ids_[0], va_surface_ids_.size(),
397 VA_LOG_ON_ERROR(va_res, "vaCreateContext failed");
398 if (va_res != VA_STATUS_SUCCESS) {
403 *va_surfaces = va_surface_ids_;
407 void VaapiWrapper::DestroySurfaces() {
408 base::AutoLock auto_lock(va_lock_);
409 DVLOG(2) << "Destroying " << va_surface_ids_.size() << " surfaces";
411 if (va_context_id_ != VA_INVALID_ID) {
412 VAStatus va_res = vaDestroyContext(va_display_, va_context_id_);
413 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed");
416 if (!va_surface_ids_.empty()) {
417 VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_ids_[0],
418 va_surface_ids_.size());
419 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed");
422 va_surface_ids_.clear();
423 va_context_id_ = VA_INVALID_ID;
426 bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
429 base::AutoLock auto_lock(va_lock_);
431 VABufferID buffer_id;
432 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_,
433 va_buffer_type, size,
434 1, buffer, &buffer_id);
435 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
437 switch (va_buffer_type) {
438 case VASliceParameterBufferType:
439 case VASliceDataBufferType:
440 case VAEncSliceParameterBufferType:
441 pending_slice_bufs_.push_back(buffer_id);
445 pending_va_bufs_.push_back(buffer_id);
452 bool VaapiWrapper::SubmitVAEncMiscParamBuffer(
453 VAEncMiscParameterType misc_param_type,
456 base::AutoLock auto_lock(va_lock_);
458 VABufferID buffer_id;
459 VAStatus va_res = vaCreateBuffer(va_display_,
461 VAEncMiscParameterBufferType,
462 sizeof(VAEncMiscParameterBuffer) + size,
466 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
468 void* data_ptr = NULL;
469 va_res = vaMapBuffer(va_display_, buffer_id, &data_ptr);
470 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
471 if (va_res != VA_STATUS_SUCCESS) {
472 vaDestroyBuffer(va_display_, buffer_id);
478 VAEncMiscParameterBuffer* misc_param =
479 reinterpret_cast<VAEncMiscParameterBuffer*>(data_ptr);
480 misc_param->type = misc_param_type;
481 memcpy(misc_param->data, buffer, size);
482 va_res = vaUnmapBuffer(va_display_, buffer_id);
483 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
485 pending_va_bufs_.push_back(buffer_id);
489 void VaapiWrapper::DestroyPendingBuffers() {
490 base::AutoLock auto_lock(va_lock_);
492 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) {
493 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]);
494 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
497 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) {
498 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]);
499 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
502 pending_va_bufs_.clear();
503 pending_slice_bufs_.clear();
506 bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) {
507 base::AutoLock auto_lock(va_lock_);
508 VAStatus va_res = vaCreateBuffer(va_display_,
510 VAEncCodedBufferType,
515 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a coded buffer", false);
517 DCHECK(coded_buffers_.insert(*buffer_id).second);
521 void VaapiWrapper::DestroyCodedBuffers() {
522 base::AutoLock auto_lock(va_lock_);
524 for (std::set<VABufferID>::const_iterator iter = coded_buffers_.begin();
525 iter != coded_buffers_.end();
527 VAStatus va_res = vaDestroyBuffer(va_display_, *iter);
528 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
531 coded_buffers_.clear();
534 bool VaapiWrapper::Execute(VASurfaceID va_surface_id) {
535 base::AutoLock auto_lock(va_lock_);
537 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
538 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
539 DVLOG(4) << "Target VA surface " << va_surface_id;
541 // Get ready to execute for given surface.
542 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_,
544 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false);
546 if (pending_va_bufs_.size() > 0) {
547 // Commit parameter and slice buffers.
548 va_res = vaRenderPicture(va_display_,
550 &pending_va_bufs_[0],
551 pending_va_bufs_.size());
552 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false);
555 if (pending_slice_bufs_.size() > 0) {
556 va_res = vaRenderPicture(va_display_,
558 &pending_slice_bufs_[0],
559 pending_slice_bufs_.size());
560 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false);
563 // Instruct HW codec to start processing committed buffers.
564 // Does not block and the job is not finished after this returns.
565 va_res = vaEndPicture(va_display_, va_context_id_);
566 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false);
571 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
572 bool result = Execute(va_surface_id);
573 DestroyPendingBuffers();
577 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
579 gfx::Size dest_size) {
580 base::AutoLock auto_lock(va_lock_);
582 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
583 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
585 // Put the data into an X Pixmap.
586 va_res = vaPutSurface(va_display_,
589 0, 0, dest_size.width(), dest_size.height(),
590 0, 0, dest_size.width(), dest_size.height(),
592 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false);
596 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id,
599 base::AutoLock auto_lock(va_lock_);
601 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
602 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
604 // Derive a VAImage from the VASurface
605 va_res = vaDeriveImage(va_display_, va_surface_id, image);
606 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed");
607 if (va_res != VA_STATUS_SUCCESS)
610 // Map the VAImage into memory
611 va_res = vaMapBuffer(va_display_, image->buf, mem);
612 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed");
613 if (va_res == VA_STATUS_SUCCESS)
616 va_res = vaDestroyImage(va_display_, image->image_id);
617 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
622 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) {
623 base::AutoLock auto_lock(va_lock_);
625 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf);
626 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
628 va_res = vaDestroyImage(va_display_, image->image_id);
629 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed");
632 static void DestroyVAImage(VADisplay va_display, VAImage image) {
633 if (image.image_id != VA_INVALID_ID)
634 vaDestroyImage(va_display, image.image_id);
637 bool VaapiWrapper::UploadVideoFrameToSurface(
638 const scoped_refptr<media::VideoFrame>& frame,
639 VASurfaceID va_surface_id) {
640 base::AutoLock auto_lock(va_lock_);
643 VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image);
644 VA_SUCCESS_OR_RETURN(va_res, "vaDeriveImage failed", false);
645 base::ScopedClosureRunner vaimage_deleter(
646 base::Bind(&DestroyVAImage, va_display_, image));
648 if (image.format.fourcc != VA_FOURCC_NV12) {
649 DVLOG(1) << "Unsupported image format: " << image.format.fourcc;
653 if (gfx::Rect(image.width, image.height) < gfx::Rect(frame->coded_size())) {
654 DVLOG(1) << "Buffer too small to fit the frame.";
658 void* image_ptr = NULL;
659 va_res = vaMapBuffer(va_display_, image.buf, &image_ptr);
660 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false);
665 base::AutoUnlock auto_unlock(va_lock_);
666 ret = libyuv::I420ToNV12(frame->data(media::VideoFrame::kYPlane),
667 frame->stride(media::VideoFrame::kYPlane),
668 frame->data(media::VideoFrame::kUPlane),
669 frame->stride(media::VideoFrame::kUPlane),
670 frame->data(media::VideoFrame::kVPlane),
671 frame->stride(media::VideoFrame::kVPlane),
672 static_cast<uint8*>(image_ptr) + image.offsets[0],
674 static_cast<uint8*>(image_ptr) + image.offsets[1],
680 va_res = vaUnmapBuffer(va_display_, image.buf);
681 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
686 bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
687 VASurfaceID sync_surface_id,
690 size_t* coded_data_size) {
691 base::AutoLock auto_lock(va_lock_);
693 VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id);
694 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
696 VACodedBufferSegment* buffer_segment = NULL;
697 va_res = vaMapBuffer(
698 va_display_, buffer_id, reinterpret_cast<void**>(&buffer_segment));
699 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false);
703 base::AutoUnlock auto_unlock(va_lock_);
704 *coded_data_size = 0;
706 while (buffer_segment) {
707 DCHECK(buffer_segment->buf);
709 if (buffer_segment->size > target_size) {
710 DVLOG(1) << "Insufficient output buffer size";
714 memcpy(target_ptr, buffer_segment->buf, buffer_segment->size);
716 target_ptr += buffer_segment->size;
717 *coded_data_size += buffer_segment->size;
718 target_size -= buffer_segment->size;
721 reinterpret_cast<VACodedBufferSegment*>(buffer_segment->next);
725 va_res = vaUnmapBuffer(va_display_, buffer_id);
726 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed");
728 va_res = vaDestroyBuffer(va_display_, buffer_id);
729 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
731 DCHECK(coded_buffers_.erase(buffer_id));
733 return buffer_segment == NULL;
737 bool VaapiWrapper::PostSandboxInitialization() {
739 paths[kModuleVa].push_back(kVaLib);
741 return InitializeStubs(paths);
744 } // namespace content