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

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

Issue 14914009: VAVDA: Redesign stage 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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_delegate.h"
10
11 #define LOG_VA_ERROR_AND_REPORT(va_res, err_msg) \
12 do { \
13 DVLOG(1) << err_msg \
14 << " VA error: " << VAAPI_ErrorStr(va_res); \
15 report_error_to_uma_cb_.Run(); \
16 } while (0)
17
18 #define VA_LOG_ON_ERROR(va_res, err_msg) \
19 do { \
20 if ((va_res) != VA_STATUS_SUCCESS) \
21 LOG_VA_ERROR_AND_REPORT(va_res, err_msg); \
22 } while (0)
23
24 #define VA_SUCCESS_OR_RETURN(va_res, err_msg, ret) \
25 do { \
26 if ((va_res) != VA_STATUS_SUCCESS) { \
27 LOG_VA_ERROR_AND_REPORT(va_res, 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 VADisplay (*VaapiGetDisplay)(Display *dpy);
38 typedef int (*VaapiDisplayIsValid)(VADisplay dpy);
39 typedef VAStatus (*VaapiInitialize)(VADisplay dpy,
40 int *major_version,
41 int *minor_version);
42 typedef VAStatus (*VaapiTerminate)(VADisplay dpy);
43 typedef VAStatus (*VaapiGetConfigAttributes)(VADisplay dpy,
44 VAProfile profile,
45 VAEntrypoint entrypoint,
46 VAConfigAttrib *attrib_list,
47 int num_attribs);
48 typedef VAStatus (*VaapiCreateConfig)(VADisplay dpy,
49 VAProfile profile,
50 VAEntrypoint entrypoint,
51 VAConfigAttrib *attrib_list,
52 int num_attribs,
53 VAConfigID *config_id);
54 typedef VAStatus (*VaapiDestroyConfig)(VADisplay dpy, VAConfigID config_id);
55 typedef VAStatus (*VaapiCreateSurfaces)(VADisplay dpy,
56 int width,
57 int height,
58 int format,
59 int num_surfaces,
60 VASurfaceID *surfaces);
61 typedef VAStatus (*VaapiDestroySurfaces)(VADisplay dpy,
62 VASurfaceID *surfaces,
63 int num_surfaces);
64 typedef VAStatus (*VaapiCreateContext)(VADisplay dpy,
65 VAConfigID config_id,
66 int picture_width,
67 int picture_height,
68 int flag,
69 VASurfaceID *render_targets,
70 int num_render_targets,
71 VAContextID *context);
72 typedef VAStatus (*VaapiDestroyContext)(VADisplay dpy, VAContextID context);
73 typedef VAStatus (*VaapiPutSurface)(VADisplay dpy,
74 VASurfaceID surface,
75 Drawable draw,
76 short srcx,
77 short srcy,
78 unsigned short srcw,
79 unsigned short srch,
80 short destx,
81 short desty,
82 unsigned short destw,
83 unsigned short desth,
84 VARectangle *cliprects,
85 unsigned int number_cliprects,
86 unsigned int flags);
87 typedef VAStatus (*VaapiSyncSurface)(VADisplay dpy, VASurfaceID render_target);
88 typedef VAStatus (*VaapiBeginPicture)(VADisplay dpy,
89 VAContextID context,
90 VASurfaceID render_target);
91 typedef VAStatus (*VaapiRenderPicture)(VADisplay dpy,
92 VAContextID context,
93 VABufferID *buffers,
94 int num_buffers);
95 typedef VAStatus (*VaapiEndPicture)(VADisplay dpy, VAContextID context);
96 typedef VAStatus (*VaapiCreateBuffer)(VADisplay dpy,
97 VAContextID context,
98 VABufferType type,
99 unsigned int size,
100 unsigned int num_elements,
101 void *data,
102 VABufferID *buf_id);
103 typedef VAStatus (*VaapiDestroyBuffer)(VADisplay dpy, VABufferID buffer_id);
104 typedef const char* (*VaapiErrorStr)(VAStatus error_status);
105
106 #define VAAPI_SYM(name, handle) Vaapi##name VAAPI_##name = NULL
107
108 VAAPI_SYM(GetDisplay, vaapi_x11_handle);
109 VAAPI_SYM(DisplayIsValid, vaapi_handle);
110 VAAPI_SYM(Initialize, vaapi_handle);
111 VAAPI_SYM(Terminate, vaapi_handle);
112 VAAPI_SYM(GetConfigAttributes, vaapi_handle);
113 VAAPI_SYM(CreateConfig, vaapi_handle);
114 VAAPI_SYM(DestroyConfig, vaapi_handle);
115 VAAPI_SYM(CreateSurfaces, vaapi_handle);
116 VAAPI_SYM(DestroySurfaces, vaapi_handle);
117 VAAPI_SYM(CreateContext, vaapi_handle);
118 VAAPI_SYM(DestroyContext, vaapi_handle);
119 VAAPI_SYM(PutSurface, vaapi_x11_handle);
120 VAAPI_SYM(SyncSurface, vaapi_x11_handle);
121 VAAPI_SYM(BeginPicture, vaapi_handle);
122 VAAPI_SYM(RenderPicture, vaapi_handle);
123 VAAPI_SYM(EndPicture, vaapi_handle);
124 VAAPI_SYM(CreateBuffer, vaapi_handle);
125 VAAPI_SYM(DestroyBuffer, vaapi_handle);
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 Please lexicographically sort the 3 lists involved
Pawel Osciak 2013/05/24 01:46:39 Done.
126 VAAPI_SYM(ErrorStr, 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 VaapiDelegate::VaapiDelegate()
162 : va_display_(NULL),
163 va_config_id_(VA_INVALID_ID),
164 va_context_id_(VA_INVALID_ID) {
165 }
166
167 VaapiDelegate::~VaapiDelegate() {
168 DestroyPendingBuffers();
169 DestroySurfaces();
170 Deinitialize();
171 }
172
173 scoped_refptr<VaapiDelegate> VaapiDelegate::Create(
174 media::VideoCodecProfile profile,
175 Display* x_display,
176 const base::Closure& report_error_to_uma_cb) {
177 scoped_refptr<VaapiDelegate> vaapi_delegate(new VaapiDelegate());
178
179 if (!vaapi_delegate->Initialize(profile, x_display, report_error_to_uma_cb))
180 vaapi_delegate = NULL;
181
182 return vaapi_delegate;
183 }
184
185 bool VaapiDelegate::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";
marcheu 2013/05/23 03:02:55 nit: that message is a bit hard to grasp at first,
Pawel Osciak 2013/05/24 01:46:39 Done.
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 VaapiDelegate::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 VaapiDelegate::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 VaapiDelegate::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 VaapiDelegate::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 VaapiDelegate::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 VaapiDelegate::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 VaapiDelegate::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
380 bool result = SubmitDecode(va_surface_id);
381 DestroyPendingBuffers();
382 return result;
383 }
384
385 bool VaapiDelegate::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 VaapiDelegate::pre_sandbox_init_done_ = false;
407
408 // static
409 void VaapiDelegate::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 VaapiDelegate::PostSandboxInitialization() {
418 if (!pre_sandbox_init_done_)
419 return false;
420 #define VAAPI_DLSYM(name, handle) \
421 VAAPI_##name = reinterpret_cast<Vaapi##name>(dlsym((handle), "va"#name)) \
422
423 VAAPI_DLSYM(GetDisplay, vaapi_x11_handle);
424 VAAPI_DLSYM(DisplayIsValid, vaapi_handle);
425 VAAPI_DLSYM(Initialize, vaapi_handle);
426 VAAPI_DLSYM(Terminate, vaapi_handle);
427 VAAPI_DLSYM(GetConfigAttributes, vaapi_handle);
428 VAAPI_DLSYM(CreateConfig, vaapi_handle);
429 VAAPI_DLSYM(DestroyConfig, vaapi_handle);
430 VAAPI_DLSYM(CreateSurfaces, vaapi_handle);
431 VAAPI_DLSYM(DestroySurfaces, vaapi_handle);
432 VAAPI_DLSYM(CreateContext, vaapi_handle);
433 VAAPI_DLSYM(DestroyContext, vaapi_handle);
434 VAAPI_DLSYM(PutSurface, vaapi_x11_handle);
435 VAAPI_DLSYM(SyncSurface, vaapi_x11_handle);
436 VAAPI_DLSYM(BeginPicture, vaapi_handle);
437 VAAPI_DLSYM(RenderPicture, vaapi_handle);
438 VAAPI_DLSYM(EndPicture, vaapi_handle);
439 VAAPI_DLSYM(CreateBuffer, vaapi_handle);
440 VAAPI_DLSYM(DestroyBuffer, vaapi_handle);
441 VAAPI_DLSYM(ErrorStr, vaapi_handle);
442 #undef VAAPI_DLSYM
443
444 return VAAPI_GetDisplay &&
445 VAAPI_DisplayIsValid &&
446 VAAPI_Initialize &&
447 VAAPI_Terminate &&
448 VAAPI_GetConfigAttributes &&
449 VAAPI_CreateConfig &&
450 VAAPI_DestroyConfig &&
451 VAAPI_CreateSurfaces &&
452 VAAPI_DestroySurfaces &&
453 VAAPI_CreateContext &&
454 VAAPI_DestroyContext &&
455 VAAPI_PutSurface &&
456 VAAPI_SyncSurface &&
457 VAAPI_BeginPicture &&
458 VAAPI_RenderPicture &&
459 VAAPI_EndPicture &&
460 VAAPI_CreateBuffer &&
461 VAAPI_DestroyBuffer &&
462 VAAPI_ErrorStr;
463 }
464
465 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698