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

media / base / video_util.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_BASE_VIDEO_UTIL_H_
#define MEDIA_BASE_VIDEO_UTIL_H_

#include <stdint.h>

#include "base/memory/scoped_refptr.h"
#include "media/base/encoder_status.h"
#include "media/base/media_export.h"
#include "media/base/video_types.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

namespace base {
class TimeDelta;
}  // namespace base

namespace gpu {
struct Capabilities;
namespace raster {
class RasterInterface;
}  // namespace raster
}  // namespace gpu

namespace libyuv {
struct YuvConstants;
}  // namespace libyuv

namespace viz {
class SharedImageFormat;
}  // namespace viz

namespace media {

class VideoFramePool;
class VideoFrame;

// Fills |frame| containing YUV data to the given color values.
MEDIA_EXPORT void FillYUV(VideoFrame* frame, uint8_t y, uint8_t u, uint8_t v);

// Fills |frame| containing YUVA data with the given color values.
MEDIA_EXPORT void FillYUVA(VideoFrame* frame,
                           uint8_t y,
                           uint8_t u,
                           uint8_t v,
                           uint8_t a);

// Creates a border in |frame| such that all pixels outside of |view_area| are
// black. Only YV12 and ARGB format video frames are currently supported. If
// format is YV12, the size and position of |view_area| must be even to align
// correctly with the color planes.
MEDIA_EXPORT void LetterboxVideoFrame(VideoFrame* frame,
                                      const gfx::Rect& view_area);

// Rotates |src| plane by |rotation| degree with possible flipping vertically
// and horizontally.
// |rotation| is limited to {0, 90, 180, 270}.
// |width| and |height| are expected to be even numbers.
// Both |src| and |dest| planes are packed and have same |width| and |height|.
// When |width| != |height| and rotated by 90/270, only the maximum square
// portion located in the center is rotated. For example, for width=640 and
// height=480, the rotated area is 480x480 located from row 0 through 479 and
// from column 80 through 559. The leftmost and rightmost 80 columns are
// ignored for both |src| and |dest|.
// The caller is responsible for blanking out the margin area.
MEDIA_EXPORT void RotatePlaneByPixels(const uint8_t* src,
                                      uint8_t* dest,
                                      int width,
                                      int height,
                                      int rotation,  // Clockwise.
                                      bool flip_vert,
                                      bool flip_horiz);

// Return the largest centered rectangle with the same aspect ratio of |content|
// that fits entirely inside of |bounds|.  If |content| is empty, its aspect
// ratio would be undefined; and in this case an empty Rect would be returned.
MEDIA_EXPORT gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
                                              const gfx::Size& content);

// Same as ComputeLetterboxRegion(), except ensure the result has even-numbered
// x, y, width, and height. |bounds| must already have even-numbered
// coordinates, but the |content| size can be anything.
//
// This is useful for ensuring content scaled and converted to I420 does not
// have color distortions around the edges in a letterboxed video frame. Note
// that, in cases where ComputeLetterboxRegion() would return a 1x1-sized Rect,
// this function could return either a 0x0-sized Rect or a 2x2-sized Rect.
// Note that calling this function with `bounds` that already have the aspect
// ratio of `content` is not guaranteed to be a no-op (for context, see
// https://crbug.com/1323367).
MEDIA_EXPORT gfx::Rect ComputeLetterboxRegionForI420(const gfx::Rect& bounds,
                                                     const gfx::Size& content);

// Shrinks the given |rect| by the minimum amount necessary to align its corners
// to even-numbered coordinates. |rect| is assumed to have bounded limit values,
// and may have negative bounds.
MEDIA_EXPORT gfx::Rect MinimallyShrinkRectForI420(const gfx::Rect& rect);

// Return a scaled |size| whose area is less than or equal to |target|, where
// one of its dimensions is equal to |target|'s.  The aspect ratio of |size| is
// preserved as closely as possible.  If |size| is empty, the result will be
// empty.
MEDIA_EXPORT gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
                                                  const gfx::Size& target);

// Return a scaled |size| whose area is greater than or equal to |target|, where
// one of its dimensions is equal to |target|'s.  The aspect ratio of |size| is
// preserved as closely as possible.  If |size| is empty, the result will be
// empty.
MEDIA_EXPORT gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
                                                  const gfx::Size& target);

// Calculates the largest sub-rectangle of a rectangle of size |size| with
// roughly the same aspect ratio as |target| and centered both horizontally
// and vertically within the rectangle. It's "roughly" the same aspect ratio
// because its dimensions may be rounded down to be a multiple of |alignment|.
// The origin of the rectangle is also aligned down to a multiple of
// |alignment|. Note that |alignment| must be a power of 2.
MEDIA_EXPORT gfx::Rect CropSizeForScalingToTarget(const gfx::Size& size,
                                                  const gfx::Size& target,
                                                  size_t alignment = 1u);

// Returns the size of a rectangle whose upper left corner is at the origin (0,
// 0) and whose bottom right corner is the same as that of |rect|. This is
// useful to get the size of a buffer that contains the visible rectangle plus
// the non-visible area above and to the left of the visible rectangle.
//
// An example to illustrate: suppose the visible rectangle of a decoded frame is
// 10,10,100,100. The size of this rectangle is 90x90. However, we need to
// create a texture of size 100x100 because the client will want to sample from
// the texture starting with uv coordinates corresponding to 10,10.
MEDIA_EXPORT gfx::Size GetRectSizeFromOrigin(const gfx::Rect& rect);

