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/logging.h" | 11 #include "base/logging.h" |
11 #include "base/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
12 // Auto-generated for dlopen libva libraries | 13 // Auto-generated for dlopen libva libraries |
13 #include "content/common/gpu/media/va_stubs.h" | 14 #include "content/common/gpu/media/va_stubs.h" |
| 15 #include "third_party/libyuv/include/libyuv.h" |
14 | 16 |
15 using content_common_gpu_media::kModuleVa; | 17 using content_common_gpu_media::kModuleVa; |
16 using content_common_gpu_media::InitializeStubs; | 18 using content_common_gpu_media::InitializeStubs; |
17 using content_common_gpu_media::StubPathMap; | 19 using content_common_gpu_media::StubPathMap; |
18 | 20 |
19 // libva-x11 depends on libva, so dlopen libva-x11 is enough | 21 // libva-x11 depends on libva, so dlopen libva-x11 is enough |
20 static const base::FilePath::CharType kVaLib[] = | 22 static const base::FilePath::CharType kVaLib[] = |
21 FILE_PATH_LITERAL("libva-x11.so.1"); | 23 FILE_PATH_LITERAL("libva-x11.so.1"); |
22 | 24 |
23 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ | 25 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ |
(...skipping 12 matching lines...) Expand all Loading... |
36 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \ | 38 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \ |
37 do { \ | 39 do { \ |
38 if ((va_error) != VA_STATUS_SUCCESS) { \ | 40 if ((va_error) != VA_STATUS_SUCCESS) { \ |
39 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \ | 41 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \ |
40 return (ret); \ | 42 return (ret); \ |
41 } \ | 43 } \ |
42 } while (0) | 44 } while (0) |
43 | 45 |
44 namespace content { | 46 namespace content { |
45 | 47 |
| 48 // Config attributes common for both encode and decode. |
| 49 static const VAConfigAttrib kCommonVAConfigAttribs[] = { |
| 50 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, |
| 51 }; |
| 52 |
| 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}, |
| 58 }; |
| 59 |
46 // Maps Profile enum values to VaProfile values. | 60 // Maps Profile enum values to VaProfile values. |
47 static VAProfile ProfileToVAProfile( | 61 static VAProfile ProfileToVAProfile( |
48 media::VideoCodecProfile profile, | 62 media::VideoCodecProfile profile, |
49 const std::vector<VAProfile>& supported_profiles) { | 63 const std::vector<VAProfile>& supported_profiles) { |
50 | 64 |
51 VAProfile va_profile = VAProfileNone; | 65 VAProfile va_profile = VAProfileNone; |
52 | 66 |
53 switch (profile) { | 67 switch (profile) { |
54 case media::H264PROFILE_BASELINE: | 68 case media::H264PROFILE_BASELINE: |
55 va_profile = VAProfileH264Baseline; | 69 va_profile = VAProfileH264Baseline; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 } | 113 } |
100 | 114 |
101 VaapiWrapper::VaapiWrapper() | 115 VaapiWrapper::VaapiWrapper() |
102 : va_display_(NULL), | 116 : va_display_(NULL), |
103 va_config_id_(VA_INVALID_ID), | 117 va_config_id_(VA_INVALID_ID), |
104 va_context_id_(VA_INVALID_ID) { | 118 va_context_id_(VA_INVALID_ID) { |
105 } | 119 } |
106 | 120 |
107 VaapiWrapper::~VaapiWrapper() { | 121 VaapiWrapper::~VaapiWrapper() { |
108 DestroyPendingBuffers(); | 122 DestroyPendingBuffers(); |
| 123 DestroyCodedBuffers(); |
109 DestroySurfaces(); | 124 DestroySurfaces(); |
110 Deinitialize(); | 125 Deinitialize(); |
111 } | 126 } |
112 | 127 |
113 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( | 128 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
| 129 CodecMode mode, |
114 media::VideoCodecProfile profile, | 130 media::VideoCodecProfile profile, |
115 Display* x_display, | 131 Display* x_display, |
116 const base::Closure& report_error_to_uma_cb) { | 132 const base::Closure& report_error_to_uma_cb) { |
117 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 133 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
118 | 134 |
119 if (!vaapi_wrapper->Initialize(profile, x_display, report_error_to_uma_cb)) | 135 if (!vaapi_wrapper->Initialize( |
| 136 mode, profile, x_display, report_error_to_uma_cb)) |
120 vaapi_wrapper.reset(); | 137 vaapi_wrapper.reset(); |
121 | 138 |
122 return vaapi_wrapper.Pass(); | 139 return vaapi_wrapper.Pass(); |
123 } | 140 } |
124 | 141 |
125 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { | 142 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
126 VADisplayAttribute item = {VADisplayAttribRenderMode, | 143 VADisplayAttribute item = {VADisplayAttribRenderMode, |
127 1, // At least support '_LOCAL_OVERLAY'. | 144 1, // At least support '_LOCAL_OVERLAY'. |
128 -1, // The maximum possible support 'ALL'. | 145 -1, // The maximum possible support 'ALL'. |
129 VA_RENDER_MODE_LOCAL_GPU, | 146 VA_RENDER_MODE_LOCAL_GPU, |
130 VA_DISPLAY_ATTRIB_SETTABLE}; | 147 VA_DISPLAY_ATTRIB_SETTABLE}; |
131 | 148 |
132 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 149 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
133 if (va_res != VA_STATUS_SUCCESS) | 150 if (va_res != VA_STATUS_SUCCESS) |
134 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 151 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
135 } | 152 } |
136 | 153 |
137 bool VaapiWrapper::Initialize(media::VideoCodecProfile profile, | 154 bool VaapiWrapper::Initialize(CodecMode mode, |
| 155 media::VideoCodecProfile profile, |
138 Display* x_display, | 156 Display* x_display, |
139 const base::Closure& report_error_to_uma_cb) { | 157 const base::Closure& report_error_to_uma_cb) { |
140 static bool vaapi_functions_initialized = PostSandboxInitialization(); | 158 static bool vaapi_functions_initialized = PostSandboxInitialization(); |
141 if (!vaapi_functions_initialized) { | 159 if (!vaapi_functions_initialized) { |
142 DVLOG(1) << "Failed to initialize VAAPI libs"; | 160 DVLOG(1) << "Failed to initialize VAAPI libs"; |
143 return false; | 161 return false; |
144 } | 162 } |
145 | 163 |
146 report_error_to_uma_cb_ = report_error_to_uma_cb; | 164 report_error_to_uma_cb_ = report_error_to_uma_cb; |
147 | 165 |
(...skipping 29 matching lines...) Expand all Loading... |
177 } | 195 } |
178 | 196 |
179 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); | 197 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); |
180 | 198 |
181 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); | 199 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); |
182 if (va_profile == VAProfileNone) { | 200 if (va_profile == VAProfileNone) { |
183 DVLOG(1) << "Unsupported profile"; | 201 DVLOG(1) << "Unsupported profile"; |
184 return false; | 202 return false; |
185 } | 203 } |
186 | 204 |
187 VAConfigAttrib attrib = {VAConfigAttribRTFormat, 0}; | 205 // Query the driver for supported entrypoints. |
188 const VAEntrypoint kEntrypoint = VAEntrypointVLD; | 206 int max_entrypoints = vaMaxNumEntrypoints(va_display_); |
189 va_res = vaGetConfigAttributes(va_display_, va_profile, kEntrypoint, | 207 std::vector<VAEntrypoint> supported_entrypoints( |
190 &attrib, 1); | 208 base::checked_cast<size_t>(max_entrypoints)); |
| 209 |
| 210 int num_supported_entrypoints; |
| 211 va_res = vaQueryConfigEntrypoints(va_display_, |
| 212 va_profile, |
| 213 &supported_entrypoints[0], |
| 214 &num_supported_entrypoints); |
| 215 VA_SUCCESS_OR_RETURN(va_res, "vaQueryConfigEntrypoints failed", false); |
| 216 if (num_supported_entrypoints < 0 || |
| 217 num_supported_entrypoints > max_entrypoints) { |
| 218 DVLOG(1) << "vaQueryConfigEntrypoints returned: " |
| 219 << num_supported_entrypoints; |
| 220 return false; |
| 221 } |
| 222 |
| 223 VAEntrypoint entrypoint = |
| 224 (mode == kEncode ? VAEntrypointEncSlice : VAEntrypointVLD); |
| 225 |
| 226 if (std::find(supported_entrypoints.begin(), |
| 227 supported_entrypoints.end(), |
| 228 entrypoint) == supported_entrypoints.end()) { |
| 229 DVLOG(1) << "Unsupported entrypoint"; |
| 230 return false; |
| 231 } |
| 232 |
| 233 // 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; |
| 247 for (size_t i = 0; i < required_attribs.size(); ++i) |
| 248 attribs[i].value = 0; |
| 249 |
| 250 va_res = vaGetConfigAttributes( |
| 251 va_display_, va_profile, entrypoint, &attribs[0], attribs.size()); |
191 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); | 252 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); |
192 | 253 |
193 if (!(attrib.value & VA_RT_FORMAT_YUV420)) { | 254 for (size_t i = 0; i < required_attribs.size(); ++i) { |
194 DVLOG(1) << "YUV420 not supported by this VAAPI implementation"; | 255 if (attribs[i].type != required_attribs[i].type || |
195 return false; | 256 (attribs[i].value & required_attribs[i].value) != |
| 257 required_attribs[i].value) { |
| 258 DVLOG(1) << "Unsupported value " << required_attribs[i].value |
| 259 << " for attribute type " << required_attribs[i].type; |
| 260 return false; |
| 261 } |
196 } | 262 } |
197 | 263 |
198 TryToSetVADisplayAttributeToLocalGPU(); | 264 TryToSetVADisplayAttributeToLocalGPU(); |
199 | 265 |
200 va_res = vaCreateConfig(va_display_, va_profile, kEntrypoint, | 266 va_res = vaCreateConfig(va_display_, |
201 &attrib, 1, &va_config_id_); | 267 va_profile, |
| 268 entrypoint, |
| 269 &required_attribs[0], |
| 270 required_attribs.size(), |
| 271 &va_config_id_); |
202 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | 272 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); |
203 | 273 |
204 return true; | 274 return true; |
205 } | 275 } |
206 | 276 |
207 void VaapiWrapper::Deinitialize() { | 277 void VaapiWrapper::Deinitialize() { |
208 base::AutoLock auto_lock(va_lock_); | 278 base::AutoLock auto_lock(va_lock_); |
209 | 279 |
210 if (va_config_id_ != VA_INVALID_ID) { | 280 if (va_config_id_ != VA_INVALID_ID) { |
211 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 281 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 362 |
293 VABufferID buffer_id; | 363 VABufferID buffer_id; |
294 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, | 364 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, |
295 va_buffer_type, size, | 365 va_buffer_type, size, |
296 1, buffer, &buffer_id); | 366 1, buffer, &buffer_id); |
297 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); | 367 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); |
298 | 368 |
299 switch (va_buffer_type) { | 369 switch (va_buffer_type) { |
300 case VASliceParameterBufferType: | 370 case VASliceParameterBufferType: |
301 case VASliceDataBufferType: | 371 case VASliceDataBufferType: |
| 372 case VAEncSliceParameterBufferType: |
302 pending_slice_bufs_.push_back(buffer_id); | 373 pending_slice_bufs_.push_back(buffer_id); |
303 break; | 374 break; |
304 | 375 |
305 default: | 376 default: |
306 pending_va_bufs_.push_back(buffer_id); | 377 pending_va_bufs_.push_back(buffer_id); |
307 break; | 378 break; |
308 } | 379 } |
309 | 380 |
310 return true; | 381 return true; |
311 } | 382 } |
312 | 383 |
| 384 bool VaapiWrapper::SubmitVAEncMiscParamBuffer( |
| 385 VAEncMiscParameterType misc_param_type, |
| 386 size_t size, |
| 387 void* buffer) { |
| 388 base::AutoLock auto_lock(va_lock_); |
| 389 |
| 390 VABufferID buffer_id; |
| 391 VAStatus va_res = vaCreateBuffer(va_display_, |
| 392 va_context_id_, |
| 393 VAEncMiscParameterBufferType, |
| 394 sizeof(VAEncMiscParameterBuffer) + size, |
| 395 1, |
| 396 NULL, |
| 397 &buffer_id); |
| 398 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); |
| 399 |
| 400 void* data_ptr = NULL; |
| 401 va_res = vaMapBuffer(va_display_, buffer_id, &data_ptr); |
| 402 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
| 403 if (va_res != VA_STATUS_SUCCESS) { |
| 404 vaDestroyBuffer(va_display_, buffer_id); |
| 405 return false; |
| 406 } |
| 407 |
| 408 DCHECK(data_ptr); |
| 409 |
| 410 VAEncMiscParameterBuffer* misc_param = |
| 411 reinterpret_cast<VAEncMiscParameterBuffer*>(data_ptr); |
| 412 misc_param->type = misc_param_type; |
| 413 memcpy(misc_param->data, buffer, size); |
| 414 va_res = vaUnmapBuffer(va_display_, buffer_id); |
| 415 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
| 416 |
| 417 pending_va_bufs_.push_back(buffer_id); |
| 418 return true; |
| 419 } |
| 420 |
313 void VaapiWrapper::DestroyPendingBuffers() { | 421 void VaapiWrapper::DestroyPendingBuffers() { |
314 base::AutoLock auto_lock(va_lock_); | 422 base::AutoLock auto_lock(va_lock_); |
315 | 423 |
316 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { | 424 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { |
317 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); | 425 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); |
318 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 426 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
319 } | 427 } |
320 | 428 |
321 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { | 429 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { |
322 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); | 430 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); |
323 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 431 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
324 } | 432 } |
325 | 433 |
326 pending_va_bufs_.clear(); | 434 pending_va_bufs_.clear(); |
327 pending_slice_bufs_.clear(); | 435 pending_slice_bufs_.clear(); |
328 } | 436 } |
329 | 437 |
330 bool VaapiWrapper::SubmitDecode(VASurfaceID va_surface_id) { | 438 bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) { |
| 439 base::AutoLock auto_lock(va_lock_); |
| 440 VAStatus va_res = vaCreateBuffer(va_display_, |
| 441 va_context_id_, |
| 442 VAEncCodedBufferType, |
| 443 size, |
| 444 1, |
| 445 NULL, |
| 446 buffer_id); |
| 447 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a coded buffer", false); |
| 448 |
| 449 DCHECK(coded_buffers_.insert(*buffer_id).second); |
| 450 return true; |
| 451 } |
| 452 |
| 453 void VaapiWrapper::DestroyCodedBuffers() { |
| 454 base::AutoLock auto_lock(va_lock_); |
| 455 |
| 456 for (std::set<VABufferID>::const_iterator iter = coded_buffers_.begin(); |
| 457 iter != coded_buffers_.end(); |
| 458 ++iter) { |
| 459 VAStatus va_res = vaDestroyBuffer(va_display_, *iter); |
| 460 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
| 461 } |
| 462 |
| 463 coded_buffers_.clear(); |
| 464 } |
| 465 |
| 466 bool VaapiWrapper::Execute(VASurfaceID va_surface_id) { |
331 base::AutoLock auto_lock(va_lock_); | 467 base::AutoLock auto_lock(va_lock_); |
332 | 468 |
333 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); | 469 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); |
334 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); | 470 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); |
335 DVLOG(4) << "Decoding into VA surface " << va_surface_id; | 471 DVLOG(4) << "Target VA surface " << va_surface_id; |
336 | 472 |
337 // Get ready to decode into surface. | 473 // Get ready to execute for given surface. |
338 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, | 474 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, |
339 va_surface_id); | 475 va_surface_id); |
340 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); | 476 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); |
341 | 477 |
342 // Commit parameter and slice buffers. | 478 if (pending_va_bufs_.size() > 0) { |
343 va_res = vaRenderPicture(va_display_, va_context_id_, | 479 // Commit parameter and slice buffers. |
344 &pending_va_bufs_[0], pending_va_bufs_.size()); | 480 va_res = vaRenderPicture(va_display_, |
345 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | 481 va_context_id_, |
| 482 &pending_va_bufs_[0], |
| 483 pending_va_bufs_.size()); |
| 484 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); |
| 485 } |
346 | 486 |
347 va_res = vaRenderPicture(va_display_, va_context_id_, | 487 if (pending_slice_bufs_.size() > 0) { |
348 &pending_slice_bufs_[0], | 488 va_res = vaRenderPicture(va_display_, |
349 pending_slice_bufs_.size()); | 489 va_context_id_, |
350 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | 490 &pending_slice_bufs_[0], |
| 491 pending_slice_bufs_.size()); |
| 492 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); |
| 493 } |
351 | 494 |
352 // Instruct HW decoder to start processing committed buffers (decode this | 495 // Instruct HW codec to start processing committed buffers. |
353 // picture). This does not block until the end of decode. | 496 // Does not block and the job is not finished after this returns. |
354 va_res = vaEndPicture(va_display_, va_context_id_); | 497 va_res = vaEndPicture(va_display_, va_context_id_); |
355 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); | 498 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); |
356 | 499 |
357 return true; | 500 return true; |
358 } | 501 } |
359 | 502 |
360 bool VaapiWrapper::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) { | 503 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { |
361 bool result = SubmitDecode(va_surface_id); | 504 bool result = Execute(va_surface_id); |
362 DestroyPendingBuffers(); | 505 DestroyPendingBuffers(); |
363 return result; | 506 return result; |
364 } | 507 } |
365 | 508 |
366 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, | 509 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, |
367 Pixmap x_pixmap, | 510 Pixmap x_pixmap, |
368 gfx::Size dest_size) { | 511 gfx::Size dest_size) { |
369 base::AutoLock auto_lock(va_lock_); | 512 base::AutoLock auto_lock(va_lock_); |
370 | 513 |
371 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 514 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
372 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 515 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
373 | 516 |
374 // Put the data into an X Pixmap. | 517 // Put the data into an X Pixmap. |
375 va_res = vaPutSurface(va_display_, | 518 va_res = vaPutSurface(va_display_, |
376 va_surface_id, | 519 va_surface_id, |
377 x_pixmap, | 520 x_pixmap, |
378 0, 0, dest_size.width(), dest_size.height(), | 521 0, 0, dest_size.width(), dest_size.height(), |
379 0, 0, dest_size.width(), dest_size.height(), | 522 0, 0, dest_size.width(), dest_size.height(), |
380 NULL, 0, 0); | 523 NULL, 0, 0); |
381 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decode surface to pixmap", | 524 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); |
382 false); | |
383 return true; | 525 return true; |
384 } | 526 } |
385 | 527 |
386 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, | 528 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, |
387 VAImage* image, | 529 VAImage* image, |
388 void** mem) { | 530 void** mem) { |
389 base::AutoLock auto_lock(va_lock_); | 531 base::AutoLock auto_lock(va_lock_); |
390 | 532 |
391 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 533 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
392 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 534 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
393 | 535 |
394 // Derive a VAImage from the VASurface | 536 // Derive a VAImage from the VASurface |
395 va_res = vaDeriveImage(va_display_, va_surface_id, image); | 537 va_res = vaDeriveImage(va_display_, va_surface_id, image); |
396 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); | 538 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); |
397 if (va_res != VA_STATUS_SUCCESS) | 539 if (va_res != VA_STATUS_SUCCESS) |
398 return false; | 540 return false; |
399 | 541 |
400 // Map the VAImage into memory | 542 // Map the VAImage into memory |
401 va_res = vaMapBuffer(va_display_, image->buf, mem); | 543 va_res = vaMapBuffer(va_display_, image->buf, mem); |
402 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); | 544 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
403 if (va_res == VA_STATUS_SUCCESS) | 545 if (va_res == VA_STATUS_SUCCESS) |
404 return true; | 546 return true; |
405 | 547 |
406 vaDestroyImage(va_display_, image->image_id); | 548 va_res = vaDestroyImage(va_display_, image->image_id); |
| 549 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); |
| 550 |
407 return false; | 551 return false; |
408 } | 552 } |
409 | 553 |
410 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { | 554 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { |
411 base::AutoLock auto_lock(va_lock_); | 555 base::AutoLock auto_lock(va_lock_); |
412 | 556 |
413 vaUnmapBuffer(va_display_, image->buf); | 557 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf); |
414 vaDestroyImage(va_display_, image->image_id); | 558 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
| 559 |
| 560 va_res = vaDestroyImage(va_display_, image->image_id); |
| 561 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); |
| 562 } |
| 563 |
| 564 static void DestroyVAImage(VADisplay va_display, VAImage image) { |
| 565 if (image.image_id != VA_INVALID_ID) |
| 566 vaDestroyImage(va_display, image.image_id); |
| 567 } |
| 568 |
| 569 bool VaapiWrapper::UploadVideoFrameToSurface( |
| 570 const scoped_refptr<media::VideoFrame>& frame, |
| 571 VASurfaceID va_surface_id) { |
| 572 base::AutoLock auto_lock(va_lock_); |
| 573 |
| 574 VAImage image; |
| 575 VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image); |
| 576 VA_SUCCESS_OR_RETURN(va_res, "vaDeriveImage failed", false); |
| 577 base::ScopedClosureRunner vaimage_deleter( |
| 578 base::Bind(&DestroyVAImage, va_display_, image)); |
| 579 |
| 580 if (image.format.fourcc != VA_FOURCC_NV12) { |
| 581 DVLOG(1) << "Unsupported image format: " << image.format.fourcc; |
| 582 return false; |
| 583 } |
| 584 |
| 585 if (gfx::Rect(image.width, image.height) < gfx::Rect(frame->coded_size())) { |
| 586 DVLOG(1) << "Buffer too small to fit the frame."; |
| 587 return false; |
| 588 } |
| 589 |
| 590 void* image_ptr = NULL; |
| 591 va_res = vaMapBuffer(va_display_, image.buf, &image_ptr); |
| 592 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false); |
| 593 DCHECK(image_ptr); |
| 594 |
| 595 int ret = 0; |
| 596 { |
| 597 base::AutoUnlock auto_unlock(va_lock_); |
| 598 ret = libyuv::I420ToNV12(frame->data(media::VideoFrame::kYPlane), |
| 599 frame->stride(media::VideoFrame::kYPlane), |
| 600 frame->data(media::VideoFrame::kUPlane), |
| 601 frame->stride(media::VideoFrame::kUPlane), |
| 602 frame->data(media::VideoFrame::kVPlane), |
| 603 frame->stride(media::VideoFrame::kVPlane), |
| 604 static_cast<uint8*>(image_ptr) + image.offsets[0], |
| 605 image.pitches[0], |
| 606 static_cast<uint8*>(image_ptr) + image.offsets[1], |
| 607 image.pitches[1], |
| 608 image.width, |
| 609 image.height); |
| 610 } |
| 611 |
| 612 va_res = vaUnmapBuffer(va_display_, image.buf); |
| 613 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
| 614 |
| 615 return ret == 0; |
| 616 } |
| 617 |
| 618 bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer_id, |
| 619 VASurfaceID sync_surface_id, |
| 620 uint8* target_ptr, |
| 621 size_t target_size, |
| 622 size_t* coded_data_size) { |
| 623 base::AutoLock auto_lock(va_lock_); |
| 624 |
| 625 VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id); |
| 626 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
| 627 |
| 628 VACodedBufferSegment* buffer_segment = NULL; |
| 629 va_res = vaMapBuffer( |
| 630 va_display_, buffer_id, reinterpret_cast<void**>(&buffer_segment)); |
| 631 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false); |
| 632 DCHECK(target_ptr); |
| 633 |
| 634 { |
| 635 base::AutoUnlock auto_unlock(va_lock_); |
| 636 *coded_data_size = 0; |
| 637 |
| 638 while (buffer_segment) { |
| 639 DCHECK(buffer_segment->buf); |
| 640 |
| 641 if (buffer_segment->size > target_size) { |
| 642 DVLOG(1) << "Insufficient output buffer size"; |
| 643 break; |
| 644 } |
| 645 |
| 646 memcpy(target_ptr, buffer_segment->buf, buffer_segment->size); |
| 647 |
| 648 target_ptr += buffer_segment->size; |
| 649 *coded_data_size += buffer_segment->size; |
| 650 target_size -= buffer_segment->size; |
| 651 |
| 652 buffer_segment = |
| 653 reinterpret_cast<VACodedBufferSegment*>(buffer_segment->next); |
| 654 } |
| 655 } |
| 656 |
| 657 va_res = vaUnmapBuffer(va_display_, buffer_id); |
| 658 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
| 659 |
| 660 va_res = vaDestroyBuffer(va_display_, buffer_id); |
| 661 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
| 662 |
| 663 DCHECK(coded_buffers_.erase(buffer_id)); |
| 664 |
| 665 return buffer_segment == NULL; |
415 } | 666 } |
416 | 667 |
417 // static | 668 // static |
418 bool VaapiWrapper::PostSandboxInitialization() { | 669 bool VaapiWrapper::PostSandboxInitialization() { |
419 StubPathMap paths; | 670 StubPathMap paths; |
420 paths[kModuleVa].push_back(kVaLib); | 671 paths[kModuleVa].push_back(kVaLib); |
421 | 672 |
422 return InitializeStubs(paths); | 673 return InitializeStubs(paths); |
423 } | 674 } |
424 | 675 |
425 } // namespace content | 676 } // namespace content |
OLD | NEW |