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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
media / renderers / paint_canvas_video_renderer.h [blame]
// Copyright 2012 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_RENDERERS_PAINT_CANVAS_VIDEO_RENDERER_H_
#define MEDIA_RENDERERS_PAINT_CANVAS_VIDEO_RENDERER_H_
#include <stddef.h>
#include <stdint.h>
#include <optional>
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image.h"
#include "components/viz/common/resources/shared_image_format.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/media_export.h"
#include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h"
#include "media/base/video_transformation.h"
#include "media/renderers/video_frame_shared_image_cache.h"
namespace gfx {
class RectF;
}
namespace gpu {
struct Capabilities;
class ClientSharedImage;
namespace gles2 {
class GLES2Interface;
}
} // namespace gpu
namespace viz {
class RasterContextProvider;
}
namespace media {
class VideoTextureBacking;
// Handles rendering of VideoFrames to PaintCanvases.
class MEDIA_EXPORT PaintCanvasVideoRenderer {
public:
// Specifies the chroma upsampling filter used for pixel formats with chroma
// subsampling (YUV 4:2:0 and YUV 4:2:2).
//
// NOTE: Keep the numeric values in sync with libyuv::FilterMode.
enum FilterMode {
kFilterNone = 0, // Nearest neighbor.
kFilterBilinear = 2, // Bilinear interpolation.
};
PaintCanvasVideoRenderer();
PaintCanvasVideoRenderer(const PaintCanvasVideoRenderer&) = delete;
PaintCanvasVideoRenderer& operator=(const PaintCanvasVideoRenderer&) = delete;
~PaintCanvasVideoRenderer();
// Paints `video_frame` on `canvas`. The below Paint and Copy functions call
// into this function.
//
// If the format of `video_frame` is PIXEL_FORMAT_NATIVE_TEXTURE, `context_3d`
// and `context_support` must be provided.
//
// If `video_frame` is nullptr or an unsupported format, then paint black.
struct PaintParams {
// Translate and scale the video frame to `dest_rect` on the specified
// canvas. If not specified, then this will be a rectangle at 0,0 with the
// size of `video_frame->visible_rect().size()`.
std::optional<gfx::RectF> dest_rect;
// If true, then reinterpret the video frame as being in sRGB color space
// (though preserving the original YUV to RGB matrix) when drawing.
bool reinterpret_as_srgb = false;
// The transformation to apply to the video before the copy.
VideoTransformation transformation = media::kNoTransformation;
};
void Paint(scoped_refptr<VideoFrame> video_frame,
cc::PaintCanvas* canvas,
cc::PaintFlags& flags,
const PaintParams& params,
viz::RasterContextProvider* raster_context_provider);
// Paints |video_frame|, scaled to its |video_frame->visible_rect().size()|
// on |canvas|. Note that the origin of |video_frame->visible_rect()| is
// ignored -- the copy is done to the origin of |canvas|.
//
// If the format of |video_frame| is PIXEL_FORMAT_NATIVE_TEXTURE, |context_3d|
// and |context_support| must be provided.
void Copy(scoped_refptr<VideoFrame> video_frame,
cc::PaintCanvas* canvas,
viz::RasterContextProvider* raster_context_provider);
// Convert the contents of |video_frame| to raw RGB pixels. |rgb_pixels|
// should point into a buffer large enough to hold as many 32 bit RGBA pixels
// as are in the visible_rect() area of the frame. |premultiply_alpha|
// indicates whether the R, G, B samples in |rgb_pixels| should be multiplied
// by alpha. |filter| specifies the chroma upsampling filter used for pixel
// formats with chroma subsampling. If chroma planes in the pixel format are
// not subsampled, |filter| is ignored. |disable_threading| indicates whether
// this method should convert |video_frame| without posting any tasks to
// base::ThreadPool, regardless of the frame size. If this method is called
// from a task running in base::ThreadPool, setting |disable_threading| to
// true can avoid a potential temporary deadlock of base::ThreadPool. See
// crbug.com/1402841.
//
// NOTE: If |video_frame| doesn't have an alpha plane, all the A samples in
// |rgb_pixels| will be 255 (equivalent to an alpha of 1.0) and therefore the
// value of |premultiply_alpha| has no effect on the R, G, B samples in
// |rgb_pixels|.
static void ConvertVideoFrameToRGBPixels(const media::VideoFrame* video_frame,
void* rgb_pixels,
size_t row_bytes,
bool premultiply_alpha = true,
FilterMode filter = kFilterNone,
bool disable_threading = false);
// The output format that ConvertVideoFrameToRGBPixels will write.
static viz::SharedImageFormat GetRGBPixelsOutputFormat();
// Copy the contents of |video_frame| to |texture| of |destination_gl|.
//
// The format of |video_frame| must be VideoFrame::NATIVE_TEXTURE.
bool CopyVideoFrameTexturesToGLTexture(
viz::RasterContextProvider* raster_context_provider,
gpu::gles2::GLES2Interface* destination_gl,
scoped_refptr<VideoFrame> video_frame,
unsigned int target,
unsigned int texture,
unsigned int internal_format,
unsigned int format,
unsigned int type,
int level,
bool premultiply_alpha,
bool flip_y);
// Copy the CPU-side YUV contents of |video_frame| to texture |texture| in
// context |destination_gl|.
// |level|, |internal_format|, |type| specify target texture |texture|.
// The format of |video_frame| must be mappable.
// |context_3d| has a GrContext that may be used during the copy.
// CorrectLastImageDimensions() ensures that the source texture will be
// cropped to |visible_rect|. Returns true on success.
bool CopyVideoFrameYUVDataToGLTexture(
viz::RasterContextProvider* raster_context_provider,
gpu::gles2::GLES2Interface* destination_gl,
scoped_refptr<VideoFrame> video_frame,
unsigned int target,
unsigned int texture,
unsigned int internal_format,
unsigned int format,
unsigned int type,
int level,
bool premultiply_alpha,
bool flip_y);
// Calls texImage2D where the texture image data source is the contents of
// |video_frame|. Texture |texture| needs to be created and bound to |target|
// before this call and the binding is active upon return.
// This is an optimization of WebGL |video_frame| TexImage2D implementation
// for specific combinations of |video_frame| and |texture| formats; e.g. if
// |frame format| is Y16, optimizes conversion of normalized 16-bit content
// and calls texImage2D to |texture|. |level|, |internal_format|, |format| and
// |type| are WebGL texImage2D parameters.
// Returns false if there is no implementation for given parameters.
static bool TexImage2D(unsigned target,
unsigned texture,
gpu::gles2::GLES2Interface* gl,
const gpu::Capabilities& gpu_capabilities,
VideoFrame* video_frame,
int level,
int internalformat,
unsigned format,
unsigned type,
bool flip_y,
bool premultiply_alpha);
// Calls texSubImage2D where the texture image data source is the contents of
// |video_frame|.
// This is an optimization of WebGL |video_frame| TexSubImage2D implementation
// for specific combinations of |video_frame| and texture |format| and |type|;
// e.g. if |frame format| is Y16, converts unsigned 16-bit value to target
// |format| and calls WebGL texSubImage2D. |level|, |format|, |type|,
// |xoffset| and |yoffset| are texSubImage2D parameters.
// Returns false if there is no implementation for given parameters.
static bool TexSubImage2D(unsigned target,
gpu::gles2::GLES2Interface* gl,
VideoFrame* video_frame,
int level,
unsigned format,
unsigned type,
int xoffset,
int yoffset,
bool flip_y,
bool premultiply_alpha);
// Copies VideoFrame contents to the `destination` shared image. if
// `use_visible_rect` is set to true, only `VideoFrame::visible_rect()`
// portion is copied, otherwise copies all underlying buffer.
[[nodiscard]] gpu::SyncToken CopyVideoFrameToSharedImage(
viz::RasterContextProvider* raster_context_provider,
scoped_refptr<VideoFrame> video_frame,
const gpu::MailboxHolder& destination,
bool use_visible_rect);
// Check whether video frame can be uploaded through
// CopyVideoFrameToSharedImage(). The limitation comes from
// VideoFrameYUVConverter.
bool CanUseCopyVideoFrameToSharedImage(const VideoFrame& video_frame);
// In general, We hold the most recently painted frame to increase the
// performance for the case that the same frame needs to be painted
// repeatedly. Call this function if you are sure the most recent frame will
// never be painted again, so we can release the resource.
void ResetCache();
// Used for unit test.
gfx::Size LastImageDimensionsForTesting();
private:
// This structure wraps information extracted out of a VideoFrame and/or
// constructed out of it. The various calls in PaintCanvasVideoRenderer must
// not keep a reference to the VideoFrame so necessary data is extracted out
// of it.
struct Cache {
explicit Cache(VideoFrame::ID frame_id);
~Cache();
// VideoFrame::unique_id() of the videoframe used to generate the cache.
VideoFrame::ID frame_id;
// A PaintImage that can be used to draw into a PaintCanvas. This is sized
// to the visible size of the VideoFrame. Its contents are generated lazily.
cc::PaintImage paint_image;
// The backing for the source texture. This is also responsible for managing
// the lifetime of the texture.
sk_sp<VideoTextureBacking> texture_backing;
// The GL texture ID used in non-OOP code path.
// This is only set if the VideoFrame was texture-backed.
uint32_t source_texture = 0;
// The allocated size of VideoFrame texture.
// This is only set if the VideoFrame was texture-backed.
gfx::Size coded_size;
// The visible subrect of |coded_size| that represents the logical contents
// of the frame after cropping.
// This is only set if the VideoFrame was texture-backed.
gfx::Rect visible_rect;
// Used to allow recycling of the previous shared image. This requires that
// no external users have access to this resource via SkImage. Returns true
// if the existing resource can be recycled.
bool Recycle();
};
// Update the cache holding the most-recently-painted frame. Returns false
// if the image couldn't be updated.
bool UpdateLastImage(scoped_refptr<VideoFrame> video_frame,
viz::RasterContextProvider* raster_context_provider);
bool PrepareVideoFrame(scoped_refptr<VideoFrame> video_frame,
viz::RasterContextProvider* raster_context_provider,
const gpu::MailboxHolder& dest_holder);
std::optional<Cache> cache_;
// If |cache_| is not used for a while, it's deleted to save memory.
base::DelayTimer cache_deleting_timer_;
// Stable paint image id to provide to draw image calls.
cc::PaintImage::Id renderer_stable_id_;
// Used for DCHECKs to ensure method calls executed in the correct thread.
SEQUENCE_CHECKER(sequence_checker_);
struct YUVTextureCache {
YUVTextureCache();
~YUVTextureCache();
void Reset();
// The ContextProvider that holds the texture.
scoped_refptr<viz::RasterContextProvider> raster_context_provider;
// The size of the texture.
gfx::Size size;
// The RGB shared image backing the texture.
scoped_refptr<gpu::ClientSharedImage> rgb_shared_image;
// Cache of YUV shared images that are created to upload CPU video frame
// data to the GPU.
std::unique_ptr<VideoFrameSharedImageCache> yuv_shared_image;
// A SyncToken after last usage, used for reusing or destroying texture and
// shared image.
gpu::SyncToken sync_token;
};
YUVTextureCache yuv_cache_;
};
} // namespace media
#endif // MEDIA_RENDERERS_PAINT_CANVAS_VIDEO_RENDERER_H_