// Returns |size| with only one of its dimensions increased such that the result
// matches the aspect ratio of |target|.  This is different from
// ScaleSizeToEncompassTarget() in two ways: 1) The goal is to match the aspect
// ratio of |target| rather than that of |size|.  2) Only one of the dimensions
// of |size| may change, and it may only be increased (padded).  If either
// |size| or |target| is empty, the result will be empty.
MEDIA_EXPORT gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
                                             const gfx::Size& target);

// A helper function to map GpuMemoryBuffer-based VideoFrame. This function
// maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
// format, unless the video frame is backed by DXGI GMB.
// The returned VideoFrame owns the |frame|.
// If the underlying buffer is DXGI, then it will be copied to shared memory
// in GPU process.
MEDIA_EXPORT scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
    scoped_refptr<VideoFrame> frame);

// A helper function to map GpuMemoryBuffer-based VideoFrame. This function
// maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
// format, unless the video frame is backed by DXGI GMB.
// The returned VideoFrame owns the |frame|.
// If the underlying buffer is DXGI, then it will be copied to shared memory
// in GPU process.
// If the GPU process is involved, the callback will be called in the
// GpuMemoryThread. Otherwise it will be involved immediately in the current
// sequence.
MEDIA_EXPORT void ConvertToMemoryMappedFrameAsync(
    scoped_refptr<VideoFrame> frame,
    base::OnceCallback<void(scoped_refptr<VideoFrame>)> result_cb);

// This function synchronously reads pixel data from textures associated with
// |txt_frame| and creates a new CPU memory backed frame. It's needed because
// existing video encoders can't handle texture backed frames.
//
// TODO(crbug.com/40162806): Combine this function with
// media::ConvertAndScaleFrame and put it into a new class
// media:FrameSizeAndFormatConverter.
MEDIA_EXPORT scoped_refptr<VideoFrame> ReadbackTextureBackedFrameToMemorySync(
    VideoFrame& txt_frame,
    gpu::raster::RasterInterface* ri,
    const gpu::Capabilities& caps,
    VideoFramePool* pool = nullptr);

// Synchronously reads a single plane. |src_rect| is relative to the plane,
// which may be smaller than |frame| due to subsampling.
MEDIA_EXPORT bool ReadbackTexturePlaneToMemorySync(
    VideoFrame& src_frame,
    size_t src_plane,
    gfx::Rect& src_rect,
    uint8_t* dest_pixels,
    size_t dest_stride,
    gpu::raster::RasterInterface* ri,
    const gpu::Capabilities& caps);

// Converts a frame with I420A format into I420 by dropping alpha channel.
MEDIA_EXPORT scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
    scoped_refptr<VideoFrame> frame);

// Copy I420 video frame to match the required coded size and pad the region
// outside the visible rect repeatedly with the last column / row up to the
// coded size of |dst_frame|. Return false when |dst_frame| is empty or visible
// rect is empty.
// One application is content mirroring using HW encoder. As the required coded
// size for encoder is unknown before capturing, memory copy is needed when the
// coded size does not match the requirement. Padding can improve the encoding
// efficiency in this case, as the encoder will encode the whole coded region.
// Performance-wise, this function could be expensive as it does memory copy of
// the whole visible rect.
// Note:
// 1. |src_frame| and |dst_frame| should have same size of visible rect.
// 2. The visible rect's origin of |dst_frame| should be (0,0).
// 3. |dst_frame|'s coded size (both width and height) should be larger than or
// equal to the visible size, since the visible region in both frames should be
// identical.
[[nodiscard]] MEDIA_EXPORT bool I420CopyWithPadding(const VideoFrame& src_frame,
                                                    VideoFrame* dst_frame);

// Converts kRGBA_8888_SkColorType and kBGRA_8888_SkColorType to the appropriate
// ARGB, XRGB, ABGR, or XBGR format.
MEDIA_EXPORT VideoPixelFormat
VideoPixelFormatFromSkColorType(SkColorType sk_color_type, bool is_opaque);

// Get SkColor suitable type for various formats and planes.
MEDIA_EXPORT SkColorType SkColorTypeForPlane(VideoPixelFormat format,
                                             size_t plane);

// Backs a VideoFrame with a SkImage. The created frame takes a ref on the
// provided SkImage to make this operation zero copy. Only works with CPU
// backed images.
MEDIA_EXPORT scoped_refptr<VideoFrame> CreateFromSkImage(
    sk_sp<SkImage> sk_image,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp,
    bool force_opaque = false);

// Utility to convert a SharedImageFormat to SkYUVAInfo.
SkYUVAInfo::PlaneConfig ToSkYUVAPlaneConfig(viz::SharedImageFormat format);
SkYUVAInfo::Subsampling ToSkYUVASubsampling(viz::SharedImageFormat format);

// Returns the libyuv RGB conversion matrix for a given skia YUV color space.
// If `output_argb_matrix` is true a ARGB matrix will be provided, if false a
// ABGR matrix will be provided.
//
// NOTE: When using the ABGR matrix, you must also swap the V,U parameters to
// whichever libyuv function you're using.
MEDIA_EXPORT const libyuv::YuvConstants* GetYuvContantsForColorSpace(
    SkYUVColorSpace cs,
    bool output_argb_matrix);

}  // namespace media

#endif  // MEDIA_BASE_VIDEO_UTIL_H_