|  | /* | 
|  | *  Copyright 2017 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | package org.webrtc; | 
|  |  | 
|  | import androidx.annotation.Nullable; | 
|  | import org.webrtc.EncodedImage; | 
|  |  | 
|  | /** | 
|  | * Interface for a video encoder that can be used with WebRTC. All calls will be made on the | 
|  | * encoding thread. The encoder may be constructed on a different thread and changing thread after | 
|  | * calling release is allowed. | 
|  | */ | 
|  | public interface VideoEncoder { | 
|  | /** Settings passed to the encoder by WebRTC. */ | 
|  | public class Settings { | 
|  | public final int numberOfCores; | 
|  | public final int width; | 
|  | public final int height; | 
|  | public final int startBitrate; // Kilobits per second. | 
|  | public final int maxFramerate; | 
|  | public final int numberOfSimulcastStreams; | 
|  | public final boolean automaticResizeOn; | 
|  | public final Capabilities capabilities; | 
|  |  | 
|  | // TODO(bugs.webrtc.org/10720): Remove. | 
|  | @Deprecated | 
|  | public Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate, | 
|  | int numberOfSimulcastStreams, boolean automaticResizeOn) { | 
|  | this(numberOfCores, width, height, startBitrate, maxFramerate, numberOfSimulcastStreams, | 
|  | automaticResizeOn, new VideoEncoder.Capabilities(false /* lossNotification */)); | 
|  | } | 
|  |  | 
|  | @CalledByNative("Settings") | 
|  | public Settings(int numberOfCores, int width, int height, int startBitrate, int maxFramerate, | 
|  | int numberOfSimulcastStreams, boolean automaticResizeOn, Capabilities capabilities) { | 
|  | this.numberOfCores = numberOfCores; | 
|  | this.width = width; | 
|  | this.height = height; | 
|  | this.startBitrate = startBitrate; | 
|  | this.maxFramerate = maxFramerate; | 
|  | this.numberOfSimulcastStreams = numberOfSimulcastStreams; | 
|  | this.automaticResizeOn = automaticResizeOn; | 
|  | this.capabilities = capabilities; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Capabilities (loss notification, etc.) passed to the encoder by WebRTC. */ | 
|  | public class Capabilities { | 
|  | /** | 
|  | * The remote side has support for the loss notification RTCP feedback message format, and will | 
|  | * be sending these feedback messages if necessary. | 
|  | */ | 
|  | public final boolean lossNotification; | 
|  |  | 
|  | @CalledByNative("Capabilities") | 
|  | public Capabilities(boolean lossNotification) { | 
|  | this.lossNotification = lossNotification; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Additional info for encoding. */ | 
|  | public class EncodeInfo { | 
|  | public final EncodedImage.FrameType[] frameTypes; | 
|  |  | 
|  | @CalledByNative("EncodeInfo") | 
|  | public EncodeInfo(EncodedImage.FrameType[] frameTypes) { | 
|  | this.frameTypes = frameTypes; | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO(sakal): Add values to these classes as necessary. | 
|  | /** Codec specific information about the encoded frame. */ | 
|  | public class CodecSpecificInfo {} | 
|  |  | 
|  | public class CodecSpecificInfoVP8 extends CodecSpecificInfo {} | 
|  |  | 
|  | public class CodecSpecificInfoVP9 extends CodecSpecificInfo {} | 
|  |  | 
|  | public class CodecSpecificInfoH264 extends CodecSpecificInfo {} | 
|  |  | 
|  | public class CodecSpecificInfoAV1 extends CodecSpecificInfo {} | 
|  |  | 
|  | /** | 
|  | * Represents bitrate allocated for an encoder to produce frames. Bitrate can be divided between | 
|  | * spatial and temporal layers. | 
|  | */ | 
|  | public class BitrateAllocation { | 
|  | // First index is the spatial layer and second the temporal layer. | 
|  | public final int[][] bitratesBbs; | 
|  |  | 
|  | /** | 
|  | * Initializes the allocation with a two dimensional array of bitrates. The first index of the | 
|  | * array is the spatial layer and the second index in the temporal layer. | 
|  | */ | 
|  | @CalledByNative("BitrateAllocation") | 
|  | public BitrateAllocation(int[][] bitratesBbs) { | 
|  | this.bitratesBbs = bitratesBbs; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the total bitrate allocated for all layers. | 
|  | */ | 
|  | public int getSum() { | 
|  | int sum = 0; | 
|  | for (int[] spatialLayer : bitratesBbs) { | 
|  | for (int bitrate : spatialLayer) { | 
|  | sum += bitrate; | 
|  | } | 
|  | } | 
|  | return sum; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Settings for WebRTC quality based scaling. */ | 
|  | public class ScalingSettings { | 
|  | public final boolean on; | 
|  | @Nullable public final Integer low; | 
|  | @Nullable public final Integer high; | 
|  |  | 
|  | /** | 
|  | * Settings to disable quality based scaling. | 
|  | */ | 
|  | public static final ScalingSettings OFF = new ScalingSettings(); | 
|  |  | 
|  | /** | 
|  | * Creates settings to enable quality based scaling. | 
|  | * | 
|  | * @param low Average QP at which to scale up the resolution. | 
|  | * @param high Average QP at which to scale down the resolution. | 
|  | */ | 
|  | public ScalingSettings(int low, int high) { | 
|  | this.on = true; | 
|  | this.low = low; | 
|  | this.high = high; | 
|  | } | 
|  |  | 
|  | private ScalingSettings() { | 
|  | this.on = false; | 
|  | this.low = null; | 
|  | this.high = null; | 
|  | } | 
|  |  | 
|  | // TODO(bugs.webrtc.org/8830): Below constructors are deprecated. | 
|  | // Default thresholds are going away, so thresholds have to be set | 
|  | // when scaling is on. | 
|  | /** | 
|  | * Creates quality based scaling setting. | 
|  | * | 
|  | * @param on True if quality scaling is turned on. | 
|  | */ | 
|  | @Deprecated | 
|  | public ScalingSettings(boolean on) { | 
|  | this.on = on; | 
|  | this.low = null; | 
|  | this.high = null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates quality based scaling settings with custom thresholds. | 
|  | * | 
|  | * @param on True if quality scaling is turned on. | 
|  | * @param low Average QP at which to scale up the resolution. | 
|  | * @param high Average QP at which to scale down the resolution. | 
|  | */ | 
|  | @Deprecated | 
|  | public ScalingSettings(boolean on, int low, int high) { | 
|  | this.on = on; | 
|  | this.low = low; | 
|  | this.high = high; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return on ? "[ " + low + ", " + high + " ]" : "OFF"; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Bitrate limits for resolution. | 
|  | */ | 
|  | public class ResolutionBitrateLimits { | 
|  | /** | 
|  | * Maximum size of video frame, in pixels, the bitrate limits are intended for. | 
|  | */ | 
|  | public final int frameSizePixels; | 
|  |  | 
|  | /** | 
|  | * Recommended minimum bitrate to start encoding. | 
|  | */ | 
|  | public final int minStartBitrateBps; | 
|  |  | 
|  | /** | 
|  | * Recommended minimum bitrate. | 
|  | */ | 
|  | public final int minBitrateBps; | 
|  |  | 
|  | /** | 
|  | * Recommended maximum bitrate. | 
|  | */ | 
|  | public final int maxBitrateBps; | 
|  |  | 
|  | public ResolutionBitrateLimits( | 
|  | int frameSizePixels, int minStartBitrateBps, int minBitrateBps, int maxBitrateBps) { | 
|  | this.frameSizePixels = frameSizePixels; | 
|  | this.minStartBitrateBps = minStartBitrateBps; | 
|  | this.minBitrateBps = minBitrateBps; | 
|  | this.maxBitrateBps = maxBitrateBps; | 
|  | } | 
|  |  | 
|  | @CalledByNative("ResolutionBitrateLimits") | 
|  | public int getFrameSizePixels() { | 
|  | return frameSizePixels; | 
|  | } | 
|  |  | 
|  | @CalledByNative("ResolutionBitrateLimits") | 
|  | public int getMinStartBitrateBps() { | 
|  | return minStartBitrateBps; | 
|  | } | 
|  |  | 
|  | @CalledByNative("ResolutionBitrateLimits") | 
|  | public int getMinBitrateBps() { | 
|  | return minBitrateBps; | 
|  | } | 
|  |  | 
|  | @CalledByNative("ResolutionBitrateLimits") | 
|  | public int getMaxBitrateBps() { | 
|  | return maxBitrateBps; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Rate control parameters. */ | 
|  | public class RateControlParameters { | 
|  | /** | 
|  | * Adjusted target bitrate, per spatial/temporal layer. May be lower or higher than the target | 
|  | * depending on encoder behaviour. | 
|  | */ | 
|  | public final BitrateAllocation bitrate; | 
|  |  | 
|  | /** | 
|  | * Target framerate, in fps. A value <= 0.0 is invalid and should be interpreted as framerate | 
|  | * target not available. In this case the encoder should fall back to the max framerate | 
|  | * specified in `codec_settings` of the last InitEncode() call. | 
|  | */ | 
|  | public final double framerateFps; | 
|  |  | 
|  | @CalledByNative("RateControlParameters") | 
|  | public RateControlParameters(BitrateAllocation bitrate, double framerateFps) { | 
|  | this.bitrate = bitrate; | 
|  | this.framerateFps = framerateFps; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Metadata about the Encoder. | 
|  | */ | 
|  | public class EncoderInfo { | 
|  | /** | 
|  | * The width and height of the incoming video frames should be divisible by | 
|  | * |requested_resolution_alignment| | 
|  | */ | 
|  | public final int requestedResolutionAlignment; | 
|  |  | 
|  | /** | 
|  | * Same as above but if true, each simulcast layer should also be divisible by | 
|  | * |requested_resolution_alignment|. | 
|  | */ | 
|  | public final boolean applyAlignmentToAllSimulcastLayers; | 
|  |  | 
|  | public EncoderInfo( | 
|  | int requestedResolutionAlignment, boolean applyAlignmentToAllSimulcastLayers) { | 
|  | this.requestedResolutionAlignment = requestedResolutionAlignment; | 
|  | this.applyAlignmentToAllSimulcastLayers = applyAlignmentToAllSimulcastLayers; | 
|  | } | 
|  |  | 
|  | @CalledByNative("EncoderInfo") | 
|  | public int getRequestedResolutionAlignment() { | 
|  | return requestedResolutionAlignment; | 
|  | } | 
|  |  | 
|  | @CalledByNative("EncoderInfo") | 
|  | public boolean getApplyAlignmentToAllSimulcastLayers() { | 
|  | return applyAlignmentToAllSimulcastLayers; | 
|  | } | 
|  | } | 
|  |  | 
|  | public interface Callback { | 
|  | /** | 
|  | * Old encoders assume that the byte buffer held by `frame` is not accessed after the call to | 
|  | * this method returns. If the pipeline downstream needs to hold on to the buffer, it then has | 
|  | * to make its own copy. We want to move to a model where no copying is needed, and instead use | 
|  | * retain()/release() to signal to the encoder when it is safe to reuse the buffer. | 
|  | * | 
|  | * Over the transition, implementations of this class should use the maybeRetain() method if | 
|  | * they want to keep a reference to the buffer, and fall back to copying if that method returns | 
|  | * false. | 
|  | */ | 
|  | void onEncodedFrame(EncodedImage frame, CodecSpecificInfo info); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The encoder implementation backing this interface is either 1) a Java | 
|  | * encoder (e.g., an Android platform encoder), or alternatively 2) a native | 
|  | * encoder (e.g., a software encoder or a C++ encoder adapter). | 
|  | * | 
|  | * For case 1), createNativeVideoEncoder() should return zero. | 
|  | * In this case, we expect the native library to call the encoder through | 
|  | * JNI using the Java interface declared below. | 
|  | * | 
|  | * For case 2), createNativeVideoEncoder() should return a non-zero value. | 
|  | * In this case, we expect the native library to treat the returned value as | 
|  | * a raw pointer of type webrtc::VideoEncoder* (ownership is transferred to | 
|  | * the caller). The native library should then directly call the | 
|  | * webrtc::VideoEncoder interface without going through JNI. All calls to | 
|  | * the Java interface methods declared below should thus throw an | 
|  | * UnsupportedOperationException. | 
|  | */ | 
|  | @CalledByNative | 
|  | default long createNativeVideoEncoder() { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns true if the encoder is backed by hardware. | 
|  | */ | 
|  | @CalledByNative | 
|  | default boolean isHardwareEncoder() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Initializes the encoding process. Call before any calls to encode. | 
|  | */ | 
|  | @CalledByNative VideoCodecStatus initEncode(Settings settings, Callback encodeCallback); | 
|  |  | 
|  | /** | 
|  | * Releases the encoder. No more calls to encode will be made after this call. | 
|  | */ | 
|  | @CalledByNative VideoCodecStatus release(); | 
|  |  | 
|  | /** | 
|  | * Requests the encoder to encode a frame. | 
|  | */ | 
|  | @CalledByNative VideoCodecStatus encode(VideoFrame frame, EncodeInfo info); | 
|  |  | 
|  | /** Sets the bitrate allocation and the target framerate for the encoder. */ | 
|  | VideoCodecStatus setRateAllocation(BitrateAllocation allocation, int framerate); | 
|  |  | 
|  | /** Sets the bitrate allocation and the target framerate for the encoder. */ | 
|  | default @CalledByNative VideoCodecStatus setRates(RateControlParameters rcParameters) { | 
|  | // Round frame rate up to avoid overshoots. | 
|  | int framerateFps = (int) Math.ceil(rcParameters.framerateFps); | 
|  | return setRateAllocation(rcParameters.bitrate, framerateFps); | 
|  | } | 
|  |  | 
|  | /** Any encoder that wants to use WebRTC provided quality scaler must implement this method. */ | 
|  | @CalledByNative ScalingSettings getScalingSettings(); | 
|  |  | 
|  | /** Returns the list of bitrate limits. */ | 
|  | @CalledByNative | 
|  | default ResolutionBitrateLimits[] getResolutionBitrateLimits() { | 
|  | // TODO(ssilkin): Update downstream projects and remove default implementation. | 
|  | ResolutionBitrateLimits bitrate_limits[] = {}; | 
|  | return bitrate_limits; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Should return a descriptive name for the implementation. Gets called once and cached. May be | 
|  | * called from arbitrary thread. | 
|  | */ | 
|  | @CalledByNative String getImplementationName(); | 
|  |  | 
|  | @CalledByNative | 
|  | default EncoderInfo getEncoderInfo() { | 
|  | return new EncoderInfo( | 
|  | /* requestedResolutionAlignment= */ 1, /* applyAlignmentToAllSimulcastLayers= */ false); | 
|  | } | 
|  | } |