OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 // | |
5 // This file contains an implementation of VaapiWrapper, used by | |
6 // VaapiVideoDecodeAccelerator and VaapiH264Decoder for decode, | |
7 // and VaapiVideoEncodeAccelerator for encode, to interface | |
8 // with libva (VA-API library for hardware video codec). | |
9 | |
10 #ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_WRAPPER_H_ | |
11 #define CONTENT_COMMON_GPU_MEDIA_VAAPI_WRAPPER_H_ | |
12 | |
13 #include <stddef.h> | |
14 #include <stdint.h> | |
15 | |
16 #include <set> | |
17 #include <vector> | |
18 | |
19 #include "base/files/file.h" | |
20 #include "base/lazy_instance.h" | |
21 #include "base/macros.h" | |
22 #include "base/memory/ref_counted.h" | |
23 #include "base/synchronization/lock.h" | |
24 #include "content/common/content_export.h" | |
25 #include "content/common/gpu/media/va_surface.h" | |
26 #include "media/base/video_decoder_config.h" | |
27 #include "media/base/video_frame.h" | |
28 #include "media/video/jpeg_decode_accelerator.h" | |
29 #include "media/video/video_decode_accelerator.h" | |
30 #include "media/video/video_encode_accelerator.h" | |
31 #include "third_party/libva/va/va.h" | |
32 #include "third_party/libva/va/va_vpp.h" | |
33 #include "ui/gfx/geometry/size.h" | |
34 #if defined(USE_X11) | |
35 #include "third_party/libva/va/va_x11.h" | |
36 #endif // USE_X11 | |
37 | |
38 #if defined(USE_OZONE) | |
39 namespace ui { | |
40 class NativePixmap; | |
41 } | |
42 #endif | |
43 | |
44 namespace content { | |
45 | |
46 // This class handles VA-API calls and ensures proper locking of VA-API calls | |
47 // to libva, the userspace shim to the HW codec driver. libva is not | |
48 // thread-safe, so we have to perform locking ourselves. This class is fully | |
49 // synchronous and its methods can be called from any thread and may wait on | |
50 // the va_lock_ while other, concurrent calls run. | |
51 // | |
52 // This class is responsible for managing VAAPI connection, contexts and state. | |
53 // It is also responsible for managing and freeing VABuffers (not VASurfaces), | |
54 // which are used to queue parameters and slice data to the HW codec, | |
55 // as well as underlying memory for VASurfaces themselves. | |
56 class CONTENT_EXPORT VaapiWrapper | |
57 : public base::RefCountedThreadSafe<VaapiWrapper> { | |
58 public: | |
59 enum CodecMode { | |
60 kDecode, | |
61 kEncode, | |
62 kCodecModeMax, | |
63 }; | |
64 | |
65 // Return an instance of VaapiWrapper initialized for |va_profile| and | |
66 // |mode|. |report_error_to_uma_cb| will be called independently from | |
67 // reporting errors to clients via method return values. | |
68 static scoped_refptr<VaapiWrapper> Create( | |
69 CodecMode mode, | |
70 VAProfile va_profile, | |
71 const base::Closure& report_error_to_uma_cb); | |
72 | |
73 // Create VaapiWrapper for VideoCodecProfile. It maps VideoCodecProfile | |
74 // |profile| to VAProfile. | |
75 // |report_error_to_uma_cb| will be called independently from reporting | |
76 // errors to clients via method return values. | |
77 static scoped_refptr<VaapiWrapper> CreateForVideoCodec( | |
78 CodecMode mode, | |
79 media::VideoCodecProfile profile, | |
80 const base::Closure& report_error_to_uma_cb); | |
81 | |
82 // Return the supported video encode profiles. | |
83 static media::VideoEncodeAccelerator::SupportedProfiles | |
84 GetSupportedEncodeProfiles(); | |
85 | |
86 // Return the supported video decode profiles. | |
87 static media::VideoDecodeAccelerator::SupportedProfiles | |
88 GetSupportedDecodeProfiles(); | |
89 | |
90 // Return true when JPEG decode is supported. | |
91 static bool IsJpegDecodeSupported(); | |
92 | |
93 // Create |num_surfaces| backing surfaces in driver for VASurfaces of | |
94 // |va_format|, each of size |size|. Returns true when successful, with the | |
95 // created IDs in |va_surfaces| to be managed and later wrapped in | |
96 // VASurfaces. | |
97 // The client must DestroySurfaces() each time before calling this method | |
98 // again to free the allocated surfaces first, but is not required to do so | |
99 // at destruction time, as this will be done automatically from | |
100 // the destructor. | |
101 bool CreateSurfaces(unsigned int va_format, | |
102 const gfx::Size& size, | |
103 size_t num_surfaces, | |
104 std::vector<VASurfaceID>* va_surfaces); | |
105 | |
106 // Free all memory allocated in CreateSurfaces. | |
107 void DestroySurfaces(); | |
108 | |
109 // Create a VASurface of |va_format|, |size| and using |va_attribs| | |
110 // attributes. The ownership of the surface is transferred to the | |
111 // caller. It differs from surfaces created using CreateSurfaces(), | |
112 // where VaapiWrapper is the owner of the surfaces. | |
113 scoped_refptr<VASurface> CreateUnownedSurface( | |
114 unsigned int va_format, | |
115 const gfx::Size& size, | |
116 const std::vector<VASurfaceAttrib>& va_attribs); | |
117 | |
118 #if defined(USE_OZONE) | |
119 // Create a VASurface for |pixmap|. The ownership of the surface is | |
120 // transferred to the caller. It differs from surfaces created using | |
121 // CreateSurfaces(), where VaapiWrapper is the owner of the surfaces. | |
122 scoped_refptr<VASurface> CreateVASurfaceForPixmap( | |
123 const scoped_refptr<ui::NativePixmap>& pixmap); | |
124 | |
125 // Use VPP to process |source_pixmap| to |target_pixmap| with scaling and | |
126 // color space conversion. | |
127 bool ProcessPixmap(const scoped_refptr<ui::NativePixmap>& source_pixmap, | |
128 scoped_refptr<ui::NativePixmap> target_pixmap); | |
129 | |
130 #endif | |
131 | |
132 // Submit parameters or slice data of |va_buffer_type|, copying them from | |
133 // |buffer| of size |size|, into HW codec. The data in |buffer| is no | |
134 // longer needed and can be freed after this method returns. | |
135 // Data submitted via this method awaits in the HW codec until | |
136 // ExecuteAndDestroyPendingBuffers() is called to execute or | |
137 // DestroyPendingBuffers() is used to cancel a pending job. | |
138 bool SubmitBuffer(VABufferType va_buffer_type, size_t size, void* buffer); | |
139 | |
140 // Submit a VAEncMiscParameterBuffer of given |misc_param_type|, copying its | |
141 // data from |buffer| of size |size|, into HW codec. The data in |buffer| is | |
142 // no longer needed and can be freed after this method returns. | |
143 // Data submitted via this method awaits in the HW codec until | |
144 // ExecuteAndDestroyPendingBuffers() is called to execute or | |
145 // DestroyPendingBuffers() is used to cancel a pending job. | |
146 bool SubmitVAEncMiscParamBuffer(VAEncMiscParameterType misc_param_type, | |
147 size_t size, | |
148 void* buffer); | |
149 | |
150 // Cancel and destroy all buffers queued to the HW codec via SubmitBuffer(). | |
151 // Useful when a pending job is to be cancelled (on reset or error). | |
152 void DestroyPendingBuffers(); | |
153 | |
154 // Execute job in hardware on target |va_surface_id| and destroy pending | |
155 // buffers. Return false if Execute() fails. | |
156 bool ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id); | |
157 | |
158 #if defined(USE_X11) | |
159 // Put data from |va_surface_id| into |x_pixmap| of size | |
160 // |dest_size|, converting/scaling to it. | |
161 bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id, | |
162 Pixmap x_pixmap, | |
163 gfx::Size dest_size); | |
164 #endif // USE_X11 | |
165 | |
166 // Get a VAImage from a VASurface and map it into memory. The size and format | |
167 // are derived from the surface. Use GetVaImage() instead if |format| or | |
168 // |size| are different from surface internal representation. The VAImage | |
169 // should be released using the ReturnVaImage function. Returns true when | |
170 // successful. | |
171 bool GetDerivedVaImage(VASurfaceID va_surface_id, VAImage* image, void** mem); | |
172 | |
173 // Get a VAImage from a VASurface |va_surface_id| and map it into memory with | |
174 // given |format| and |size|. The output is |image| and the mapped memory is | |
175 // |mem|. If |format| doesn't equal to the internal format, the underlying | |
176 // implementation will do format conversion if supported. |size| should be | |
177 // smaller than or equal to the surface. If |size| is smaller, the image will | |
178 // be cropped. The VAImage should be released using the ReturnVaImage | |
179 // function. Returns true when successful. | |
180 bool GetVaImage(VASurfaceID va_surface_id, | |
181 VAImageFormat* format, | |
182 const gfx::Size& size, | |
183 VAImage* image, | |
184 void** mem); | |
185 | |
186 // Release the VAImage (and the associated memory mapping) obtained from | |
187 // GetVaImage() or GetDerivedVaImage(). | |
188 void ReturnVaImage(VAImage* image); | |
189 | |
190 // Upload contents of |frame| into |va_surface_id| for encode. | |
191 bool UploadVideoFrameToSurface(const scoped_refptr<media::VideoFrame>& frame, | |
192 VASurfaceID va_surface_id); | |
193 | |
194 // Create a buffer of |size| bytes to be used as encode output. | |
195 bool CreateCodedBuffer(size_t size, VABufferID* buffer_id); | |
196 | |
197 // Download the contents of the buffer with given |buffer_id| into a buffer of | |
198 // size |target_size|, pointed to by |target_ptr|. The number of bytes | |
199 // downloaded will be returned in |coded_data_size|. |sync_surface_id| will | |
200 // be used as a sync point, i.e. it will have to become idle before starting | |
201 // the download. |sync_surface_id| should be the source surface passed | |
202 // to the encode job. | |
203 bool DownloadAndDestroyCodedBuffer(VABufferID buffer_id, | |
204 VASurfaceID sync_surface_id, | |
205 uint8_t* target_ptr, | |
206 size_t target_size, | |
207 size_t* coded_data_size); | |
208 | |
209 // Destroy all previously-allocated (and not yet destroyed) coded buffers. | |
210 void DestroyCodedBuffers(); | |
211 | |
212 // Blits a VASurface |va_surface_src| into another VASurface | |
213 // |va_surface_dest| applying pixel format conversion and scaling | |
214 // if needed. | |
215 bool BlitSurface(const scoped_refptr<VASurface>& va_surface_src, | |
216 const scoped_refptr<VASurface>& va_surface_dest); | |
217 | |
218 // Initialize static data before sandbox is enabled. | |
219 static void PreSandboxInitialization(); | |
220 | |
221 // Get the created surfaces format. | |
222 unsigned int va_surface_format() const { return va_surface_format_; } | |
223 | |
224 private: | |
225 friend class base::RefCountedThreadSafe<VaapiWrapper>; | |
226 | |
227 struct ProfileInfo { | |
228 VAProfile va_profile; | |
229 gfx::Size max_resolution; | |
230 }; | |
231 | |
232 class LazyProfileInfos { | |
233 public: | |
234 LazyProfileInfos(); | |
235 ~LazyProfileInfos(); | |
236 std::vector<ProfileInfo> GetSupportedProfileInfosForCodecMode( | |
237 CodecMode mode); | |
238 bool IsProfileSupported(CodecMode mode, VAProfile va_profile); | |
239 | |
240 private: | |
241 std::vector<ProfileInfo> supported_profiles_[kCodecModeMax]; | |
242 }; | |
243 | |
244 class VADisplayState { | |
245 public: | |
246 VADisplayState(); | |
247 ~VADisplayState(); | |
248 | |
249 // |va_lock_| must be held on entry. | |
250 bool Initialize(); | |
251 void Deinitialize(VAStatus* status); | |
252 | |
253 base::Lock* va_lock() { return &va_lock_; } | |
254 VADisplay va_display() const { return va_display_; } | |
255 | |
256 #if defined(USE_OZONE) | |
257 void SetDrmFd(base::PlatformFile fd); | |
258 #endif // USE_OZONE | |
259 | |
260 private: | |
261 friend class base::LazyInstance<VADisplayState>; | |
262 | |
263 // Returns true if the VAAPI version is less than the specified version. | |
264 bool VAAPIVersionLessThan(int major, int minor); | |
265 | |
266 // Protected by |va_lock_|. | |
267 int refcount_; | |
268 | |
269 // Libva is not thread safe, so we have to do locking for it ourselves. | |
270 // This lock is to be taken for the duration of all VA-API calls and for | |
271 // the entire job submission sequence in ExecuteAndDestroyPendingBuffers(). | |
272 base::Lock va_lock_; | |
273 | |
274 #if defined(USE_OZONE) | |
275 // Drm fd used to obtain access to the driver interface by VA. | |
276 base::ScopedFD drm_fd_; | |
277 #endif // USE_OZONE | |
278 | |
279 // The VADisplay handle. | |
280 VADisplay va_display_; | |
281 | |
282 // The VAAPI version. | |
283 int major_version_, minor_version_; | |
284 | |
285 // True if vaInitialize has been called successfully. | |
286 bool va_initialized_; | |
287 }; | |
288 | |
289 VaapiWrapper(); | |
290 ~VaapiWrapper(); | |
291 | |
292 bool Initialize(CodecMode mode, VAProfile va_profile); | |
293 void Deinitialize(); | |
294 bool VaInitialize(const base::Closure& report_error_to_uma_cb); | |
295 bool GetSupportedVaProfiles(std::vector<VAProfile>* profiles); | |
296 | |
297 // Check if |va_profile| supports |entrypoint| or not. |va_lock_| must be | |
298 // held on entry. | |
299 bool IsEntrypointSupported_Locked(VAProfile va_profile, | |
300 VAEntrypoint entrypoint); | |
301 | |
302 // Return true if |va_profile| for |entrypoint| with |required_attribs| is | |
303 // supported. |va_lock_| must be held on entry. | |
304 bool AreAttribsSupported_Locked( | |
305 VAProfile va_profile, | |
306 VAEntrypoint entrypoint, | |
307 const std::vector<VAConfigAttrib>& required_attribs); | |
308 | |
309 // Get maximum resolution for |va_profile| and |entrypoint| with | |
310 // |required_attribs|. If return value is true, |resolution| is the maximum | |
311 // resolution. |va_lock_| must be held on entry. | |
312 bool GetMaxResolution_Locked( | |
313 VAProfile va_profile, | |
314 VAEntrypoint entrypoint, | |
315 std::vector<VAConfigAttrib>& required_attribs, | |
316 gfx::Size* resolution); | |
317 | |
318 // Destroys a |va_surface| created using CreateUnownedSurface. | |
319 void DestroyUnownedSurface(VASurfaceID va_surface_id); | |
320 | |
321 // Initialize the video post processing context with the |size| of | |
322 // the input pictures to be processed. | |
323 bool InitializeVpp_Locked(); | |
324 | |
325 // Deinitialize the video post processing context. | |
326 void DeinitializeVpp(); | |
327 | |
328 // Execute pending job in hardware and destroy pending buffers. Return false | |
329 // if vaapi driver refuses to accept parameter or slice buffers submitted | |
330 // by client, or if execution fails in hardware. | |
331 bool Execute(VASurfaceID va_surface_id); | |
332 | |
333 // Attempt to set render mode to "render to texture.". Failure is non-fatal. | |
334 void TryToSetVADisplayAttributeToLocalGPU(); | |
335 | |
336 // Get supported profile infos for |mode|. | |
337 std::vector<ProfileInfo> GetSupportedProfileInfosForCodecModeInternal( | |
338 CodecMode mode); | |
339 | |
340 // Lazily initialize static data after sandbox is enabled. Return false on | |
341 // init failure. | |
342 static bool PostSandboxInitialization(); | |
343 | |
344 // Map VideoCodecProfile enum values to VaProfile values. This function | |
345 // includes a workaround for crbug.com/345569. If va_profile is h264 baseline | |
346 // and it is not supported, we try constrained baseline. | |
347 static VAProfile ProfileToVAProfile(media::VideoCodecProfile profile, | |
348 CodecMode mode); | |
349 | |
350 // Pointer to VADisplayState's member |va_lock_|. Guaranteed to be valid for | |
351 // the lifetime of VaapiWrapper. | |
352 base::Lock* va_lock_; | |
353 | |
354 // Allocated ids for VASurfaces. | |
355 std::vector<VASurfaceID> va_surface_ids_; | |
356 | |
357 // VA format of surfaces with va_surface_ids_. | |
358 unsigned int va_surface_format_; | |
359 | |
360 // Singleton instance of VADisplayState. | |
361 static base::LazyInstance<VADisplayState> va_display_state_; | |
362 | |
363 // VA handles. | |
364 // All valid after successful Initialize() and until Deinitialize(). | |
365 VADisplay va_display_; | |
366 VAConfigID va_config_id_; | |
367 // Created for the current set of va_surface_ids_ in CreateSurfaces() and | |
368 // valid until DestroySurfaces(). | |
369 VAContextID va_context_id_; | |
370 | |
371 // Data queued up for HW codec, to be committed on next execution. | |
372 std::vector<VABufferID> pending_slice_bufs_; | |
373 std::vector<VABufferID> pending_va_bufs_; | |
374 | |
375 // Bitstream buffers for encode. | |
376 std::set<VABufferID> coded_buffers_; | |
377 | |
378 // Called to report codec errors to UMA. Errors to clients are reported via | |
379 // return values from public methods. | |
380 base::Closure report_error_to_uma_cb_; | |
381 | |
382 // VPP (Video Post Processing) context, this is used to convert | |
383 // pictures used by the decoder to RGBA pictures usable by GL or the | |
384 // display hardware. | |
385 VAConfigID va_vpp_config_id_; | |
386 VAContextID va_vpp_context_id_; | |
387 VABufferID va_vpp_buffer_id_; | |
388 | |
389 // Singleton variable to store supported profile information for encode and | |
390 // decode. | |
391 static base::LazyInstance<LazyProfileInfos> profile_infos_; | |
392 | |
393 DISALLOW_COPY_AND_ASSIGN(VaapiWrapper); | |
394 }; | |
395 | |
396 } // namespace content | |
397 | |
398 #endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_WRAPPER_H_ | |
OLD | NEW |