1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
media / gpu / vaapi / vaapi_video_encoder_delegate.h [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_
#define MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_
#include <va/va.h>
#include <optional>
#include <vector>
#include "base/containers/queue.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "media/base/video_bitrate_allocation.h"
#include "media/base/video_codecs.h"
#include "media/video/video_encode_accelerator.h"
#include "media/video/video_encoder_info.h"
#include "ui/gfx/geometry/size.h"
namespace media {
struct BitstreamBufferMetadata;
class CodecPicture;
class ScopedVABuffer;
class VideoFrame;
class VaapiWrapper;
// An VaapiVideoEncoderDelegate performs high-level, platform-independent
// encoding process tasks, such as managing codec state, reference frames, etc.,
// but may require support from an external accelerator (typically a hardware
// accelerator) to offload some stages of the actual encoding process, using
// the parameters that the Delegate prepares beforehand.
//
// For each frame to be encoded, clients provide an EncodeJob object to be set
// up by a Delegate subclass with job parameters, and execute the job
// afterwards. Any resources required for the job are also provided by the
// clients, and associated with the EncodeJob object.
class VaapiVideoEncoderDelegate {
public:
struct Config {
// Maximum number of reference frames.
// For H.264 encoding, the value represents the maximum number of reference
// frames for both the reference picture list 0 (bottom 16 bits) and the
// reference picture list 1 (top 16 bits).
size_t max_num_ref_frames;
};
// EncodeResult owns the necessary resource to keep the encoded buffer. The
// encoded buffer can be downloaded with the EncodeResult, for example, by
// calling VaapiWrapper::DownloadFromVABuffer().
class EncodeResult {
public:
EncodeResult(std::unique_ptr<ScopedVABuffer> coded_buffer,
const BitstreamBufferMetadata& metadata);
~EncodeResult();
EncodeResult(EncodeResult&&);
EncodeResult& operator=(EncodeResult&&);
EncodeResult(const EncodeResult&) = delete;
EncodeResult& operator=(const EncodeResult&) = delete;
VABufferID coded_buffer_id() const;
const BitstreamBufferMetadata& metadata() const;
bool IsFrameDropped() const { return !coded_buffer_; }
private:
std::unique_ptr<ScopedVABuffer> coded_buffer_;
BitstreamBufferMetadata metadata_;
};
// An abstraction of an encode job for one frame. Parameters required for an
// EncodeJob to be executed are prepared by an VaapiVideoEncoderDelegate,
// while the accelerator-specific callbacks required to set up and execute it
// are provided by the accelerator itself, based on these parameters.
// Accelerators are also responsible for providing any resources (such as
// memory for output, etc.) as needed.
class EncodeJob {
public:
// Creates an EncodeJob to encode the va surface associated with
// |input_surface_id|, which will be executed by
// VaapiVideoEncoderDelegate::Encode().
// If |keyframe| is true, requests this job to produce a keyframe.
// |picture| is for a reconstructed frame and the encoded chunk is written
// into the buffer of |coded_buffer|.
EncodeJob(bool keyframe,
base::TimeDelta timestamp,
uint8_t spatial_index,
bool end_of_picture,
VASurfaceID input_surface_id,
scoped_refptr<CodecPicture> picture,
std::unique_ptr<ScopedVABuffer> coded_buffer);
EncodeJob(const EncodeJob&) = delete;
EncodeJob& operator=(const EncodeJob&) = delete;
~EncodeJob();
// Creates EncodeResult with |metadata|. This passes ownership of the
// resources owned by EncodeJob and therefore must be called with
// std::move().
EncodeResult CreateEncodeResult(const BitstreamBufferMetadata& metadata) &&;
// Requests this job to produce a keyframe; requesting a keyframe may not
// always result in one being produced by the encoder (e.g. if it would
// not fit in the bitrate budget).
void ProduceKeyframe() { keyframe_ = true; }
// Returns true if this job has been requested to produce a keyframe.
bool IsKeyframeRequested() const { return keyframe_; }
void DropFrame() { coded_buffer_.reset(); }
bool IsFrameDropped() const { return !coded_buffer_; }
base::TimeDelta timestamp() const;
uint8_t spatial_index() const;
// This is a frame in the top spatial layer.
bool end_of_picture() const;
uint8_t spatial_idx() const;
// VA-API specific methods.
VABufferID coded_buffer_id() const;
VASurfaceID input_surface_id() const;
const scoped_refptr<CodecPicture>& picture() const;
private:
// True if this job is to produce a keyframe.
bool keyframe_;
// |timestamp_| to be added to the produced encoded chunk.
const base::TimeDelta timestamp_;
const uint8_t spatial_index_ = 0;
const bool end_of_picture_;
// VA-API specific members.
// Input surface ID and size for video frame data or scaled data.
const VASurfaceID input_surface_id_;
const scoped_refptr<CodecPicture> picture_;
// Buffer that will contain the output bitstream data for this frame.
std::unique_ptr<ScopedVABuffer> coded_buffer_;
};
VaapiVideoEncoderDelegate(scoped_refptr<VaapiWrapper> vaapi_wrapper,
base::RepeatingClosure error_cb);
virtual ~VaapiVideoEncoderDelegate();
// Initializes the encoder with requested parameter set |config| and
// |ave_config|. Returns false if the requested set of parameters is not
// supported, true on success.
virtual bool Initialize(
const VideoEncodeAccelerator::Config& config,
const VaapiVideoEncoderDelegate::Config& ave_config) = 0;
// Updates current framerate and/or bitrate to |framerate| in FPS
// and the specified video bitrate allocation.
virtual bool UpdateRates(const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate) = 0;
// Returns coded size for the input buffers required to encode, in pixels;
// typically visible size adjusted to match codec alignment requirements.
virtual gfx::Size GetCodedSize() const = 0;
// Returns minimum size in bytes for bitstream buffers required to fit output
// stream buffers produced.
virtual size_t GetBitstreamBufferSize() const;
// Returns maximum number of reference frames that may be used by the
// encoder to encode one frame. The client should be able to provide up to
// at least this many frames simultaneously for encode to make progress.
virtual size_t GetMaxNumOfRefFrames() const = 0;
// Prepares and submits the encode operation to underlying driver for an
// EncodeJob for one frame and returns true on success.
bool Encode(EncodeJob& encode_job);
// Creates and returns the encode result for specified EncodeJob by
// synchronizing the corresponding encode operation. std::nullopt is returned
// on failure.
std::optional<EncodeResult> GetEncodeResult(
std::unique_ptr<EncodeJob> encode_job);
// Gets the active spatial layer resolutions for K-SVC encoding, VaapiVEA
// can get this info from the encoder delegate. Returns empty vector on
// failure.
virtual std::vector<gfx::Size> GetSVCLayerResolutions() = 0;
protected:
// Friend in order o access PrepareEncodeJobResult declaration.
friend class H264VaapiVideoEncoderDelegateTest;
friend class VP9VaapiVideoEncoderDelegateTest;
friend class VaapiVideoEncodeAcceleratorTest;
enum class PrepareEncodeJobResult {
kSuccess, // Submit the encode job successfully.
kFail, // Error happens in submitting the encode job.
kDrop, // Encode job is dropped. An returned encoded chunk is empty.
};
const scoped_refptr<VaapiWrapper> vaapi_wrapper_;
base::RepeatingClosure error_cb_;
SEQUENCE_CHECKER(sequence_checker_);
private:
virtual BitstreamBufferMetadata GetMetadata(const EncodeJob& encode_job,
size_t payload_size) = 0;
// Prepares a new |encode_job| to be executed in Accelerator. Returns
// kSuccess on success, and kFail on failure.
virtual PrepareEncodeJobResult PrepareEncodeJob(EncodeJob& encode_job) = 0;
// Notifies the encoded chunk size in bytes with layers info through
// BitstreamBufferMetadata to update a bitrate controller in
// VaapiVideoEncoderDelegate. This should be called only if constant
// quantization encoding is used, which currently is true for VP8, VP9, H264
// and AV1.
virtual void BitrateControlUpdate(
const BitstreamBufferMetadata& metadata) = 0;
};
} // namespace media
#endif // MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_