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 <set>
14#include <vector>
15
16#include "base/callback.h"
17#include "base/memory/ref_counted.h"
18#include "base/synchronization/lock.h"
19#include "content/common/content_export.h"
20#include "content/common/gpu/media/va_surface.h"
21#include "media/base/video_decoder_config.h"
22#include "media/base/video_frame.h"
23#include "third_party/libva/va/va_x11.h"
24#include "ui/gfx/size.h"
25
26namespace content {
27
28// This class handles VA-API calls and ensures proper locking of VA-API calls
29// to libva, the userspace shim to the HW codec driver. libva is not
30// thread-safe, so we have to perform locking ourselves. This class is fully
31// synchronous and its methods can be called from any thread and may wait on
32// the va_lock_ while other, concurrent calls run.
33//
34// This class is responsible for managing VAAPI connection, contexts and state.
35// It is also responsible for managing and freeing VABuffers (not VASurfaces),
36// which are used to queue parameters and slice data to the HW codec,
37// as well as underlying memory for VASurfaces themselves.
38class CONTENT_EXPORT VaapiWrapper {
39 public:
40  enum CodecMode {
41    kDecode,
42    kEncode,
43  };
44
45  // |report_error_to_uma_cb| will be called independently from reporting
46  // errors to clients via method return values.
47  static scoped_ptr<VaapiWrapper> Create(
48      CodecMode mode,
49      media::VideoCodecProfile profile,
50      Display* x_display,
51      const base::Closure& report_error_to_uma_cb);
52
53  // Return the supported encode profiles.
54  static std::vector<media::VideoCodecProfile> GetSupportedEncodeProfiles(
55      Display* x_display,
56      const base::Closure& report_error_to_uma_cb);
57
58  ~VaapiWrapper();
59
60  // Create |num_surfaces| backing surfaces in driver for VASurfaces, each
61  // of size |size|. Returns true when successful, with the created IDs in
62  // |va_surfaces| to be managed and later wrapped in VASurfaces.
63  // The client must DestroySurfaces() each time before calling this method
64  // again to free the allocated surfaces first, but is not required to do so
65  // at destruction time, as this will be done automatically from
66  // the destructor.
67  bool CreateSurfaces(gfx::Size size,
68                      size_t num_surfaces,
69                      std::vector<VASurfaceID>* va_surfaces);
70
71  // Free all memory allocated in CreateSurfaces.
72  void DestroySurfaces();
73
74  // Submit parameters or slice data of |va_buffer_type|, copying them from
75  // |buffer| of size |size|, into HW codec. The data in |buffer| is no
76  // longer needed and can be freed after this method returns.
77  // Data submitted via this method awaits in the HW codec until
78  // ExecuteAndDestroyPendingBuffers() is called to execute or
79  // DestroyPendingBuffers() is used to cancel a pending job.
80  bool SubmitBuffer(VABufferType va_buffer_type, size_t size, void* buffer);
81
82  // Submit a VAEncMiscParameterBuffer of given |misc_param_type|, copying its
83  // data from |buffer| of size |size|, into HW codec. The data in |buffer| is
84  // no longer needed and can be freed after this method returns.
85  // Data submitted via this method awaits in the HW codec until
86  // ExecuteAndDestroyPendingBuffers() is called to execute or
87  // DestroyPendingBuffers() is used to cancel a pending job.
88  bool SubmitVAEncMiscParamBuffer(VAEncMiscParameterType misc_param_type,
89                                  size_t size,
90                                  void* buffer);
91
92  // Cancel and destroy all buffers queued to the HW codec via SubmitBuffer().
93  // Useful when a pending job is to be cancelled (on reset or error).
94  void DestroyPendingBuffers();
95
96  // Execute job in hardware on target |va_surface_id| and destroy pending
97  // buffers. Return false if Execute() fails.
98  bool ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id);
99
100  // Put data from |va_surface_id| into |x_pixmap| of size |size|,
101  // converting/scaling to it.
102  bool PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
103                            Pixmap x_pixmap,
104                            gfx::Size dest_size);
105
106  // Returns true if the VAAPI version is less than the specified version.
107  bool VAAPIVersionLessThan(int major, int minor);
108
109  // Get a VAImage from a VASurface and map it into memory. The VAImage should
110  // be released using the ReturnVaImage function. Returns true when successful.
111  // This is intended for testing only.
112  bool GetVaImageForTesting(VASurfaceID va_surface_id,
113                            VAImage* image,
114                            void** mem);
115
116  // Release the VAImage (and the associated memory mapping) obtained from
117  // GetVaImage(). This is intended for testing only.
118  void ReturnVaImageForTesting(VAImage* image);
119
120  // Upload contents of |frame| into |va_surface_id| for encode.
121  bool UploadVideoFrameToSurface(const scoped_refptr<media::VideoFrame>& frame,
122                                 VASurfaceID va_surface_id);
123
124  // Create a buffer of |size| bytes to be used as encode output.
125  bool CreateCodedBuffer(size_t size, VABufferID* buffer_id);
126
127  // Download the contents of the buffer with given |buffer_id| into a buffer of
128  // size |target_size|, pointed to by |target_ptr|. The number of bytes
129  // downloaded will be returned in |coded_data_size|. |sync_surface_id| will
130  // be used as a sync point, i.e. it will have to become idle before starting
131  // the download. |sync_surface_id| should be the source surface passed
132  // to the encode job.
133  bool DownloadAndDestroyCodedBuffer(VABufferID buffer_id,
134                                     VASurfaceID sync_surface_id,
135                                     uint8* target_ptr,
136                                     size_t target_size,
137                                     size_t* coded_data_size);
138
139  // Destroy all previously-allocated (and not yet destroyed) coded buffers.
140  void DestroyCodedBuffers();
141
142 private:
143  VaapiWrapper();
144
145  bool Initialize(CodecMode mode,
146                  media::VideoCodecProfile profile,
147                  Display* x_display,
148                  const base::Closure& report_error_to_uma_cb);
149  void Deinitialize();
150  bool VaInitialize(Display* x_display,
151                    const base::Closure& report_error_to_uma_cb);
152  bool GetSupportedVaProfiles(std::vector<VAProfile>* profiles);
153  bool IsEntrypointSupported(VAProfile va_profile, VAEntrypoint entrypoint);
154  bool AreAttribsSupported(VAProfile va_profile,
155                           VAEntrypoint entrypoint,
156                           const std::vector<VAConfigAttrib>& required_attribs);
157
158  // Execute pending job in hardware and destroy pending buffers. Return false
159  // if vaapi driver refuses to accept parameter or slice buffers submitted
160  // by client, or if execution fails in hardware.
161  bool Execute(VASurfaceID va_surface_id);
162
163  // Attempt to set render mode to "render to texture.". Failure is non-fatal.
164  void TryToSetVADisplayAttributeToLocalGPU();
165
166  // Lazily initialize static data after sandbox is enabled.  Return false on
167  // init failure.
168  static bool PostSandboxInitialization();
169
170  // Libva is not thread safe, so we have to do locking for it ourselves.
171  // This lock is to be taken for the duration of all VA-API calls and for
172  // the entire job submission sequence in ExecuteAndDestroyPendingBuffers().
173  base::Lock va_lock_;
174
175  // Allocated ids for VASurfaces.
176  std::vector<VASurfaceID> va_surface_ids_;
177
178  // The VAAPI version.
179  int major_version_, minor_version_;
180
181  // VA handles.
182  // Both valid after successful Initialize() and until Deinitialize().
183  VADisplay va_display_;
184  VAConfigID va_config_id_;
185  // Created for the current set of va_surface_ids_ in CreateSurfaces() and
186  // valid until DestroySurfaces().
187  VAContextID va_context_id_;
188
189  // Data queued up for HW codec, to be committed on next execution.
190  std::vector<VABufferID> pending_slice_bufs_;
191  std::vector<VABufferID> pending_va_bufs_;
192
193  // Bitstream buffers for encode.
194  std::set<VABufferID> coded_buffers_;
195
196  // Called to report codec errors to UMA. Errors to clients are reported via
197  // return values from public methods.
198  base::Closure report_error_to_uma_cb_;
199
200  DISALLOW_COPY_AND_ASSIGN(VaapiWrapper);
201};
202
203}  // namespace content
204
205#endif  // CONTENT_COMMON_GPU_MEDIA_VAAPI_WRAPPER_H_
206