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

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) \
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 s/va_res/va_error/ here and in the next 4 lines
Pawel Osciak 2013/05/21 22:32:35 Well, the result might be a success too, so I'd pr
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 It cannot be success in this macro, that's my poin
Pawel Osciak 2013/05/24 01:46:39 Done.
12 do { \
13 DVLOG(1) << err_msg \
14 << " VA error: " << VAAPI_ErrorStr(va_res); \
15 report_error_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 void *vaapi_handle = NULL;
35 void *vaapi_x11_handle = NULL;
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 static (this & above)
Pawel Osciak 2013/05/21 22:32:35 Good point. Done.
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
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 #undef after done w/ these?
Pawel Osciak 2013/05/21 22:32:35 Done.
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);
126 VAAPI_SYM(ErrorStr, vaapi_handle);
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Any reason not to do these (and the typedefs above
Pawel Osciak 2013/05/21 22:32:35 Well, they are thematically and chronologically so
127
128 // Maps Profile enum values to VaProfile values.
129 static bool ProfileToVAProfile(media::VideoCodecProfile profile,
130 VAProfile& va_profile) {
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 non-const ref
Pawel Osciak 2013/05/21 22:32:35 Done.
131 switch (profile) {
132 case media::H264PROFILE_BASELINE:
133 va_profile = VAProfileH264Baseline;
134 break;
135 case media::H264PROFILE_MAIN:
136 va_profile = VAProfileH264Main;
137 break;
138 case media::H264PROFILE_HIGH:
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 What about the variants of HIGH in media? Do they
Pawel Osciak 2013/05/21 22:32:35 The other ones are "HIGH10", 422 and 444, I might'
139 va_profile = VAProfileH264High;
140 break;
141 default:
142 return false;
143 }
144 return true;
145 }
146
147 VASurface::VASurface(VASurfaceID va_surface_id, const ReleaseCB& release_cb)
148 : va_surface_id_(va_surface_id),
149 release_cb_(release_cb) {
150 DCHECK(!release_cb_.is_null());
151 }
152
153 VASurface::~VASurface() {
154 release_cb_.Run(va_surface_id_);
155 }
156
157 VaapiDelegate::VaapiDelegate()
158 : va_display_(NULL),
159 va_config_id_(VA_INVALID_ID),
160 va_context_id_(VA_INVALID_ID) {
161 }
162
163 VaapiDelegate::~VaapiDelegate() {
164 DestroyPendingBuffers();
165 DestroySurfaces();
166 Deinitialize();
167 }
168
169 scoped_refptr<VaapiDelegate> VaapiDelegate::Create(
170 media::VideoCodecProfile profile,
171 Display* x_display,
172 const base::Closure& report_error_cb) {
173 scoped_refptr<VaapiDelegate> vaapi_delegate(new VaapiDelegate);
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 nit: never omit the parens on a new statement.
Pawel Osciak 2013/05/21 22:32:35 Done.
174
175 if (!vaapi_delegate->Initialize(profile, x_display, report_error_cb))
176 vaapi_delegate = NULL;
177
178 return vaapi_delegate;
179 }
180
181 bool VaapiDelegate::Initialize(media::VideoCodecProfile profile,
182 Display* x_display,
183 const base::Closure& report_error_cb) {
184 static bool vaapi_functions_initialized = PostSandboxInitialization();
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 This idiom is not thread-safe. (https://groups.g
Pawel Osciak 2013/05/21 22:32:35 Yes, but only one thread ever runs this...
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 How's that?
Pawel Osciak 2013/05/24 01:46:39 I meant PreSandboxInitialization is run once, whic
185 if (!vaapi_functions_initialized) {
186 DVLOG(1) << "Failed to initialize VAAPI libs";
187 return false;
188 }
189
190 report_error_cb_ = report_error_cb;
191
192 base::AutoLock auto_lock(va_lock_);
193
194 VAProfile va_profile;
195 if (!ProfileToVAProfile(profile, va_profile)) {
196 DVLOG(1) << "Unsupported profile";
197 return false;
198 }
199
200 va_display_ = VAAPI_GetDisplay(x_display);
201 if (!VAAPI_DisplayIsValid(va_display_)) {
202 DVLOG(1) << "Could not get a valid VA display";
203 return false;
204 }
205
206 int major_version, minor_version;
207 VAStatus va_res;
208 va_res = VAAPI_Initialize(va_display_, &major_version, &minor_version);
209 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
210 DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version;
211
212 VAConfigAttrib attrib;
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 s/;/ = {0};/ ?
Pawel Osciak 2013/05/21 22:32:35 Done (slightly differently).
213 attrib.type = VAConfigAttribRTFormat;
214
215 VAEntrypoint entrypoint = VAEntrypointVLD;
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 necessary? (at the very least, should be const & n
Pawel Osciak 2013/05/21 22:32:35 Done.
216 va_res = VAAPI_GetConfigAttributes(va_display_, va_profile, entrypoint,
217 &attrib, 1);
218 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
219
220 if (!(attrib.value & VA_RT_FORMAT_YUV420)) {
221 DVLOG(1) << "YUV420 not supported";
222 return false;
223 }
224
225 va_res = VAAPI_CreateConfig(va_display_, va_profile, entrypoint,
226 &attrib, 1, &va_config_id_);
227 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
228
229 return true;
230 }
231
232 void VaapiDelegate::Deinitialize() {
233 base::AutoLock auto_lock(va_lock_);
234
235 if (va_config_id_ != VA_INVALID_ID) {
236 VAStatus va_res = VAAPI_DestroyConfig(va_display_, va_config_id_);
237 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
238 }
239
240 if (va_display_) {
241 VAStatus va_res = VAAPI_Terminate(va_display_);
242 VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
243 }
244
245 va_config_id_ = VA_INVALID_ID;
246 va_display_ = NULL;
247 }
248
249 bool VaapiDelegate::CreateSurfaces(int width, int height,
250 size_t num_surfaces,
251 std::vector<VASurfaceID>& va_surfaces) {
252 base::AutoLock auto_lock(va_lock_);
253
254 DCHECK(va_surfaces.empty());
255 DCHECK(!va_surface_ids_.get());
256 va_surface_ids_.reset(new VASurfaceID[num_surfaces]);
257
258 // Allocate surfaces in driver.
259 VAStatus va_res = VAAPI_CreateSurfaces(va_display_, width, height,
260 VA_RT_FORMAT_YUV420,
261 num_surfaces, va_surface_ids_.get());
262 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false);
263 num_va_surfaces_ = num_surfaces;
264
265 // And create a context associated with them.
266 va_res = VAAPI_CreateContext(va_display_, va_config_id_,
267 width, height, VA_PROGRESSIVE,
268 va_surface_ids_.get(),
269 num_surfaces, &va_context_id_);
270
271 if (va_res != VA_STATUS_SUCCESS) {
272 DVLOG(1) << "Error creating context surfaces";
273 DestroySurfaces();
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 I think this isn't really necessary, in which case
Pawel Osciak 2013/05/21 22:32:35 Please see .h about inlining DestroySurfaces(). I'
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 Why would you not want to have that contract?
Pawel Osciak 2013/05/24 01:46:39 I prefer not having contracts when they can be avo
274 return false;
275 }
276
277 for (size_t i = 0; i < num_surfaces; ++i)
278 va_surfaces.push_back(va_surface_ids_[i]);
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Once the member is a vector too you can simply ass
Pawel Osciak 2013/05/21 22:32:35 Done.
279
280 return true;
281 }
282
283 void VaapiDelegate::DestroySurfaces() {
284 base::AutoLock auto_lock(va_lock_);
285
286 if (va_context_id_ != VA_INVALID_ID) {
287 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_);
288 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed");
289 }
290
291 if (va_surface_ids_) {
292 VAStatus va_res = VAAPI_DestroySurfaces(va_display_, va_surface_ids_.get(),
293 num_va_surfaces_);
294 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed");
295 }
296
297 va_surface_ids_.reset();
298 va_context_id_ = VA_INVALID_ID;
299 }
300
301 bool VaapiDelegate::SubmitBuffer(VABufferType va_buffer_type,
302 size_t size,
303 void* buffer) {
304 base::AutoLock auto_lock(va_lock_);
305
306 VABufferID buffer_id;
307 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
308 va_buffer_type, size,
309 1, buffer, &buffer_id);
310 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a VA buffer", false);
311
312 switch (va_buffer_type) {
313 case VASliceParameterBufferType:
314 case VASliceDataBufferType:
315 pending_slice_bufs_.push_back(buffer_id);
316 break;
317
318 default:
319 pending_va_bufs_.push_back(buffer_id);
320 break;
321 }
322
323 return true;
324 }
325
326 void VaapiDelegate::DestroyPendingBuffers() {
327 base::AutoLock auto_lock(va_lock_);
328
329 for (size_t i = 0; i < pending_va_bufs_.size(); ++i) {
330 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, pending_va_bufs_[i]);
331 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
332 }
333
334 for (size_t i = 0; i < pending_slice_bufs_.size(); ++i) {
335 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, pending_slice_bufs_[i]);
336 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed");
337 }
338
339 pending_va_bufs_.clear();
340 pending_slice_bufs_.clear();
341 }
342
343 bool VaapiDelegate::SubmitDecode(VASurfaceID va_surface_id) {
344 base::AutoLock auto_lock(va_lock_);
345
346 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
347 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
348 DVLOG(4) << "Decoding into VA surface " << va_surface_id;
349
350 scoped_ptr<VABufferID[]> va_buffers(new VABufferID[pending_va_bufs_.size()]);
351 std::copy(pending_va_bufs_.begin(), pending_va_bufs_.end(), va_buffers.get());
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Why the copies? Is VAAPI_RenderPicture destructiv
Pawel Osciak 2013/05/21 22:32:35 Yes, getting over my distaste for this syntax...
352
353 scoped_ptr<VABufferID[]> slice_buffers(
354 new VABufferID[pending_slice_bufs_.size()]);
355 std::copy(pending_slice_bufs_.begin(), pending_slice_bufs_.end(),
356 slice_buffers.get());
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 ditto
Pawel Osciak 2013/05/21 22:32:35 Done.
357
358 // Get ready to decode into surface.
359 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_,
360 va_surface_id);
361 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false);
362
363 // Commit parameter and slice buffers.
364 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, va_buffers.get(),
365 pending_va_bufs_.size());
366 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false);
367
368 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, slice_buffers.get(),
369 pending_slice_bufs_.size());
370 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false);
371
372 // Instruct HW decoder to start processing committed buffers (decode this
373 // picture). This does not block until the end of decode.
374 va_res = VAAPI_EndPicture(va_display_, va_context_id_);
375 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false);
376
377 return true;
378 }
379
380 bool VaapiDelegate::DecodeAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
381 bool result = SubmitDecode(va_surface_id);
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 The lock is not held across this & the next line,
Pawel Osciak 2013/05/21 22:32:35 I actually had it that way initially. But it was t
382 DestroyPendingBuffers();
383 return result;
384 }
385
386 bool VaapiDelegate::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
387 Pixmap x_pixmap,
388 int width, int height) {
389 base::AutoLock auto_lock(va_lock_);
390
391 VAStatus va_res = VAAPI_SyncSurface(va_display_, va_surface_id);
392 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing surface", false);
393
394 // Put the data into an X Pixmap.
395 va_res = VAAPI_PutSurface(va_display_,
396 va_surface_id,
397 x_pixmap,
398 0, 0, width, height,
399 0, 0, width, height,
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 is there an assumption that this class only knows
Pawel Osciak 2013/05/21 22:32:35 Correct.
400 NULL, 0, 0);
401 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decode surface to pixmap",
402 false);
403 return true;
404 }
405
406 // static
407 bool VaapiDelegate::pre_sandbox_init_done_ = false;
408
409 // static
410 void VaapiDelegate::PreSandboxInitialization() {
411 DCHECK(!pre_sandbox_init_done_);
412 vaapi_handle = dlopen("libva.so", RTLD_NOW);
413 vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW);
414 pre_sandbox_init_done_ = vaapi_handle && vaapi_x11_handle;
415 }
416
417 // static
418 bool VaapiDelegate::PostSandboxInitialization() {
419 if (!pre_sandbox_init_done_)
420 return false;
421 #define VAAPI_DLSYM(name, handle) \
422 VAAPI_##name = reinterpret_cast<Vaapi##name>(dlsym((handle), "va"#name)) \
423
424 VAAPI_DLSYM(GetDisplay, vaapi_x11_handle);
425 VAAPI_DLSYM(DisplayIsValid, vaapi_handle);
426 VAAPI_DLSYM(Initialize, vaapi_handle);
427 VAAPI_DLSYM(Terminate, vaapi_handle);
428 VAAPI_DLSYM(GetConfigAttributes, vaapi_handle);
429 VAAPI_DLSYM(CreateConfig, vaapi_handle);
430 VAAPI_DLSYM(DestroyConfig, vaapi_handle);
431 VAAPI_DLSYM(CreateSurfaces, vaapi_handle);
432 VAAPI_DLSYM(DestroySurfaces, vaapi_handle);
433 VAAPI_DLSYM(CreateContext, vaapi_handle);
434 VAAPI_DLSYM(DestroyContext, vaapi_handle);
435 VAAPI_DLSYM(PutSurface, vaapi_x11_handle);
436 VAAPI_DLSYM(SyncSurface, vaapi_x11_handle);
437 VAAPI_DLSYM(BeginPicture, vaapi_handle);
438 VAAPI_DLSYM(RenderPicture, vaapi_handle);
439 VAAPI_DLSYM(EndPicture, vaapi_handle);
440 VAAPI_DLSYM(CreateBuffer, vaapi_handle);
441 VAAPI_DLSYM(DestroyBuffer, vaapi_handle);
442 VAAPI_DLSYM(ErrorStr, vaapi_handle);
443 #undef VAAPI_DLSYM
444
445 return VAAPI_GetDisplay &&
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 FWIW you could test for NULL and early-return as p
Pawel Osciak 2013/05/21 22:32:35 Yeah, but honestly I don't think it'd really be th
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 a) it would too be useful (I've had to add that co
Pawel Osciak 2013/05/24 01:46:39 Yeah, I see what you meant now, I like it. Done.
446 VAAPI_DisplayIsValid &&
447 VAAPI_Initialize &&
448 VAAPI_Terminate &&
449 VAAPI_GetConfigAttributes &&
450 VAAPI_CreateConfig &&
451 VAAPI_DestroyConfig &&
452 VAAPI_CreateSurfaces &&
453 VAAPI_DestroySurfaces &&
454 VAAPI_CreateContext &&
455 VAAPI_DestroyContext &&
456 VAAPI_PutSurface &&
457 VAAPI_SyncSurface &&
458 VAAPI_BeginPicture &&
459 VAAPI_RenderPicture &&
460 VAAPI_EndPicture &&
461 VAAPI_CreateBuffer &&
462 VAAPI_DestroyBuffer &&
463 VAAPI_ErrorStr;
464 }
465
466 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698