| 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" | |
| 11 #include "base/logging.h" | 10 #include "base/logging.h" |
| 12 #include "base/numerics/safe_conversions.h" | 11 #include "base/numerics/safe_conversions.h" |
| 13 // Auto-generated for dlopen libva libraries | 12 // Auto-generated for dlopen libva libraries |
| 14 #include "content/common/gpu/media/va_stubs.h" | 13 #include "content/common/gpu/media/va_stubs.h" |
| 15 #include "third_party/libyuv/include/libyuv.h" | |
| 16 | 14 |
| 17 using content_common_gpu_media::kModuleVa; | 15 using content_common_gpu_media::kModuleVa; |
| 18 using content_common_gpu_media::InitializeStubs; | 16 using content_common_gpu_media::InitializeStubs; |
| 19 using content_common_gpu_media::StubPathMap; | 17 using content_common_gpu_media::StubPathMap; |
| 20 | 18 |
| 21 // libva-x11 depends on libva, so dlopen libva-x11 is enough | 19 // libva-x11 depends on libva, so dlopen libva-x11 is enough |
| 22 static const base::FilePath::CharType kVaLib[] = | 20 static const base::FilePath::CharType kVaLib[] = |
| 23 FILE_PATH_LITERAL("libva-x11.so.1"); | 21 FILE_PATH_LITERAL("libva-x11.so.1"); |
| 24 | 22 |
| 25 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ | 23 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \ |
| (...skipping 12 matching lines...) Expand all Loading... |
| 38 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \ | 36 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \ |
| 39 do { \ | 37 do { \ |
| 40 if ((va_error) != VA_STATUS_SUCCESS) { \ | 38 if ((va_error) != VA_STATUS_SUCCESS) { \ |
| 41 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \ | 39 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \ |
| 42 return (ret); \ | 40 return (ret); \ |
| 43 } \ | 41 } \ |
| 44 } while (0) | 42 } while (0) |
| 45 | 43 |
| 46 namespace content { | 44 namespace content { |
| 47 | 45 |
| 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 | |
| 60 // Maps Profile enum values to VaProfile values. | 46 // Maps Profile enum values to VaProfile values. |
| 61 static VAProfile ProfileToVAProfile( | 47 static VAProfile ProfileToVAProfile( |
| 62 media::VideoCodecProfile profile, | 48 media::VideoCodecProfile profile, |
| 63 const std::vector<VAProfile>& supported_profiles) { | 49 const std::vector<VAProfile>& supported_profiles) { |
| 64 | 50 |
| 65 VAProfile va_profile = VAProfileNone; | 51 VAProfile va_profile = VAProfileNone; |
| 66 | 52 |
| 67 switch (profile) { | 53 switch (profile) { |
| 68 case media::H264PROFILE_BASELINE: | 54 case media::H264PROFILE_BASELINE: |
| 69 va_profile = VAProfileH264Baseline; | 55 va_profile = VAProfileH264Baseline; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 } | 99 } |
| 114 | 100 |
| 115 VaapiWrapper::VaapiWrapper() | 101 VaapiWrapper::VaapiWrapper() |
| 116 : va_display_(NULL), | 102 : va_display_(NULL), |
| 117 va_config_id_(VA_INVALID_ID), | 103 va_config_id_(VA_INVALID_ID), |
| 118 va_context_id_(VA_INVALID_ID) { | 104 va_context_id_(VA_INVALID_ID) { |
| 119 } | 105 } |
| 120 | 106 |
| 121 VaapiWrapper::~VaapiWrapper() { | 107 VaapiWrapper::~VaapiWrapper() { |
| 122 DestroyPendingBuffers(); | 108 DestroyPendingBuffers(); |
| 123 DestroyCodedBuffers(); | |
| 124 DestroySurfaces(); | 109 DestroySurfaces(); |
| 125 Deinitialize(); | 110 Deinitialize(); |
| 126 } | 111 } |
| 127 | 112 |
| 128 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( | 113 scoped_ptr<VaapiWrapper> VaapiWrapper::Create( |
| 129 CodecMode mode, | |
| 130 media::VideoCodecProfile profile, | 114 media::VideoCodecProfile profile, |
| 131 Display* x_display, | 115 Display* x_display, |
| 132 const base::Closure& report_error_to_uma_cb) { | 116 const base::Closure& report_error_to_uma_cb) { |
| 133 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 117 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
| 134 | 118 |
| 135 if (!vaapi_wrapper->Initialize( | 119 if (!vaapi_wrapper->Initialize(profile, x_display, report_error_to_uma_cb)) |
| 136 mode, profile, x_display, report_error_to_uma_cb)) | |
| 137 vaapi_wrapper.reset(); | 120 vaapi_wrapper.reset(); |
| 138 | 121 |
| 139 return vaapi_wrapper.Pass(); | 122 return vaapi_wrapper.Pass(); |
| 140 } | 123 } |
| 141 | 124 |
| 142 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { | 125 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
| 143 VADisplayAttribute item = {VADisplayAttribRenderMode, | 126 VADisplayAttribute item = {VADisplayAttribRenderMode, |
| 144 1, // At least support '_LOCAL_OVERLAY'. | 127 1, // At least support '_LOCAL_OVERLAY'. |
| 145 -1, // The maximum possible support 'ALL'. | 128 -1, // The maximum possible support 'ALL'. |
| 146 VA_RENDER_MODE_LOCAL_GPU, | 129 VA_RENDER_MODE_LOCAL_GPU, |
| 147 VA_DISPLAY_ATTRIB_SETTABLE}; | 130 VA_DISPLAY_ATTRIB_SETTABLE}; |
| 148 | 131 |
| 149 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 132 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
| 150 if (va_res != VA_STATUS_SUCCESS) | 133 if (va_res != VA_STATUS_SUCCESS) |
| 151 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 134 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
| 152 } | 135 } |
| 153 | 136 |
| 154 bool VaapiWrapper::Initialize(CodecMode mode, | 137 bool VaapiWrapper::Initialize(media::VideoCodecProfile profile, |
| 155 media::VideoCodecProfile profile, | |
| 156 Display* x_display, | 138 Display* x_display, |
| 157 const base::Closure& report_error_to_uma_cb) { | 139 const base::Closure& report_error_to_uma_cb) { |
| 158 static bool vaapi_functions_initialized = PostSandboxInitialization(); | 140 static bool vaapi_functions_initialized = PostSandboxInitialization(); |
| 159 if (!vaapi_functions_initialized) { | 141 if (!vaapi_functions_initialized) { |
| 160 DVLOG(1) << "Failed to initialize VAAPI libs"; | 142 DVLOG(1) << "Failed to initialize VAAPI libs"; |
| 161 return false; | 143 return false; |
| 162 } | 144 } |
| 163 | 145 |
| 164 report_error_to_uma_cb_ = report_error_to_uma_cb; | 146 report_error_to_uma_cb_ = report_error_to_uma_cb; |
| 165 | 147 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 195 } | 177 } |
| 196 | 178 |
| 197 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); | 179 supported_profiles.resize(base::checked_cast<size_t>(num_supported_profiles)); |
| 198 | 180 |
| 199 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); | 181 VAProfile va_profile = ProfileToVAProfile(profile, supported_profiles); |
| 200 if (va_profile == VAProfileNone) { | 182 if (va_profile == VAProfileNone) { |
| 201 DVLOG(1) << "Unsupported profile"; | 183 DVLOG(1) << "Unsupported profile"; |
| 202 return false; | 184 return false; |
| 203 } | 185 } |
| 204 | 186 |
| 205 // Query the driver for supported entrypoints. | 187 VAConfigAttrib attrib = {VAConfigAttribRTFormat, 0}; |
| 206 int max_entrypoints = vaMaxNumEntrypoints(va_display_); | 188 const VAEntrypoint kEntrypoint = VAEntrypointVLD; |
| 207 std::vector<VAEntrypoint> supported_entrypoints( | 189 va_res = vaGetConfigAttributes(va_display_, va_profile, kEntrypoint, |
| 208 base::checked_cast<size_t>(max_entrypoints)); | 190 &attrib, 1); |
| 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()); | |
| 252 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); | 191 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); |
| 253 | 192 |
| 254 for (size_t i = 0; i < required_attribs.size(); ++i) { | 193 if (!(attrib.value & VA_RT_FORMAT_YUV420)) { |
| 255 if (attribs[i].type != required_attribs[i].type || | 194 DVLOG(1) << "YUV420 not supported by this VAAPI implementation"; |
| 256 (attribs[i].value & required_attribs[i].value) != | 195 return false; |
| 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 } | |
| 262 } | 196 } |
| 263 | 197 |
| 264 TryToSetVADisplayAttributeToLocalGPU(); | 198 TryToSetVADisplayAttributeToLocalGPU(); |
| 265 | 199 |
| 266 va_res = vaCreateConfig(va_display_, | 200 va_res = vaCreateConfig(va_display_, va_profile, kEntrypoint, |
| 267 va_profile, | 201 &attrib, 1, &va_config_id_); |
| 268 entrypoint, | |
| 269 &required_attribs[0], | |
| 270 required_attribs.size(), | |
| 271 &va_config_id_); | |
| 272 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | 202 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); |
| 273 | 203 |
| 274 return true; | 204 return true; |
| 275 } | 205 } |
| 276 | 206 |
| 277 void VaapiWrapper::Deinitialize() { | 207 void VaapiWrapper::Deinitialize() { |
| 278 base::AutoLock auto_lock(va_lock_); | 208 base::AutoLock auto_lock(va_lock_); |
| 279 | 209 |
| 280 if (va_config_id_ != VA_INVALID_ID) { | 210 if (va_config_id_ != VA_INVALID_ID) { |
| 281 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 211 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 | 292 |
| 363 VABufferID buffer_id; | 293 VABufferID buffer_id; |
| 364 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, | 294 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, |
| 365 va_buffer_type, size, | 295 va_buffer_type, size, |
| 366 1, buffer, &buffer_id); | 296 1, buffer, &buffer_id); |
| 367 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); | 297 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); |
| 368 | 298 |
| 369 switch (va_buffer_type) { | 299 switch (va_buffer_type) { |
| 370 case VASliceParameterBufferType: | 300 case VASliceParameterBufferType: |
| 371 case VASliceDataBufferType: | 301 case VASliceDataBufferType: |
| 372 case VAEncSliceParameterBufferType: | |
| 373 pending_slice_bufs_.push_back(buffer_id); | 302 pending_slice_bufs_.push_back(buffer_id); |
| 374 break; | 303 break; |
| 375 | 304 |
| 376 default: | 305 default: |
| 377 pending_va_bufs_.push_back(buffer_id); | 306 pending_va_bufs_.push_back(buffer_id); |
| 378 break; | 307 break; |
| 379 } | 308 } |
| 380 | 309 |
| 381 return true; | 310 return true; |
| 382 } | 311 } |
| 383 | 312 |
| 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 | |
| 421 void VaapiWrapper::DestroyPendingBuffers() { | 313 void VaapiWrapper::DestroyPendingBuffers() { |
| 422 base::AutoLock auto_lock(va_lock_); | 314 base::AutoLock auto_lock(va_lock_); |
| 423 | 315 |
| 424 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { | 316 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { |
| 425 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); | 317 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); |
| 426 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 318 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
| 427 } | 319 } |
| 428 | 320 |
| 429 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { | 321 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { |
| 430 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); | 322 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); |
| 431 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 323 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
| 432 } | 324 } |
| 433 | 325 |
| 434 pending_va_bufs_.clear(); | 326 pending_va_bufs_.clear(); |
| 435 pending_slice_bufs_.clear(); | 327 pending_slice_bufs_.clear(); |
| 436 } | 328 } |
| 437 | 329 |
| 438 bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) { | 330 bool VaapiWrapper::SubmitDecode(VASurfaceID va_surface_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) { | |
| 467 base::AutoLock auto_lock(va_lock_); | 331 base::AutoLock auto_lock(va_lock_); |
| 468 | 332 |
| 469 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); | 333 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); |
| 470 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); | 334 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); |
| 471 DVLOG(4) << "Target VA surface " << va_surface_id; | 335 DVLOG(4) << "Decoding into VA surface " << va_surface_id; |
| 472 | 336 |
| 473 // Get ready to execute for given surface. | 337 // Get ready to decode into surface. |
| 474 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, | 338 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, |
| 475 va_surface_id); | 339 va_surface_id); |
| 476 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); | 340 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); |
| 477 | 341 |
| 478 if (pending_va_bufs_.size() > 0) { | 342 // Commit parameter and slice buffers. |
| 479 // Commit parameter and slice buffers. | 343 va_res = vaRenderPicture(va_display_, va_context_id_, |
| 480 va_res = vaRenderPicture(va_display_, | 344 &pending_va_bufs_[0], pending_va_bufs_.size()); |
| 481 va_context_id_, | 345 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); |
| 482 &pending_va_bufs_[0], | |
| 483 pending_va_bufs_.size()); | |
| 484 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | |
| 485 } | |
| 486 | 346 |
| 487 if (pending_slice_bufs_.size() > 0) { | 347 va_res = vaRenderPicture(va_display_, va_context_id_, |
| 488 va_res = vaRenderPicture(va_display_, | 348 &pending_slice_bufs_[0], |
| 489 va_context_id_, | 349 pending_slice_bufs_.size()); |
| 490 &pending_slice_bufs_[0], | 350 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); |
| 491 pending_slice_bufs_.size()); | |
| 492 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | |
| 493 } | |
| 494 | 351 |
| 495 // Instruct HW codec to start processing committed buffers. | 352 // Instruct HW decoder to start processing committed buffers (decode this |
| 496 // Does not block and the job is not finished after this returns. | 353 // picture). This does not block until the end of decode. |
| 497 va_res = vaEndPicture(va_display_, va_context_id_); | 354 va_res = vaEndPicture(va_display_, va_context_id_); |
| 498 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); | 355 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); |
| 499 | 356 |
| 500 return true; | 357 return true; |
| 501 } | 358 } |
| 502 | 359 |
| 503 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { | 360 bool VaapiWrapper::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) { |
| 504 bool result = Execute(va_surface_id); | 361 bool result = SubmitDecode(va_surface_id); |
| 505 DestroyPendingBuffers(); | 362 DestroyPendingBuffers(); |
| 506 return result; | 363 return result; |
| 507 } | 364 } |
| 508 | 365 |
| 509 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, | 366 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, |
| 510 Pixmap x_pixmap, | 367 Pixmap x_pixmap, |
| 511 gfx::Size dest_size) { | 368 gfx::Size dest_size) { |
| 512 base::AutoLock auto_lock(va_lock_); | 369 base::AutoLock auto_lock(va_lock_); |
| 513 | 370 |
| 514 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 371 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
| 515 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 372 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
| 516 | 373 |
| 517 // Put the data into an X Pixmap. | 374 // Put the data into an X Pixmap. |
| 518 va_res = vaPutSurface(va_display_, | 375 va_res = vaPutSurface(va_display_, |
| 519 va_surface_id, | 376 va_surface_id, |
| 520 x_pixmap, | 377 x_pixmap, |
| 521 0, 0, dest_size.width(), dest_size.height(), | 378 0, 0, dest_size.width(), dest_size.height(), |
| 522 0, 0, dest_size.width(), dest_size.height(), | 379 0, 0, dest_size.width(), dest_size.height(), |
| 523 NULL, 0, 0); | 380 NULL, 0, 0); |
| 524 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); | 381 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decode surface to pixmap", |
| 382 false); |
| 525 return true; | 383 return true; |
| 526 } | 384 } |
| 527 | 385 |
| 528 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, | 386 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, |
| 529 VAImage* image, | 387 VAImage* image, |
| 530 void** mem) { | 388 void** mem) { |
| 531 base::AutoLock auto_lock(va_lock_); | 389 base::AutoLock auto_lock(va_lock_); |
| 532 | 390 |
| 533 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 391 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
| 534 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 392 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
| 535 | 393 |
| 536 // Derive a VAImage from the VASurface | 394 // Derive a VAImage from the VASurface |
| 537 va_res = vaDeriveImage(va_display_, va_surface_id, image); | 395 va_res = vaDeriveImage(va_display_, va_surface_id, image); |
| 538 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); | 396 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); |
| 539 if (va_res != VA_STATUS_SUCCESS) | 397 if (va_res != VA_STATUS_SUCCESS) |
| 540 return false; | 398 return false; |
| 541 | 399 |
| 542 // Map the VAImage into memory | 400 // Map the VAImage into memory |
| 543 va_res = vaMapBuffer(va_display_, image->buf, mem); | 401 va_res = vaMapBuffer(va_display_, image->buf, mem); |
| 544 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); | 402 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
| 545 if (va_res == VA_STATUS_SUCCESS) | 403 if (va_res == VA_STATUS_SUCCESS) |
| 546 return true; | 404 return true; |
| 547 | 405 |
| 548 va_res = vaDestroyImage(va_display_, image->image_id); | 406 vaDestroyImage(va_display_, image->image_id); |
| 549 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); | |
| 550 | |
| 551 return false; | 407 return false; |
| 552 } | 408 } |
| 553 | 409 |
| 554 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { | 410 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { |
| 555 base::AutoLock auto_lock(va_lock_); | 411 base::AutoLock auto_lock(va_lock_); |
| 556 | 412 |
| 557 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf); | 413 vaUnmapBuffer(va_display_, image->buf); |
| 558 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | 414 vaDestroyImage(va_display_, image->image_id); |
| 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; | |
| 666 } | 415 } |
| 667 | 416 |
| 668 // static | 417 // static |
| 669 bool VaapiWrapper::PostSandboxInitialization() { | 418 bool VaapiWrapper::PostSandboxInitialization() { |
| 670 StubPathMap paths; | 419 StubPathMap paths; |
| 671 paths[kModuleVa].push_back(kVaLib); | 420 paths[kModuleVa].push_back(kVaLib); |
| 672 | 421 |
| 673 return InitializeStubs(paths); | 422 return InitializeStubs(paths); |
| 674 } | 423 } |
| 675 | 424 |
| 676 } // namespace content | 425 } // namespace content |
| OLD | NEW |