summaryrefslogtreecommitdiffstats
path: root/dom/media/encoder/VP8TrackEncoder.h
blob: c0e0d3a92959c75daa5c42b66676e82e794fb2be (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
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef VP8TrackEncoder_h_
#define VP8TrackEncoder_h_

#include "TrackEncoder.h"

#include "mozilla/RollingMean.h"
#include "TimeUnits.h"
#include "vpx/vpx_codec.h"

namespace mozilla {

typedef struct vpx_codec_ctx vpx_codec_ctx_t;
typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
typedef struct vpx_image vpx_image_t;

class VP8Metadata;

/**
 * VP8TrackEncoder implements VideoTrackEncoder by using the libvpx library.
 * We implement a realtime and variable frame rate encoder. In order to achieve
 * that, there is a frame-drop encoding policy implemented in Encode().
 */
class VP8TrackEncoder : public VideoTrackEncoder {
  enum EncodeOperation {
    ENCODE_NORMAL_FRAME,  // VP8 track encoder works normally.
    ENCODE_I_FRAME,       // The next frame will be encoded as I-Frame.
    SKIP_FRAME,           // Skip the next frame.
  };

 public:
  VP8TrackEncoder(RefPtr<DriftCompensator> aDriftCompensator,
                  TrackRate aTrackRate,
                  MediaQueue<EncodedFrame>& aEncodedDataQueue,
                  FrameDroppingMode aFrameDroppingMode,
                  Maybe<float> aKeyFrameIntervalFactor = Nothing());
  virtual ~VP8TrackEncoder();

  already_AddRefed<TrackMetadataBase> GetMetadata() final;

 protected:
  nsresult Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
                int32_t aDisplayHeight, float aEstimatedFrameRate) final;

 private:
  // Initiates the underlying vpx encoder.
  nsresult InitInternal(int32_t aWidth, int32_t aHeight,
                        int32_t aMaxKeyFrameDistance);

  // Get the EncodeOperation for next target frame.
  EncodeOperation GetNextEncodeOperation(TimeDuration aTimeElapsed,
                                         TimeDuration aProcessedDuration);

  // Extracts the encoded data from the underlying encoder and returns it.
  // Return value: An EncodedFrame if a frame was extracted.
  //               nullptr if we reached end-of-stream or nothing was available
  //                       from the underlying encoder.
  //               An error nsresult otherwise.
  Result<RefPtr<EncodedFrame>, nsresult> ExtractEncodedData();

  // Takes the data in aSegment, encodes it, extracts it, and pushes it to
  // mEncodedDataQueue.
  nsresult Encode(VideoSegment* aSegment) final;

  // Prepare the input data to the mVPXImageWrapper for encoding.
  nsresult PrepareRawFrame(VideoChunk& aChunk);

  // Re-configures an existing encoder with a new frame size.
  nsresult Reconfigure(int32_t aWidth, int32_t aHeight,
                       int32_t aMaxKeyFrameDistance);

  // Destroys the context and image wrapper. Does not de-allocate the structs.
  void Destroy();

  // Helper that calculates the desired max keyframe distance (vp8 config's
  // max_kf_dist) based on configured key frame interval and recent framerate.
  // Returns Nothing if not enough input data is available.
  Maybe<int32_t> CalculateMaxKeyFrameDistance(
      Maybe<float> aEstimatedFrameRate = Nothing()) const;

  void SetMaxKeyFrameDistance(int32_t aMaxKeyFrameDistance);

  // VP8 Metadata, set on successfuly Init and never modified again.
  RefPtr<VP8Metadata> mMetadata;

  // The width the encoder is currently configured with. The input frames to the
  // underlying encoder must match this width, i.e., the underlying encoder will
  // not do any resampling.
  int mFrameWidth = 0;

  // The height the encoder is currently configured with. The input frames to
  // the underlying encoder must match this height, i.e., the underlying encoder
  // will not do any resampling.
  int mFrameHeight = 0;

  // Encoded timestamp.
  TrackTime mEncodedTimestamp = 0;

  // Total duration in mTrackRate extracted from the underlying encoder.
  CheckedInt64 mExtractedDuration;

  // Total duration extracted from the underlying encoder.
  media::TimeUnit mExtractedDurationUs;

  // Muted frame, we only create it once.
  RefPtr<layers::Image> mMuteFrame;

  // I420 frame, for converting to I420.
  UniquePtr<uint8_t[]> mI420Frame;
  size_t mI420FrameSize = 0;

  /**
   * A duration of non-key frames in mTrackRate.
   */
  TrackTime mDurationSinceLastKeyframe = 0;

  /**
   * The max interval at which a keyframe gets forced (causing video quality
   * degradation). The encoder is configured to encode keyframes more often than
   * this, though it can vary based on frame rate.
   */
  const TimeDuration mKeyFrameInterval;

  /**
   * A factor used to multiply the estimated key-frame-interval based on
   * mKeyFrameInterval (ms) with when configuring kf_max_dist in the encoder.
   * The goal is to set it a bit below 1.0 to avoid falling back to forcing
   * keyframes.
   * NB that for purposes of testing the mKeyFrameInterval fallback this may be
   *    set to values higher than 1.0.
   */
  float mKeyFrameIntervalFactor;

  /**
   * Time when we last updated the key-frame-distance.
   */
  media::TimeUnit mLastKeyFrameDistanceUpdate;

  /**
   * The frame duration value last used to configure kf_max_dist.
   */
  Maybe<int32_t> mMaxKeyFrameDistance;

  /**
   * The mean duration of recent frames.
   */
  RollingMean<TimeDuration, TimeDuration> mMeanFrameDuration{30};

  /**
   * The mean wall-clock time it took to encode recent frames.
   */
  RollingMean<TimeDuration, TimeDuration> mMeanFrameEncodeDuration{30};

  // VP8 relative members.
  // Codec context structure.
  vpx_codec_ctx_t mVPXContext;
  // Image Descriptor.
  vpx_image_t mVPXImageWrapper;
};

}  // namespace mozilla

#endif