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_