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_