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 |