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

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

Issue 14914009: VAVDA: Redesign stage 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add CONTENT_EXPORT to VaapiWrapper Created 7 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
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <dlfcn.h>
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "content/common/gpu/media/vaapi_wrapper.h"
10
11 #define LOG_VA_ERROR_AND_REPORT(va_error, err_msg) \
12 do { \
13 DVLOG(1) << err_msg \
14 << " VA error: " << VAAPI_ErrorStr(va_error); \
15 report_error_to_uma_cb_.Run(); \
16 } while (0)
17
18 #define VA_LOG_ON_ERROR(va_error, err_msg) \
19 do { \
20 if ((va_error) != VA_STATUS_SUCCESS) \
21 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
22 } while (0)
23
24 #define VA_SUCCESS_OR_RETURN(va_error, err_msg, ret) \
25 do { \
26 if ((va_error) != VA_STATUS_SUCCESS) { \
27 LOG_VA_ERROR_AND_REPORT(va_error, err_msg); \
28 return (ret); \
29 } \
30 } while (0)
31
32 namespace content {
33
34 static void *vaapi_handle = NULL;
35 static void *vaapi_x11_handle = NULL;
36
37 typedef VAStatus (*VaapiBeginPicture)(VADisplay dpy,
38 VAContextID context,
39 VASurfaceID render_target);
40 typedef VAStatus (*VaapiCreateBuffer)(VADisplay dpy,
41 VAContextID context,
42 VABufferType type,
43 unsigned int size,
44 unsigned int num_elements,
45 void *data,
46 VABufferID *buf_id);
47 typedef VAStatus (*VaapiCreateConfig)(VADisplay dpy,
48 VAProfile profile,
49 VAEntrypoint entrypoint,
50 VAConfigAttrib *attrib_list,
51 int num_attribs,
52 VAConfigID *config_id);
53 typedef VAStatus (*VaapiCreateContext)(VADisplay dpy,
54 VAConfigID config_id,
55 int picture_width,
56 int picture_height,
57 int flag,
58 VASurfaceID *render_targets,
59 int num_render_targets,
60 VAContextID *context);
61 typedef VAStatus (*VaapiCreateSurfaces)(VADisplay dpy,
62 int width,
63 int height,
64 int format,
65 int num_surfaces,
66 VASurfaceID *surfaces);
67 typedef VAStatus (*VaapiDestroyBuffer)(VADisplay dpy, VABufferID buffer_id);
68 typedef VAStatus (*VaapiDestroyConfig)(VADisplay dpy, VAConfigID config_id);
69 typedef VAStatus (*VaapiDestroyContext)(VADisplay dpy, VAContextID context);
70 typedef VAStatus (*VaapiDestroySurfaces)(VADisplay dpy,
71 VASurfaceID *surfaces,
72 int num_surfaces);
73 typedef int (*VaapiDisplayIsValid)(VADisplay dpy);
74 typedef VAStatus (*VaapiEndPicture)(VADisplay dpy, VAContextID context);
75 typedef const char* (*VaapiErrorStr)(VAStatus error_status);
76 typedef VAStatus (*VaapiGetConfigAttributes)(VADisplay dpy,
77 VAProfile profile,
78 VAEntrypoint entrypoint,
79 VAConfigAttrib *attrib_list,
80 int num_attribs);
81 typedef VADisplay (*VaapiGetDisplay)(Display *dpy);
82 typedef VAStatus (*VaapiInitialize)(VADisplay dpy,
83 int *major_version,
84 int *minor_version);
85 typedef VAStatus (*VaapiPutSurface)(VADisplay dpy,
86 VASurfaceID surface,
87 Drawable draw,
88 short srcx,
89 short srcy,
90 unsigned short srcw,
91 unsigned short srch,
92 short destx,
93 short desty,
94 unsigned short destw,
95 unsigned short desth,
96 VARectangle *cliprects,
97 unsigned int number_cliprects,
98 unsigned int flags);
99 typedef VAStatus (*VaapiRenderPicture)(VADisplay dpy,
100 VAContextID context,
101 VABufferID *buffers,
102 int num_buffers);
103 typedef VAStatus (*VaapiSyncSurface)(VADisplay dpy, VASurfaceID render_target);
104 typedef VAStatus (*VaapiTerminate)(VADisplay dpy);
105
106 #define VAAPI_SYM(name, handle) Vaapi##name VAAPI_##name = NULL
107
108 VAAPI_SYM(BeginPicture, vaapi_handle);
109 VAAPI_SYM(CreateBuffer, vaapi_handle);
110 VAAPI_SYM(CreateConfig, vaapi_handle);
111 VAAPI_SYM(CreateContext, vaapi_handle);
112 VAAPI_SYM(CreateSurfaces, vaapi_handle);
113 VAAPI_SYM(DestroyBuffer, vaapi_handle);
114 VAAPI_SYM(DestroyConfig, vaapi_handle);
115 VAAPI_SYM(DestroyContext, vaapi_handle);
116 VAAPI_SYM(DestroySurfaces, vaapi_handle);
117 VAAPI_SYM(DisplayIsValid, vaapi_handle);
118 VAAPI_SYM(EndPicture, vaapi_handle);
119 VAAPI_SYM(ErrorStr, vaapi_handle);
120 VAAPI_SYM(GetConfigAttributes, vaapi_handle);
121 VAAPI_SYM(GetDisplay, vaapi_x11_handle);
122 VAAPI_SYM(Initialize, vaapi_handle);
123 VAAPI_SYM(PutSurface, vaapi_x11_handle);
124 VAAPI_SYM(RenderPicture, vaapi_handle);
125 VAAPI_SYM(SyncSurface, vaapi_x11_handle);
126 VAAPI_SYM(Terminate, vaapi_handle);
127
128 #undef VAAPI_SYM
129
130 // Maps Profile enum values to VaProfile values.
131 static bool ProfileToVAProfile(media::VideoCodecProfile profile,
132 VAProfile* va_profile) {
133 switch (profile) {
134 case media::H264PROFILE_BASELINE:
135 *va_profile = VAProfileH264Baseline;
136 break;
137 case media::H264PROFILE_MAIN:
138 *va_profile = VAProfileH264Main;
139 break;
140 // TODO(posciak): See if we can/want support other variants
141 // of media::H264PROFILE_HIGH*.
142 case media::H264PROFILE_HIGH:
143 *va_profile = VAProfileH264High;
144 break;
145 default:
146 return false;
147 }
148 return true;
149 }
150
151 VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb)
152 : va_surface_id_(va_surface_id),
153 release_cb_(release_cb) {
154 DCHECK(!release_cb_.is_null());
155 }
156
157 VASurface::~VASurface() {
158 release_cb_.Run(va_surface_id_);
159 }
160
161 VaapiWrapper::VaapiWrapper()
162 : va_display_(NULL),
163 va_config_id_(VA_INVALID_ID),
164 va_context_id_(VA_INVALID_ID) {
165 }
166
167 VaapiWrapper::~VaapiWrapper() {
168 DestroyPendingBuffers();
169 DestroySurfaces();
170 Deinitialize();
171 }
172
173 scoped_ptr<VaapiWrapper> VaapiWrapper::Create(
174 media::VideoCodecProfile profile,
175 Display* x_display,
176 const base::Closure& report_error_to_uma_cb) {
177 scoped_ptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper());
178
179 if (!vaapi_wrapper->Initialize(profile, x_display, report_error_to_uma_cb))
180 vaapi_wrapper.reset();
181
182 return vaapi_wrapper.Pass();
183 }
184
185 bool VaapiWrapper::Initialize(media::VideoCodecProfile profile,
186 Display* x_display,
187 const base::Closure& report_error_to_uma_cb) {
188 static bool vaapi_functions_initialized = PostSandboxInitialization();
189 if (!vaapi_functions_initialized) {
190 DVLOG(1) << "Failed to initialize VAAPI libs";
191 return false;
192 }
193
194 report_error_to_uma_cb_ = report_error_to_uma_cb;
195
196 base::AutoLock auto_lock(va_lock_);
197
198 VAProfile va_profile;
199 if (!ProfileToVAProfile(profile, &va_profile)) {
200 DVLOG(1) << "Unsupported profile";
201 return false;
202 }
203
204 va_display_ = VAAPI_GetDisplay(x_display);
205 if (!VAAPI_DisplayIsValid(va_display_)) {
206 DVLOG(1) << "Could not get a valid VA display";
207 return false;
208 }
209
210 int major_version, minor_version;
211 VAStatus va_res;
212 va_res = VAAPI_Initialize(va_display_, &major_version, &minor_version);
213 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
214 DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version;
215
216 VAConfigAttrib attrib = {VAConfigAttribRTFormat, 0};
217
218 const VAEntrypoint kEntrypoint = VAEntrypointVLD;
219 va_res = VAAPI_GetConfigAttributes(va_display_, va_profile, kEntrypoint,
220 &attrib, 1);
221 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
222
223 if (!(attrib.value & VA_RT_FORMAT_YUV420)) {
224 DVLOG(1) << "YUV420 not supported by this VAAPI implementation";
225 return false;
226 }
227
228 va_res = VAAPI_CreateConfig(va_display_, va_profile, kEntrypoint,
229 &attrib, 1, &va_config_id_);
230 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
231
232 return true;
233 }
234
235 void VaapiWrapper::Deinitialize() {
236 base::AutoLock auto_lock(va_lock_);
237
238 if (va_config_id_ != VA_INVALID_ID) {
239 VAStatus va_res = VAAPI_DestroyConfig(va_display_, va_config_id_);
240 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
241 }
242
243 if (va_display_) {
244 VAStatus va_res = VAAPI_Terminate(va_display_);
245 VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
246 }
247
248 va_config_id_ = VA_INVALID_ID;
249 va_display_ = NULL;
250 }
251
252 bool VaapiWrapper::CreateSurfaces(gfx::Size size,
253 size_t num_surfaces,
254 std::vector<VASurfaceID>* va_surfaces) {
255 base::AutoLock auto_lock(va_lock_);
256
257 DCHECK(va_surfaces->empty());
258 DCHECK(va_surface_ids_.empty());
259 va_surface_ids_.resize(num_surfaces);
260
261 // Allocate surfaces in driver.
262 VAStatus va_res = VAAPI_CreateSurfaces(va_display_,
263 size.width(), size.height(),
264 VA_RT_FORMAT_YUV420,
265 va_surface_ids_.size(),
266 &va_surface_ids_[0]);
267 VA_LOG_ON_ERROR(va_res, "vaCreateSurfaces failed");
268 if (va_res != VA_STATUS_SUCCESS) {
269 va_surface_ids_.clear();
270 return false;
271 }
272
273 // And create a context associated with them.
274 va_res = VAAPI_CreateContext(va_display_, va_config_id_,
275 size.width(), size.height(), VA_PROGRESSIVE,
276 &va_surface_ids_[0], va_surface_ids_.size(),
277 &va_context_id_);
278
279 VA_LOG_ON_ERROR(va_res, "vaCreateContext failed");
280 if (va_res != VA_STATUS_SUCCESS) {
281 DestroySurfaces();
282 return false;
283 }
284
285 *va_surfaces = va_surface_ids_;
286 return true;
287 }
288
289 void VaapiWrapper::DestroySurfaces() {
290 base::AutoLock auto_lock(va_lock_);
291
292 if (va_context_id_ != VA_INVALID_ID) {
293 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_);
294 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed");
295 }
296
297 if (!va_surface_ids_.empty()) {
298 VAStatus va_res = VAAPI_DestroySurfaces(va_display_, &va_surface_ids_[0],
299 va_surface_ids_.size());
300 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed");
301 }
302
303 va_surface_ids_.clear();
304 va_context_id_ = VA_INVALID_ID;
305 }
306
307 bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
308 size_t size,
309 void* buffer) {
310 base::AutoLock auto_lock(va_lock_);
311
312 VABufferID buffer_id;
313 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
314 va_buffer_type, size,
315 1, buffer, &buffer_id);
316 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
317
318 switch (va_buffer_type) {
319 case VASliceParameterBufferType:
320 case VASliceDataBufferType:
321 pending_slice_bufs_.push_back(buffer_id);
322 break;
323
324 default:
325 pending_va_bufs_.push_back(buffer_id);
326 break;
327 }
328
329 return true;
330 }
331
332 void VaapiWrapper::DestroyPendingBuffers() {
333 base::AutoLock auto_lock(va_lock_);
334
335 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) {
336 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, pending_va_bufs_[i]);
337 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
338 }
339
340 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) {
341 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, pending_slice_bufs_[i]);
342 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
343 }
344
345 pending_va_bufs_.clear();
346 pending_slice_bufs_.clear();
347 }
348
349 bool VaapiWrapper::SubmitDecode(VASurfaceID va_surface_id) {
350 base::AutoLock auto_lock(va_lock_);
351
352 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
353 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
354 DVLOG(4) << "Decoding into VA surface " << va_surface_id;
355
356 // Get ready to decode into surface.
357 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_,
358 va_surface_id);
359 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false);
360
361 // Commit parameter and slice buffers.
362 va_res = VAAPI_RenderPicture(va_display_, va_context_id_,
363 &pending_va_bufs_[0], pending_va_bufs_.size());
364 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false);
365
366 va_res = VAAPI_RenderPicture(va_display_, va_context_id_,
367 &pending_slice_bufs_[0],
368 pending_slice_bufs_.size());
369 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false);
370
371 // Instruct HW decoder to start processing committed buffers (decode this
372 // picture). This does not block until the end of decode.
373 va_res = VAAPI_EndPicture(va_display_, va_context_id_);
374 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false);
375
376 return true;
377 }
378
379 bool VaapiWrapper::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
380 bool result = SubmitDecode(va_surface_id);
381 DestroyPendingBuffers();
382 return result;
383 }
384
385 bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
386 Pixmap x_pixmap,
387 gfx::Size dest_size) {
388 base::AutoLock auto_lock(va_lock_);
389
390 VAStatus va_res = VAAPI_SyncSurface(va_display_, va_surface_id);
391 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
392
393 // Put the data into an X Pixmap.
394 va_res = VAAPI_PutSurface(va_display_,
395 va_surface_id,
396 x_pixmap,
397 0, 0, dest_size.width(), dest_size.height(),
398 0, 0, dest_size.width(), dest_size.height(),
399 NULL, 0, 0);
400 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decode surface to pixmap",
401 false);
402 return true;
403 }
404
405 // static
406 bool VaapiWrapper::pre_sandbox_init_done_ = false;
407
408 // static
409 void VaapiWrapper::PreSandboxInitialization() {
410 DCHECK(!pre_sandbox_init_done_);
411 vaapi_handle = dlopen("libva.so", RTLD_NOW);
412 vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW);
413 pre_sandbox_init_done_ = vaapi_handle && vaapi_x11_handle;
414 }
415
416 // static
417 bool VaapiWrapper::PostSandboxInitialization() {
418 if (!pre_sandbox_init_done_)
419 return false;
420 #define VAAPI_DLSYM_OR_RETURN_ON_ERROR(name, handle) \
421 do { \
422 VAAPI_##name = reinterpret_cast<Vaapi##name>(dlsym((handle), "va"#name)); \
423 if (VAAPI_##name == NULL) { \
424 DVLOG(1) << "Failed to dlsym va"#name; \
425 return false; \
426 } \
427 } while (0)
428
429 VAAPI_DLSYM_OR_RETURN_ON_ERROR(BeginPicture, vaapi_handle);
430 VAAPI_DLSYM_OR_RETURN_ON_ERROR(CreateBuffer, vaapi_handle);
431 VAAPI_DLSYM_OR_RETURN_ON_ERROR(CreateConfig, vaapi_handle);
432 VAAPI_DLSYM_OR_RETURN_ON_ERROR(CreateContext, vaapi_handle);
433 VAAPI_DLSYM_OR_RETURN_ON_ERROR(CreateSurfaces, vaapi_handle);
434 VAAPI_DLSYM_OR_RETURN_ON_ERROR(DestroyBuffer, vaapi_handle);
435 VAAPI_DLSYM_OR_RETURN_ON_ERROR(DestroyConfig, vaapi_handle);
436 VAAPI_DLSYM_OR_RETURN_ON_ERROR(DestroyContext, vaapi_handle);
437 VAAPI_DLSYM_OR_RETURN_ON_ERROR(DestroySurfaces, vaapi_handle);
438 VAAPI_DLSYM_OR_RETURN_ON_ERROR(DisplayIsValid, vaapi_handle);
439 VAAPI_DLSYM_OR_RETURN_ON_ERROR(EndPicture, vaapi_handle);
440 VAAPI_DLSYM_OR_RETURN_ON_ERROR(ErrorStr, vaapi_handle);
441 VAAPI_DLSYM_OR_RETURN_ON_ERROR(GetConfigAttributes, vaapi_handle);
442 VAAPI_DLSYM_OR_RETURN_ON_ERROR(GetDisplay, vaapi_x11_handle);
443 VAAPI_DLSYM_OR_RETURN_ON_ERROR(Initialize, vaapi_handle);
444 VAAPI_DLSYM_OR_RETURN_ON_ERROR(PutSurface, vaapi_x11_handle);
445 VAAPI_DLSYM_OR_RETURN_ON_ERROR(RenderPicture, vaapi_handle);
446 VAAPI_DLSYM_OR_RETURN_ON_ERROR(SyncSurface, vaapi_x11_handle);
447 VAAPI_DLSYM_OR_RETURN_ON_ERROR(Terminate, vaapi_handle);
448 #undef VAAPI_DLSYM
449
450 return true;
451 }
452
453 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/vaapi_wrapper.h ('k') | content/common/gpu/media/video_decode_accelerator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698