• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc;
12 
13 import androidx.annotation.Nullable;
14 import org.webrtc.EncodedImage;
15 
16 /**
17  * Interface for a video encoder that can be used with WebRTC. All calls will be made on the
18  * encoding thread. The encoder may be constructed on a different thread and changing thread after
19  * calling release is allowed.
20  */
21 public interface VideoEncoder {
22   /** Settings passed to the encoder by WebRTC. */
23   public class Settings {
24     public final int numberOfCores;
25     public final int width;
26     public final int height;
27     public final int startBitrate; // Kilobits per second.
28     public final int maxFramerate;
29     public final int numberOfSimulcastStreams;
30     public final boolean automaticResizeOn;
31     public final Capabilities capabilities;
32 
33     // TODO(bugs.webrtc.org/10720): Remove.
34     @Deprecated
Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate, int numberOfSimulcastStreams, boolean automaticResizeOn)35     public Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate,
36         int numberOfSimulcastStreams, boolean automaticResizeOn) {
37       this(numberOfCores, width, height, startBitrate, maxFramerate, numberOfSimulcastStreams,
38           automaticResizeOn, new VideoEncoder.Capabilities(false /* lossNotification */));
39     }
40 
41     @CalledByNative("Settings")
Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate, int numberOfSimulcastStreams, boolean automaticResizeOn, Capabilities capabilities)42     public Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate,
43         int numberOfSimulcastStreams, boolean automaticResizeOn, Capabilities capabilities) {
44       this.numberOfCores = numberOfCores;
45       this.width = width;
46       this.height = height;
47       this.startBitrate = startBitrate;
48       this.maxFramerate = maxFramerate;
49       this.numberOfSimulcastStreams = numberOfSimulcastStreams;
50       this.automaticResizeOn = automaticResizeOn;
51       this.capabilities = capabilities;
52     }
53   }
54 
55   /** Capabilities (loss notification, etc.) passed to the encoder by WebRTC. */
56   public class Capabilities {
57     /**
58      * The remote side has support for the loss notification RTCP feedback message format, and will
59      * be sending these feedback messages if necessary.
60      */
61     public final boolean lossNotification;
62 
63     @CalledByNative("Capabilities")
Capabilities(boolean lossNotification)64     public Capabilities(boolean lossNotification) {
65       this.lossNotification = lossNotification;
66     }
67   }
68 
69   /** Additional info for encoding. */
70   public class EncodeInfo {
71     public final EncodedImage.FrameType[] frameTypes;
72 
73     @CalledByNative("EncodeInfo")
EncodeInfo(EncodedImage.FrameType[] frameTypes)74     public EncodeInfo(EncodedImage.FrameType[] frameTypes) {
75       this.frameTypes = frameTypes;
76     }
77   }
78 
79   // TODO(sakal): Add values to these classes as necessary.
80   /** Codec specific information about the encoded frame. */
81   public class CodecSpecificInfo {}
82 
83   public class CodecSpecificInfoVP8 extends CodecSpecificInfo {}
84 
85   public class CodecSpecificInfoVP9 extends CodecSpecificInfo {}
86 
87   public class CodecSpecificInfoH264 extends CodecSpecificInfo {}
88 
89   public class CodecSpecificInfoAV1 extends CodecSpecificInfo {}
90 
91   /**
92    * Represents bitrate allocated for an encoder to produce frames. Bitrate can be divided between
93    * spatial and temporal layers.
94    */
95   public class BitrateAllocation {
96     // First index is the spatial layer and second the temporal layer.
97     public final int[][] bitratesBbs;
98 
99     /**
100      * Initializes the allocation with a two dimensional array of bitrates. The first index of the
101      * array is the spatial layer and the second index in the temporal layer.
102      */
103     @CalledByNative("BitrateAllocation")
BitrateAllocation(int[][] bitratesBbs)104     public BitrateAllocation(int[][] bitratesBbs) {
105       this.bitratesBbs = bitratesBbs;
106     }
107 
108     /**
109      * Gets the total bitrate allocated for all layers.
110      */
getSum()111     public int getSum() {
112       int sum = 0;
113       for (int[] spatialLayer : bitratesBbs) {
114         for (int bitrate : spatialLayer) {
115           sum += bitrate;
116         }
117       }
118       return sum;
119     }
120   }
121 
122   /** Settings for WebRTC quality based scaling. */
123   public class ScalingSettings {
124     public final boolean on;
125     @Nullable public final Integer low;
126     @Nullable public final Integer high;
127 
128     /**
129      * Settings to disable quality based scaling.
130      */
131     public static final ScalingSettings OFF = new ScalingSettings();
132 
133     /**
134      * Creates settings to enable quality based scaling.
135      *
136      * @param low Average QP at which to scale up the resolution.
137      * @param high Average QP at which to scale down the resolution.
138      */
ScalingSettings(int low, int high)139     public ScalingSettings(int low, int high) {
140       this.on = true;
141       this.low = low;
142       this.high = high;
143     }
144 
ScalingSettings()145     private ScalingSettings() {
146       this.on = false;
147       this.low = null;
148       this.high = null;
149     }
150 
151     // TODO(bugs.webrtc.org/8830): Below constructors are deprecated.
152     // Default thresholds are going away, so thresholds have to be set
153     // when scaling is on.
154     /**
155      * Creates quality based scaling setting.
156      *
157      * @param on True if quality scaling is turned on.
158      */
159     @Deprecated
ScalingSettings(boolean on)160     public ScalingSettings(boolean on) {
161       this.on = on;
162       this.low = null;
163       this.high = null;
164     }
165 
166     /**
167      * Creates quality based scaling settings with custom thresholds.
168      *
169      * @param on True if quality scaling is turned on.
170      * @param low Average QP at which to scale up the resolution.
171      * @param high Average QP at which to scale down the resolution.
172      */
173     @Deprecated
ScalingSettings(boolean on, int low, int high)174     public ScalingSettings(boolean on, int low, int high) {
175       this.on = on;
176       this.low = low;
177       this.high = high;
178     }
179 
180     @Override
toString()181     public String toString() {
182       return on ? "[ " + low + ", " + high + " ]" : "OFF";
183     }
184   }
185 
186   /**
187    * Bitrate limits for resolution.
188    */
189   public class ResolutionBitrateLimits {
190     /**
191      * Maximum size of video frame, in pixels, the bitrate limits are intended for.
192      */
193     public final int frameSizePixels;
194 
195     /**
196      * Recommended minimum bitrate to start encoding.
197      */
198     public final int minStartBitrateBps;
199 
200     /**
201      * Recommended minimum bitrate.
202      */
203     public final int minBitrateBps;
204 
205     /**
206      * Recommended maximum bitrate.
207      */
208     public final int maxBitrateBps;
209 
ResolutionBitrateLimits( int frameSizePixels, int minStartBitrateBps, int minBitrateBps, int maxBitrateBps)210     public ResolutionBitrateLimits(
211         int frameSizePixels, int minStartBitrateBps, int minBitrateBps, int maxBitrateBps) {
212       this.frameSizePixels = frameSizePixels;
213       this.minStartBitrateBps = minStartBitrateBps;
214       this.minBitrateBps = minBitrateBps;
215       this.maxBitrateBps = maxBitrateBps;
216     }
217 
218     @CalledByNative("ResolutionBitrateLimits")
getFrameSizePixels()219     public int getFrameSizePixels() {
220       return frameSizePixels;
221     }
222 
223     @CalledByNative("ResolutionBitrateLimits")
getMinStartBitrateBps()224     public int getMinStartBitrateBps() {
225       return minStartBitrateBps;
226     }
227 
228     @CalledByNative("ResolutionBitrateLimits")
getMinBitrateBps()229     public int getMinBitrateBps() {
230       return minBitrateBps;
231     }
232 
233     @CalledByNative("ResolutionBitrateLimits")
getMaxBitrateBps()234     public int getMaxBitrateBps() {
235       return maxBitrateBps;
236     }
237   }
238 
239   /** Rate control parameters. */
240   public class RateControlParameters {
241     /**
242      * Adjusted target bitrate, per spatial/temporal layer. May be lower or higher than the target
243      * depending on encoder behaviour.
244      */
245     public final BitrateAllocation bitrate;
246 
247     /**
248      * Target framerate, in fps. A value <= 0.0 is invalid and should be interpreted as framerate
249      * target not available. In this case the encoder should fall back to the max framerate
250      * specified in `codec_settings` of the last InitEncode() call.
251      */
252     public final double framerateFps;
253 
254     @CalledByNative("RateControlParameters")
RateControlParameters(BitrateAllocation bitrate, double framerateFps)255     public RateControlParameters(BitrateAllocation bitrate, double framerateFps) {
256       this.bitrate = bitrate;
257       this.framerateFps = framerateFps;
258     }
259   }
260 
261   /**
262    * Metadata about the Encoder.
263    */
264   public class EncoderInfo {
265     /**
266      * The width and height of the incoming video frames should be divisible by
267      * |requested_resolution_alignment|
268      */
269     public final int requestedResolutionAlignment;
270 
271     /**
272      * Same as above but if true, each simulcast layer should also be divisible by
273      * |requested_resolution_alignment|.
274      */
275     public final boolean applyAlignmentToAllSimulcastLayers;
276 
EncoderInfo( int requestedResolutionAlignment, boolean applyAlignmentToAllSimulcastLayers)277     public EncoderInfo(
278         int requestedResolutionAlignment, boolean applyAlignmentToAllSimulcastLayers) {
279       this.requestedResolutionAlignment = requestedResolutionAlignment;
280       this.applyAlignmentToAllSimulcastLayers = applyAlignmentToAllSimulcastLayers;
281     }
282 
283     @CalledByNative("EncoderInfo")
getRequestedResolutionAlignment()284     public int getRequestedResolutionAlignment() {
285       return requestedResolutionAlignment;
286     }
287 
288     @CalledByNative("EncoderInfo")
getApplyAlignmentToAllSimulcastLayers()289     public boolean getApplyAlignmentToAllSimulcastLayers() {
290       return applyAlignmentToAllSimulcastLayers;
291     }
292   }
293 
294   public interface Callback {
295     /**
296      * Old encoders assume that the byte buffer held by `frame` is not accessed after the call to
297      * this method returns. If the pipeline downstream needs to hold on to the buffer, it then has
298      * to make its own copy. We want to move to a model where no copying is needed, and instead use
299      * retain()/release() to signal to the encoder when it is safe to reuse the buffer.
300      *
301      * Over the transition, implementations of this class should use the maybeRetain() method if
302      * they want to keep a reference to the buffer, and fall back to copying if that method returns
303      * false.
304      */
onEncodedFrame(EncodedImage frame, CodecSpecificInfo info)305     void onEncodedFrame(EncodedImage frame, CodecSpecificInfo info);
306   }
307 
308   /**
309    * The encoder implementation backing this interface is either 1) a Java
310    * encoder (e.g., an Android platform encoder), or alternatively 2) a native
311    * encoder (e.g., a software encoder or a C++ encoder adapter).
312    *
313    * For case 1), createNativeVideoEncoder() should return zero.
314    * In this case, we expect the native library to call the encoder through
315    * JNI using the Java interface declared below.
316    *
317    * For case 2), createNativeVideoEncoder() should return a non-zero value.
318    * In this case, we expect the native library to treat the returned value as
319    * a raw pointer of type webrtc::VideoEncoder* (ownership is transferred to
320    * the caller). The native library should then directly call the
321    * webrtc::VideoEncoder interface without going through JNI. All calls to
322    * the Java interface methods declared below should thus throw an
323    * UnsupportedOperationException.
324    */
325   @CalledByNative
createNativeVideoEncoder()326   default long createNativeVideoEncoder() {
327     return 0;
328   }
329 
330   /**
331    * Returns true if the encoder is backed by hardware.
332    */
333   @CalledByNative
isHardwareEncoder()334   default boolean isHardwareEncoder() {
335     return true;
336   }
337 
338   /**
339    * Initializes the encoding process. Call before any calls to encode.
340    */
initEncode(Settings settings, Callback encodeCallback)341   @CalledByNative VideoCodecStatus initEncode(Settings settings, Callback encodeCallback);
342 
343   /**
344    * Releases the encoder. No more calls to encode will be made after this call.
345    */
release()346   @CalledByNative VideoCodecStatus release();
347 
348   /**
349    * Requests the encoder to encode a frame.
350    */
encode(VideoFrame frame, EncodeInfo info)351   @CalledByNative VideoCodecStatus encode(VideoFrame frame, EncodeInfo info);
352 
353   /** Sets the bitrate allocation and the target framerate for the encoder. */
setRateAllocation(BitrateAllocation allocation, int framerate)354   VideoCodecStatus setRateAllocation(BitrateAllocation allocation, int framerate);
355 
356   /** Sets the bitrate allocation and the target framerate for the encoder. */
setRates(RateControlParameters rcParameters)357   default @CalledByNative VideoCodecStatus setRates(RateControlParameters rcParameters) {
358     // Round frame rate up to avoid overshoots.
359     int framerateFps = (int) Math.ceil(rcParameters.framerateFps);
360     return setRateAllocation(rcParameters.bitrate, framerateFps);
361   }
362 
363   /** Any encoder that wants to use WebRTC provided quality scaler must implement this method. */
getScalingSettings()364   @CalledByNative ScalingSettings getScalingSettings();
365 
366   /** Returns the list of bitrate limits. */
367   @CalledByNative
getResolutionBitrateLimits()368   default ResolutionBitrateLimits[] getResolutionBitrateLimits() {
369     // TODO(ssilkin): Update downstream projects and remove default implementation.
370     ResolutionBitrateLimits bitrate_limits[] = {};
371     return bitrate_limits;
372   }
373 
374   /**
375    * Should return a descriptive name for the implementation. Gets called once and cached. May be
376    * called from arbitrary thread.
377    */
getImplementationName()378   @CalledByNative String getImplementationName();
379 
380   @CalledByNative
getEncoderInfo()381   default EncoderInfo getEncoderInfo() {
382     return new EncoderInfo(
383         /* requestedResolutionAlignment= */ 1, /* applyAlignmentToAllSimulcastLayers= */ false);
384   }
385 }
386