Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: content/common/gpu/media/vaapi_wrapper.cc

Issue 333253002: Add VaapiVideoEncodeAccelerator for HW-accelerated video encode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698