| 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 |