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

media / base / video_encoder.h [blame]

// Copyright 2020 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_ENCODER_H_
#define MEDIA_BASE_VIDEO_ENCODER_H_

#include <cstdint>
#include <optional>
#include <vector>

#include "base/containers/heap_array.h"
#include "base/functional/callback.h"
#include "base/task/bind_post_task.h"
#include "base/time/time.h"
#include "media/base/bitrate.h"
#include "media/base/encoder_status.h"
#include "media/base/media_export.h"
#include "media/base/svc_scalability_mode.h"
#include "media/base/video_codecs.h"
#include "media/base/video_types.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"

namespace media {

struct VideoEncoderInfo;
class VideoFrame;

// Returns the drop frame threshold for media::VideoEncoder used in WebCodecs.
MEDIA_EXPORT uint8_t GetDefaultVideoEncoderDropFrameThreshold();

MEDIA_EXPORT uint32_t GetDefaultVideoEncodeBitrate(gfx::Size frame_size,
                                                   uint32_t framerate);

MEDIA_EXPORT int GetNumberOfThreadsForSoftwareEncoding(gfx::Size frame_size);

// Encoded video frame, its data and metadata.
struct MEDIA_EXPORT VideoEncoderOutput {
  VideoEncoderOutput();
  VideoEncoderOutput(VideoEncoderOutput&&);
  ~VideoEncoderOutput();

  // Feel free take these buffers out and use underlying memory as is without
  // copying.
  base::HeapArray<uint8_t> data;
  base::HeapArray<uint8_t> alpha_data;

  base::TimeDelta timestamp;
  bool key_frame = false;
  int temporal_id = 0;
  gfx::ColorSpace color_space;

  // Some platforms may adjust the encoding size to meet hardware requirements.
  // If not set, the encoded size is the same as configured.
  std::optional<gfx::Size> encoded_size;
};

class MEDIA_EXPORT VideoEncoder {
 public:
  // TODO: Move this to a new file if there are more codec specific options.
  struct MEDIA_EXPORT AvcOptions {
    bool produce_annexb = false;
  };

  struct MEDIA_EXPORT HevcOptions {
    bool produce_annexb = false;
  };

  enum class LatencyMode { Realtime, Quality };
  enum class ContentHint { Camera, Screen };

  struct MEDIA_EXPORT Options {
    Options();
    Options(const Options&);
    ~Options();

    std::string ToString();

    std::optional<Bitrate> bitrate;
    std::optional<double> framerate;

    gfx::Size frame_size;

    std::optional<int> keyframe_interval = 10000;

    LatencyMode latency_mode = LatencyMode::Realtime;

    std::optional<SVCScalabilityMode> scalability_mode;

    std::optional<ContentHint> content_hint;

    // Controls encoded pixel format.
    std::optional<VideoChromaSampling> subsampling;

    // Controls encoded bit depth.
    std::optional<uint8_t> bit_depth;

    // Only used for H264 encoding.
    AvcOptions avc;

    // Only used for HEVC encoding.
    HevcOptions hevc;

    // Allow clients to choose reference pattern for frames.
    bool manual_reference_buffer_control = false;
  };

  struct MEDIA_EXPORT EncodeOptions {
    explicit EncodeOptions(bool key_frame);
    EncodeOptions();
    EncodeOptions(const EncodeOptions&);
    ~EncodeOptions();
    bool key_frame = false;
    // Per-frame codec-specific quantizer value.
    // Should only be used when encoder configured with kExternal bitrate mode.
    std::optional<int> quantizer;

    // Ids of the encoder's buffers (past frames) that this frame can reference
    // for inter-frame prediction.
    // Valid values: [0..VideoEncoderInfo::number_of_manual_reference_buffers)
    absl::InlinedVector<uint8_t, 4> reference_buffers;

    // Id of the encoder's buffer where this frame should be kept after
    // encoding. This frames can later be referenced via `reference_buffers`.
    // If empty, this frame can't be used for inter-frame prediction by future
    // frames.
    // Valid values: [0..VideoEncoderInfo::number_of_manual_reference_buffers)
    std::optional<uint8_t> update_buffer;
  };

