summaryrefslogtreecommitdiff
path: root/chromium/media/cast/encoding/external_video_encoder.h
blob: 4f81e16d4a49ade6c2f3b58371bfa4ac7020ba33 (plain)
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
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_CAST_ENCODING_EXTERNAL_VIDEO_ENCODER_H_
#define MEDIA_CAST_ENCODING_EXTERNAL_VIDEO_ENCODER_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>

#include "base/memory/weak_ptr.h"
#include "media/cast/cast_environment.h"
#include "media/cast/encoding/size_adaptable_video_encoder_base.h"
#include "media/cast/encoding/video_encoder.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/geometry/size.h"

namespace media {
namespace cast {

// Cast MAIN thread proxy to the internal media::VideoEncodeAccelerator
// implementation running on a separate thread.  Encodes media::VideoFrames and
// emits media::cast::EncodedFrames.
class ExternalVideoEncoder final : public VideoEncoder {
 public:
  // Returns true if the current platform and system configuration supports
  // using ExternalVideoEncoder with the given |video_config|.
  static bool IsSupported(const FrameSenderConfig& video_config);

  // Returns true if the external encoder should be used for a codec with a
  // given receiver and set of VEA profiles. Some receivers have implementation
  // bugs that keep the external encoder from being used even if it is supported
  // by the sender.
  static bool IsRecommended(
      Codec codec,
      base::StringPiece receiver_model_name,
      const std::vector<media::VideoEncodeAccelerator::SupportedProfile>&
          profiles);

  ExternalVideoEncoder(
      const scoped_refptr<CastEnvironment>& cast_environment,
      const FrameSenderConfig& video_config,
      const gfx::Size& frame_size,
      FrameId first_frame_id,
      StatusChangeCallback status_change_cb,
      const CreateVideoEncodeAcceleratorCallback& create_vea_cb);

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

  ~ExternalVideoEncoder() final;

  // VideoEncoder implementation.
  bool EncodeVideoFrame(scoped_refptr<media::VideoFrame> video_frame,
                        base::TimeTicks reference_time,
                        FrameEncodedCallback frame_encoded_callback) final;
  void SetBitRate(int new_bit_rate) final;
  void GenerateKeyFrame() final;

 private:
  class VEAClientImpl;

  // Called from the destructor (or earlier on error), to schedule destruction
  // of |client_| via the encoder task runner.
  void DestroyClientSoon();

  // Method invoked by the CreateVideoEncodeAcceleratorCallback to construct a
  // VEAClientImpl to own and interface with a new |vea|.  Upon return,
  // |client_| holds a reference to the new VEAClientImpl.
  void OnCreateVideoEncodeAccelerator(
      const FrameSenderConfig& video_config,
      FrameId first_frame_id,
      const StatusChangeCallback& status_change_cb,
      scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
      std::unique_ptr<media::VideoEncodeAccelerator> vea);

  const scoped_refptr<CastEnvironment> cast_environment_;

  // The size of the visible region of the video frames to be encoded.
  const gfx::Size frame_size_;

  int bit_rate_;
  bool key_frame_requested_ = false;

  scoped_refptr<VEAClientImpl> client_;

  // Provides a weak pointer for the OnCreateVideoEncoderAccelerator() callback.
  // NOTE: Weak pointers must be invalidated before all other member variables.
  base::WeakPtrFactory<ExternalVideoEncoder> weak_factory_{this};
};

// An implementation of SizeAdaptableVideoEncoderBase to proxy for
// ExternalVideoEncoder instances.
class SizeAdaptableExternalVideoEncoder final
    : public SizeAdaptableVideoEncoderBase {
 public:
  SizeAdaptableExternalVideoEncoder(
      const scoped_refptr<CastEnvironment>& cast_environment,
      const FrameSenderConfig& video_config,
      StatusChangeCallback status_change_cb,
      const CreateVideoEncodeAcceleratorCallback& create_vea_cb);

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

  ~SizeAdaptableExternalVideoEncoder() final;

 protected:
  std::unique_ptr<VideoEncoder> CreateEncoder() final;

 private:
  // Special callbacks needed by media::cast::ExternalVideoEncoder.
  const CreateVideoEncodeAcceleratorCallback create_vea_cb_;
};

// A utility class for examining the sequence of frames sent to an external
// encoder, and returning an estimate of the what the software VP8 encoder would
// have used for a quantizer value when encoding each frame.  The quantizer
// value is related to the complexity of the content of the frame.
class QuantizerEstimator {
 public:
  static constexpr int NO_RESULT = -1;
  static constexpr int MIN_VP8_QUANTIZER = 4;
  static constexpr int MAX_VP8_QUANTIZER = 63;

  QuantizerEstimator();

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

  ~QuantizerEstimator();

  // Discard any state related to the processing of prior frames.
  void Reset();

  // Examine |frame| and estimate and return the quantizer value the software
  // VP8 encoder would have used when encoding the frame, in the range
  // [4.0,63.0].  If |frame| is not in planar YUV format, or its size is empty,
  // this returns |NO_RESULT|.
  double EstimateForKeyFrame(const VideoFrame& frame);
  double EstimateForDeltaFrame(const VideoFrame& frame);

 private:
  // Returns true if the frame is in planar YUV format.
  static bool CanExamineFrame(const VideoFrame& frame);

  // Returns a value in the range [0,log2(num_buckets)], the Shannon Entropy
  // based on the probabilities of values falling within each of the buckets of
  // the given |histogram|.
  static double ComputeEntropyFromHistogram(const int* histogram,
                                            size_t histogram_size,
                                            int num_samples);

  // Map the |shannon_entropy| to its corresponding software VP8 quantizer.
  static double ToQuantizerEstimate(double shannon_entropy);

  // A cache of a subset of rows of pixels from the last frame examined.  This
  // is used to compute the entropy of the difference between frames, which in
  // turn is used to compute the entropy and quantizer.
  std::unique_ptr<uint8_t[]> last_frame_pixel_buffer_;
  gfx::Size last_frame_size_;
};

}  // namespace cast
}  // namespace media

#endif  // MEDIA_CAST_ENCODING_EXTERNAL_VIDEO_ENCODER_H_