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