| 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 |