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

media / gpu / mac / vt_video_encode_accelerator_mac.h [blame]

// Copyright 2016 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_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
#define MEDIA_GPU_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_

#include <memory>

#include "base/apple/scoped_cftyperef.h"
#include "base/containers/circular_deque.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "media/base/bitrate.h"
#include "media/base/mac/videotoolbox_helpers.h"
#include "media/base/video_codecs.h"
#include "media/gpu/media_gpu_export.h"
#include "media/media_buildflags.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/color_space.h"

namespace media {

class MediaLog;

// VideoToolbox.framework implementation of the VideoEncodeAccelerator
// interface for MacOSX. VideoToolbox makes no guarantees that it is thread
// safe, so this object is pinned to the thread on which it is constructed.
class MEDIA_GPU_EXPORT VTVideoEncodeAccelerator
    : public VideoEncodeAccelerator {
 public:
  VTVideoEncodeAccelerator();

  VTVideoEncodeAccelerator(const VTVideoEncodeAccelerator&) = delete;
  VTVideoEncodeAccelerator& operator=(const VTVideoEncodeAccelerator&) = delete;

  // VideoEncodeAccelerator implementation.
  SupportedProfiles GetSupportedProfiles() override;

  bool Initialize(const Config& config,
                  Client* client,
                  std::unique_ptr<MediaLog> media_log = nullptr) override;
  void Encode(scoped_refptr<VideoFrame> frame, bool force_keyframe) override;
  void UseOutputBitstreamBuffer(BitstreamBuffer buffer) override;
  void RequestEncodingParametersChange(
      const Bitrate& bitrate,
      uint32_t framerate,
      const std::optional<gfx::Size>& size) override;
  void Destroy() override;
  void Flush(FlushCallback flush_callback) override;
  bool IsFlushSupported() override;

 private:
  // Holds the associated data of a video frame being processed.
  struct InProgressFrameEncode;

  // Holds output buffers coming from the encoder.
  struct EncodeOutput;

  // Holds output buffers coming from the client ready to be filled.
  struct BitstreamBufferRef;

  ~VTVideoEncodeAccelerator() override;

  // Compression session callback function to handle compressed frames.
  static void CompressionCallback(void* encoder_opaque,
                                  void* request_opaque,
                                  OSStatus status,
                                  VTEncodeInfoFlags info,
                                  CMSampleBufferRef sbuf);
  void CompressionCallbackTask(OSStatus status,
                               std::unique_ptr<EncodeOutput> encode_output);

  // Copy CMSampleBuffer into a BitstreamBuffer and return it to the |client_|.
  void ReturnBitstreamBuffer(
      std::unique_ptr<EncodeOutput> encode_output,
      std::unique_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref);

  // Reset the encoder's compression session by destroying the existing one and
  // creating a new one. The new session is configured using
  // ConfigureCompressionSession().
  bool ResetCompressionSession();

  // Configure the current compression session using current encoder settings.
  bool ConfigureCompressionSession(VideoCodec codec);

  // Flushes the encoder. The flush callback won't be run until all pending
  // encodes have been completed.
  void MaybeRunFlushCallback();

  void SetEncoderColorSpace();

  void NotifyErrorStatus(EncoderStatus status);

  base::TimeDelta AssignMonotonicTimestamp();

  video_toolbox::ScopedVTCompressionSessionRef compression_session_;

  gfx::Size input_visible_size_;
  size_t bitstream_buffer_size_ = 0;
  int32_t frame_rate_ = 0;
  int num_temporal_layers_ = 1;
  VideoCodecProfile profile_ = H264PROFILE_BASELINE;
  VideoCodec codec_ = VideoCodec::kH264;

  media::Bitrate bitrate_;

  // If True, the encoder fails initialization if setting of session's property
  // kVTCompressionPropertyKey_MaxFrameDelayCount returns an error.
  // Encoder can work even after if MaxFrameDelayCount fails, but it'll
  // have larger latency on low resolutions, and it's bad for RTC.
  // Context: https://crbug.com/1195177 https://crbug.com/webrtc/7304
  bool require_low_delay_ = true;

  // Used to control selection of OS software encoders.
  Config::EncoderType required_encoder_type_ = Config::EncoderType::kHardware;

  // Bitstream buffers ready to be used to return encoded output as a FIFO.
  base::circular_deque<std::unique_ptr<BitstreamBufferRef>>
      bitstream_buffer_queue_;

  // EncodeOutput needs to be copied into a BitstreamBufferRef as a FIFO.
  base::circular_deque<std::unique_ptr<EncodeOutput>> encoder_output_queue_;

  // Our original calling task runner for the child thread.
  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
  SEQUENCE_CHECKER(sequence_checker_);

  // To expose client callbacks from VideoEncodeAccelerator.
  raw_ptr<Client> client_ = nullptr;

  std::unique_ptr<MediaLog> media_log_;

  // Tracking information for ensuring flushes aren't completed until all
  // pending encodes have been returned.
  int pending_encodes_ = 0;
  FlushCallback pending_flush_cb_;

  // Color space of the first frame sent to Encode().
  std::optional<gfx::ColorSpace> encoder_color_space_;
  bool can_set_encoder_color_space_ = true;

  bool encoder_produces_svc_spec_compliant_bitstream_ = false;

  // Monotonically-growing timestamp that will be assigned to the next frame
  base::TimeDelta next_timestamp_;

  // Declared last to ensure that all weak pointers are invalidated before
  // other destructors run.
  base::WeakPtr<VTVideoEncodeAccelerator> encoder_weak_ptr_;
  base::WeakPtrFactory<VTVideoEncodeAccelerator> encoder_weak_factory_{this};
};

}  // namespace media

#endif  // MEDIA_GPU_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_