  // A sequence of codec specific bytes, commonly known as extradata.
  // If available, it should be given to the decoder as part of the
  // decoder config.
  using CodecDescription = std::vector<uint8_t>;

  // Provides the VideoEncoder client with information about the specific
  // encoder implementation.
  using EncoderInfoCB =
      base::RepeatingCallback<void(const VideoEncoderInfo& encoder_info)>;

  // Callback for VideoEncoder to report an encoded video frame whenever it
  // becomes available.
  using OutputCB =
      base::RepeatingCallback<void(VideoEncoderOutput output,
                                   std::optional<CodecDescription>)>;

  // Callback to report success and errors in encoder calls.
  using EncoderStatusCB = base::OnceCallback<void(EncoderStatus error)>;

  struct MEDIA_EXPORT PendingEncode {
    PendingEncode();
    PendingEncode(PendingEncode&&);
    ~PendingEncode();
    EncoderStatusCB done_callback;
    scoped_refptr<VideoFrame> frame;
    EncodeOptions options;
  };

  VideoEncoder();
  VideoEncoder(const VideoEncoder&) = delete;
  VideoEncoder& operator=(const VideoEncoder&) = delete;
  virtual ~VideoEncoder();

  // Initializes a VideoEncoder with the given |options|, executing the
  // |done_cb| upon completion. |output_cb| is called for each encoded frame
  // produced by the coder.
  //
  // Note:
  // 1) Can't be called more than once for the same instance of the encoder.
  // 2) No VideoEncoder calls should be made before |done_cb| is executed.
  virtual void Initialize(VideoCodecProfile profile,
                          const Options& options,
                          EncoderInfoCB info_cb,
                          OutputCB output_cb,
                          EncoderStatusCB done_cb) = 0;

  // Requests a |frame| to be encoded. The status of the encoder and the frame
  // are returned via the provided callback |done_cb|.
  //
  // |done_cb| will not be called from within this method, and that it will be
  // called even if Encode() is never called again.

  // After the frame, or several frames, are encoded the encoder calls
  // |output_cb| specified in Initialize() for available VideoEncoderOutput.
  // |output_cb| may be called before or after |done_cb|,
  // including before Encode() returns.
  // Encode() does not expect EOS frames, use Flush() to finalize the stream
  // and harvest the outputs.
  virtual void Encode(scoped_refptr<VideoFrame> frame,
                      const EncodeOptions& options,
                      EncoderStatusCB done_cb) = 0;

  // Adjust encoder options and the output callback for future frames, executing
  // the |done_cb| upon completion.
  //
  // Note:
  // 1. Not all options can be changed on the fly.
  // 2. ChangeOptions() should be called after calling Flush() and waiting
  // for it to finish.
  virtual void ChangeOptions(const Options& options,
                             OutputCB output_cb,
                             EncoderStatusCB done_cb) = 0;

  // Requests all outputs for already encoded frames to be
  // produced via |output_cb| and calls |dene_cb| after that.
  virtual void Flush(EncoderStatusCB done_cb) = 0;

  // Normally VideoEncoder implementations aren't supposed to call
  // EncoderInfoCB, OutputCB, and EncoderStatusCB directly from inside any of
  // VideoEncoder's methods.  This method tells VideoEncoder that all callbacks
  // can be called directly from within its methods. It saves extra thread hops
  // if it's known that all callbacks already point to a task runner different
  // from the current one.
  virtual void DisablePostedCallbacks();

 protected:
  template <typename Callback>
  Callback BindCallbackToCurrentLoopIfNeeded(Callback callback) {
    return post_callbacks_
               ? base::BindPostTaskToCurrentDefault(std::move(callback))
               : std::move(callback);
  }

 private:
  bool post_callbacks_ = true;
};

}  // namespace media

#endif  // MEDIA_BASE_VIDEO_ENCODER_H_