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}, | |
wuchengli
2014/06/17 14:33:12
I'm curious. What does RT stand for?
Pawel Osciak
2014/06/18 07:05:08
My guess is raw texture, but I may be wrong.
| |
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: " | |
wuchengli
2014/06/17 14:33:12
Doesn't this mean something is wrong? LOG(WARNING)
Pawel Osciak
2014/06/18 07:05:08
LOG() would also show up in release. This goes bac
| |
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"; | |
wuchengli
2014/06/17 14:33:12
print |entrypoint|?
Pawel Osciak
2014/06/18 07:05:08
Done.
| |
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, | |
wuchengli
2014/06/17 14:33:12
This can be inserted by constructor.
Pawel Osciak
2014/06/18 07:05:09
It'd have to be a member, but we don't really need
| |
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; | |
wuchengli
2014/06/17 14:33:12
nit: the constructor can take a vector. Not sure w
Pawel Osciak
2014/06/18 07:05:09
In C++ assignment on definition calls the copy con
| |
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 || |
wuchengli
2014/06/17 14:33:12
No need to compare the type according to the funct
Pawel Osciak
2014/06/18 07:05:09
Yes, but I'd still prefer to keep this.
| |
195 return false; | 256 !(attribs[i].value & required_attribs[i].value)) { |
wuchengli
2014/06/17 14:33:12
Should be (attribs[i].value & required_attribs[i].
Pawel Osciak
2014/06/18 07:05:09
Good catch.
| |
257 DVLOG(1) << "Unsupported value " << required_attribs[i].value | |
258 << " for attribute type " << required_attribs[i].type; | |
259 return false; | |
260 } | |
196 } | 261 } |
197 | 262 |
198 TryToSetVADisplayAttributeToLocalGPU(); | 263 TryToSetVADisplayAttributeToLocalGPU(); |
199 | 264 |
200 va_res = vaCreateConfig(va_display_, va_profile, kEntrypoint, | 265 va_res = vaCreateConfig(va_display_, |
201 &attrib, 1, &va_config_id_); | 266 va_profile, |
267 entrypoint, | |
268 &required_attribs[0], | |
269 required_attribs.size(), | |
270 &va_config_id_); | |
202 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | 271 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); |
203 | 272 |
204 return true; | 273 return true; |
205 } | 274 } |
206 | 275 |
207 void VaapiWrapper::Deinitialize() { | 276 void VaapiWrapper::Deinitialize() { |
208 base::AutoLock auto_lock(va_lock_); | 277 base::AutoLock auto_lock(va_lock_); |
209 | 278 |
210 if (va_config_id_ != VA_INVALID_ID) { | 279 if (va_config_id_ != VA_INVALID_ID) { |
211 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 280 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 | 361 |
293 VABufferID buffer_id; | 362 VABufferID buffer_id; |
294 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, | 363 VAStatus va_res = vaCreateBuffer(va_display_, va_context_id_, |
295 va_buffer_type, size, | 364 va_buffer_type, size, |
296 1, buffer, &buffer_id); | 365 1, buffer, &buffer_id); |
297 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); | 366 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); |
298 | 367 |
299 switch (va_buffer_type) { | 368 switch (va_buffer_type) { |
300 case VASliceParameterBufferType: | 369 case VASliceParameterBufferType: |
301 case VASliceDataBufferType: | 370 case VASliceDataBufferType: |
371 case VAEncSliceParameterBufferType: | |
302 pending_slice_bufs_.push_back(buffer_id); | 372 pending_slice_bufs_.push_back(buffer_id); |
303 break; | 373 break; |
304 | 374 |
305 default: | 375 default: |
306 pending_va_bufs_.push_back(buffer_id); | 376 pending_va_bufs_.push_back(buffer_id); |
307 break; | 377 break; |
308 } | 378 } |
309 | 379 |
310 return true; | 380 return true; |
311 } | 381 } |
312 | 382 |
383 bool VaapiWrapper::SubmitVAEncMiscParamBuffer( | |
384 VAEncMiscParameterType misc_param_type, | |
385 size_t size, | |
386 void* buffer) { | |
387 base::AutoLock auto_lock(va_lock_); | |
388 | |
389 VABufferID buffer_id; | |
390 VAStatus va_res = vaCreateBuffer(va_display_, | |
391 va_context_id_, | |
392 VAEncMiscParameterBufferType, | |
393 sizeof(VAEncMiscParameterBuffer) + size, | |
394 1, | |
395 NULL, | |
396 &buffer_id); | |
397 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false); | |
398 | |
399 void* data_ptr = NULL; | |
400 va_res = vaMapBuffer(va_display_, buffer_id, &data_ptr); | |
401 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); | |
wuchengli
2014/06/17 14:33:12
Use LOG_VA_ERROR_AND_REPORT and move it to if clau
Pawel Osciak
2014/06/18 07:05:08
While you are right, honestly we have a lot of thi
| |
402 if (va_res != VA_STATUS_SUCCESS) { | |
403 vaDestroyBuffer(va_display_, buffer_id); | |
404 return false; | |
405 } | |
406 | |
407 DCHECK(data_ptr); | |
wuchengli
2014/06/17 14:33:13
Do we need this? The code will crash in misc_param
Pawel Osciak
2014/06/18 07:05:09
But the crash may not be as obvious.
| |
408 | |
409 VAEncMiscParameterBuffer* misc_param = | |
410 reinterpret_cast<VAEncMiscParameterBuffer*>(data_ptr); | |
411 misc_param->type = misc_param_type; | |
412 memcpy(misc_param->data, buffer, size); | |
413 va_res = vaUnmapBuffer(va_display_, buffer_id); | |
414 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | |
wuchengli
2014/06/17 14:33:12
If unmap fails, do things still work later?
Pawel Osciak
2014/06/18 07:05:08
We'll destroy the buffer anyway.
| |
415 | |
416 pending_va_bufs_.push_back(buffer_id); | |
417 return true; | |
418 } | |
419 | |
313 void VaapiWrapper::DestroyPendingBuffers() { | 420 void VaapiWrapper::DestroyPendingBuffers() { |
314 base::AutoLock auto_lock(va_lock_); | 421 base::AutoLock auto_lock(va_lock_); |
315 | 422 |
316 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { | 423 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) { |
317 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); | 424 VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_bufs_[i]); |
318 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 425 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
319 } | 426 } |
320 | 427 |
321 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { | 428 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) { |
322 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); | 429 VAStatus va_res = vaDestroyBuffer(va_display_, pending_slice_bufs_[i]); |
323 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | 430 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); |
324 } | 431 } |
325 | 432 |
326 pending_va_bufs_.clear(); | 433 pending_va_bufs_.clear(); |
327 pending_slice_bufs_.clear(); | 434 pending_slice_bufs_.clear(); |
328 } | 435 } |
329 | 436 |
330 bool VaapiWrapper::SubmitDecode(VASurfaceID va_surface_id) { | 437 bool VaapiWrapper::CreateCodedBuffer(size_t size, VABufferID* buffer_id) { |
438 base::AutoLock auto_lock(va_lock_); | |
439 VAStatus va_res = vaCreateBuffer(va_display_, | |
440 va_context_id_, | |
441 VAEncCodedBufferType, | |
442 size, | |
443 1, | |
444 NULL, | |
445 buffer_id); | |
446 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a coded buffer", false); | |
447 | |
448 DCHECK(coded_buffers_.insert(*buffer_id).second); | |
449 return true; | |
450 } | |
451 | |
452 void VaapiWrapper::DestroyCodedBuffers() { | |
wuchengli
2014/06/17 14:33:12
Need auto_lock(va_lock_) because this method is pu
Pawel Osciak
2014/06/18 07:05:09
Oh good catch. I missed it when refactoring.
| |
453 for (std::set<VABufferID>::const_iterator iter = coded_buffers_.begin(); | |
454 iter != coded_buffers_.end(); | |
455 ++iter) { | |
456 VAStatus va_res = vaDestroyBuffer(va_display_, *iter); | |
457 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
458 } | |
459 | |
460 coded_buffers_.clear(); | |
461 } | |
462 | |
463 bool VaapiWrapper::Execute(VASurfaceID va_surface_id) { | |
331 base::AutoLock auto_lock(va_lock_); | 464 base::AutoLock auto_lock(va_lock_); |
332 | 465 |
333 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); | 466 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); |
334 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); | 467 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); |
335 DVLOG(4) << "Decoding into VA surface " << va_surface_id; | 468 DVLOG(4) << "Target VA surface " << va_surface_id; |
336 | 469 |
337 // Get ready to decode into surface. | 470 // Get ready to execute for given surface. |
338 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, | 471 VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, |
339 va_surface_id); | 472 va_surface_id); |
340 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); | 473 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); |
341 | 474 |
342 // Commit parameter and slice buffers. | 475 if (pending_va_bufs_.size() > 0) { |
343 va_res = vaRenderPicture(va_display_, va_context_id_, | 476 // Commit parameter and slice buffers. |
344 &pending_va_bufs_[0], pending_va_bufs_.size()); | 477 va_res = vaRenderPicture(va_display_, |
345 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | 478 va_context_id_, |
479 &pending_va_bufs_[0], | |
480 pending_va_bufs_.size()); | |
481 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | |
482 } | |
346 | 483 |
347 va_res = vaRenderPicture(va_display_, va_context_id_, | 484 if (pending_slice_bufs_.size() > 0) { |
348 &pending_slice_bufs_[0], | 485 va_res = vaRenderPicture(va_display_, |
349 pending_slice_bufs_.size()); | 486 va_context_id_, |
350 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | 487 &pending_slice_bufs_[0], |
488 pending_slice_bufs_.size()); | |
489 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | |
490 } | |
351 | 491 |
352 // Instruct HW decoder to start processing committed buffers (decode this | 492 // Instruct HW codec to start processing committed buffers. |
353 // picture). This does not block until the end of decode. | 493 // Does not block and the job is not finished after it returns. |
wuchengli
2014/06/17 14:33:12
"after this returns" seems clearer. I think you me
Pawel Osciak
2014/06/18 07:05:09
Done.
| |
354 va_res = vaEndPicture(va_display_, va_context_id_); | 494 va_res = vaEndPicture(va_display_, va_context_id_); |
355 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); | 495 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); |
356 | 496 |
357 return true; | 497 return true; |
358 } | 498 } |
359 | 499 |
360 bool VaapiWrapper::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) { | 500 bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) { |
wuchengli
2014/06/17 14:33:12
Do we need to make sure Execute and DestroyPending
Pawel Osciak
2014/06/18 07:05:09
No.
| |
361 bool result = SubmitDecode(va_surface_id); | 501 bool result = Execute(va_surface_id); |
362 DestroyPendingBuffers(); | 502 DestroyPendingBuffers(); |
363 return result; | 503 return result; |
364 } | 504 } |
365 | 505 |
366 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, | 506 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id, |
367 Pixmap x_pixmap, | 507 Pixmap x_pixmap, |
368 gfx::Size dest_size) { | 508 gfx::Size dest_size) { |
369 base::AutoLock auto_lock(va_lock_); | 509 base::AutoLock auto_lock(va_lock_); |
370 | 510 |
371 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 511 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
372 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 512 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
373 | 513 |
374 // Put the data into an X Pixmap. | 514 // Put the data into an X Pixmap. |
375 va_res = vaPutSurface(va_display_, | 515 va_res = vaPutSurface(va_display_, |
376 va_surface_id, | 516 va_surface_id, |
377 x_pixmap, | 517 x_pixmap, |
378 0, 0, dest_size.width(), dest_size.height(), | 518 0, 0, dest_size.width(), dest_size.height(), |
379 0, 0, dest_size.width(), dest_size.height(), | 519 0, 0, dest_size.width(), dest_size.height(), |
380 NULL, 0, 0); | 520 NULL, 0, 0); |
381 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decode surface to pixmap", | 521 VA_SUCCESS_OR_RETURN(va_res, "Failed putting surface to pixmap", false); |
382 false); | |
383 return true; | 522 return true; |
384 } | 523 } |
385 | 524 |
386 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, | 525 bool VaapiWrapper::GetVaImageForTesting(VASurfaceID va_surface_id, |
387 VAImage* image, | 526 VAImage* image, |
388 void** mem) { | 527 void** mem) { |
389 base::AutoLock auto_lock(va_lock_); | 528 base::AutoLock auto_lock(va_lock_); |
390 | 529 |
391 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); | 530 VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); |
392 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | 531 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); |
393 | 532 |
394 // Derive a VAImage from the VASurface | 533 // Derive a VAImage from the VASurface |
395 va_res = vaDeriveImage(va_display_, va_surface_id, image); | 534 va_res = vaDeriveImage(va_display_, va_surface_id, image); |
396 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); | 535 VA_LOG_ON_ERROR(va_res, "vaDeriveImage failed"); |
397 if (va_res != VA_STATUS_SUCCESS) | 536 if (va_res != VA_STATUS_SUCCESS) |
wuchengli
2014/06/17 14:33:12
Can use VA_SUCCESS_OR_RETURN.
Pawel Osciak
2014/06/18 07:05:08
I think this file needs more refactoring of those
| |
398 return false; | 537 return false; |
399 | 538 |
400 // Map the VAImage into memory | 539 // Map the VAImage into memory |
401 va_res = vaMapBuffer(va_display_, image->buf, mem); | 540 va_res = vaMapBuffer(va_display_, image->buf, mem); |
402 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); | 541 VA_LOG_ON_ERROR(va_res, "vaMapBuffer failed"); |
403 if (va_res == VA_STATUS_SUCCESS) | 542 if (va_res == VA_STATUS_SUCCESS) |
404 return true; | 543 return true; |
405 | 544 |
406 vaDestroyImage(va_display_, image->image_id); | 545 va_res = vaDestroyImage(va_display_, image->image_id); |
546 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); | |
547 | |
407 return false; | 548 return false; |
408 } | 549 } |
409 | 550 |
410 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { | 551 void VaapiWrapper::ReturnVaImageForTesting(VAImage* image) { |
411 base::AutoLock auto_lock(va_lock_); | 552 base::AutoLock auto_lock(va_lock_); |
412 | 553 |
413 vaUnmapBuffer(va_display_, image->buf); | 554 VAStatus va_res = vaUnmapBuffer(va_display_, image->buf); |
414 vaDestroyImage(va_display_, image->image_id); | 555 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); |
556 | |
557 va_res = vaDestroyImage(va_display_, image->image_id); | |
558 VA_LOG_ON_ERROR(va_res, "vaDestroyImage failed"); | |
559 } | |
560 | |
561 static void DestroyVAImage(VADisplay va_display, VAImage image) { | |
562 if (image.image_id != VA_INVALID_ID) | |
wuchengli
2014/06/17 14:33:12
Should this a DCHECK or this can happen?
Pawel Osciak
2014/06/18 07:05:08
This is defensive.
| |
563 vaDestroyImage(va_display, image.image_id); | |
564 } | |
565 | |
566 bool VaapiWrapper::UploadVideoFrameToSurface( | |
567 const scoped_refptr<media::VideoFrame>& frame, | |
568 VASurfaceID va_surface_id) { | |
569 base::AutoLock auto_lock(va_lock_); | |
570 | |
571 VAImage image; | |
572 VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image); | |
573 VA_SUCCESS_OR_RETURN(va_res, "vaDeriveImage failed", false); | |
574 base::ScopedClosureRunner vaimage_deleter( | |
575 base::Bind(&DestroyVAImage, va_display_, image)); | |
576 | |
577 if (image.format.fourcc != VA_FOURCC_NV12) { | |
578 DVLOG(1) << "Unsupported image format: " << image.format.fourcc; | |
579 return false; | |
580 } | |
581 | |
582 if (gfx::Rect(image.width, image.height) < gfx::Rect(frame->coded_size())) { | |
583 DVLOG(1) << "Buffer too small to fit the frame."; | |
584 return false; | |
585 } | |
586 | |
587 void* image_ptr = NULL; | |
588 va_res = vaMapBuffer(va_display_, image.buf, &image_ptr); | |
589 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false); | |
590 DCHECK(image_ptr); | |
591 | |
592 int ret = 0; | |
593 { | |
594 base::AutoUnlock auto_unlock(va_lock_); | |
595 ret = libyuv::I420ToNV12(frame->data(media::VideoFrame::kYPlane), | |
596 frame->stride(media::VideoFrame::kYPlane), | |
597 frame->data(media::VideoFrame::kUPlane), | |
598 frame->stride(media::VideoFrame::kUPlane), | |
599 frame->data(media::VideoFrame::kVPlane), | |
600 frame->stride(media::VideoFrame::kVPlane), | |
601 static_cast<uint8*>(image_ptr) + image.offsets[0], | |
602 image.pitches[0], | |
603 static_cast<uint8*>(image_ptr) + image.offsets[1], | |
604 image.pitches[1], | |
605 image.width, | |
606 image.height); | |
607 } | |
608 | |
609 va_res = vaUnmapBuffer(va_display_, image.buf); | |
610 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | |
611 | |
612 return ret == 0; | |
613 } | |
614 | |
615 bool VaapiWrapper::DownloadAndDestroyCodedBuffer(VABufferID buffer, | |
wuchengli
2014/06/17 14:33:12
buffer_id for consistency
Pawel Osciak
2014/06/18 07:05:08
Done.
| |
616 VASurfaceID sync_surface_id, | |
617 uint8* target_ptr, | |
618 size_t target_size, | |
619 size_t* coded_data_size) { | |
620 base::AutoLock auto_lock(va_lock_); | |
621 | |
622 VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id); | |
623 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false); | |
624 | |
625 VACodedBufferSegment* buffer_segment = NULL; | |
626 va_res = vaMapBuffer( | |
627 va_display_, buffer, reinterpret_cast<void**>(&buffer_segment)); | |
628 VA_SUCCESS_OR_RETURN(va_res, "vaMapBuffer failed", false); | |
629 DCHECK(target_ptr); | |
630 | |
631 { | |
632 base::AutoUnlock auto_unlock(va_lock_); | |
633 *coded_data_size = 0; | |
634 | |
635 while (buffer_segment) { | |
636 DCHECK(buffer_segment->buf); | |
637 | |
638 if (buffer_segment->size > target_size) { | |
639 DVLOG(1) << "Insufficient output buffer size"; | |
640 break; | |
641 } | |
642 | |
643 memcpy(target_ptr, buffer_segment->buf, buffer_segment->size); | |
644 | |
645 target_ptr += buffer_segment->size; | |
646 *coded_data_size += buffer_segment->size; | |
647 target_size -= buffer_segment->size; | |
648 | |
649 buffer_segment = | |
650 reinterpret_cast<VACodedBufferSegment*>(buffer_segment->next); | |
651 } | |
652 } | |
653 | |
654 va_res = vaUnmapBuffer(va_display_, buffer); | |
655 VA_LOG_ON_ERROR(va_res, "vaUnmapBuffer failed"); | |
656 | |
657 va_res = vaDestroyBuffer(va_display_, buffer); | |
658 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
659 | |
660 DCHECK(coded_buffers_.erase(buffer)); | |
661 | |
662 return buffer_segment == NULL; | |
415 } | 663 } |
416 | 664 |
417 // static | 665 // static |
418 bool VaapiWrapper::PostSandboxInitialization() { | 666 bool VaapiWrapper::PostSandboxInitialization() { |
419 StubPathMap paths; | 667 StubPathMap paths; |
420 paths[kModuleVa].push_back(kVaLib); | 668 paths[kModuleVa].push_back(kVaLib); |
421 | 669 |
422 return InitializeStubs(paths); | 670 return InitializeStubs(paths); |
423 } | 671 } |
424 | 672 |
425 } // namespace content | 673 } // namespace content |
OLD | NEW |