discord-jadx/app/src/main/java/org/webrtc/HardwareVideoEncoder.java

641 lines
26 KiB
Java

package org.webrtc;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.opengl.EGLContext;
import android.opengl.GLES20;
import android.os.Bundle;
import android.view.Surface;
import androidx.annotation.Nullable;
import b.d.b.a.a;
import com.discord.models.domain.ModelAuditLogEntry;
import h0.c.n;
import h0.c.r0;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import org.webrtc.EglBase14;
import org.webrtc.EncodedImage;
import org.webrtc.ThreadUtils;
import org.webrtc.VideoEncoder;
import org.webrtc.VideoFrame;
@TargetApi(19)
/* loaded from: classes3.dex */
public class HardwareVideoEncoder implements VideoEncoder {
private static final int DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US = 100000;
private static final String KEY_BITRATE_MODE = "bitrate-mode";
private static final int MAX_ENCODER_Q_SIZE = 2;
private static final int MAX_VIDEO_FRAMERATE = 30;
private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000;
private static final String TAG = "HardwareVideoEncoder";
private static final int VIDEO_AVC_LEVEL_3 = 256;
private static final int VIDEO_AVC_PROFILE_HIGH = 8;
private static final int VIDEO_ControlRateConstant = 2;
private int adjustedBitrate;
private boolean automaticResizeOn;
private final BitrateAdjuster bitrateAdjuster;
private VideoEncoder.Callback callback;
@Nullable
private MediaCodecWrapper codec;
private final String codecName;
private final VideoCodecMimeType codecType;
@Nullable
private ByteBuffer configBuffer;
private final ThreadUtils.ThreadChecker encodeThreadChecker;
private final long forcedKeyFrameNs;
private int height;
private final int keyFrameIntervalSec;
private long lastKeyFrameNs;
private final MediaCodecWrapperFactory mediaCodecWrapperFactory;
@Nullable
private ByteBuffer[] outputBuffers;
@Nullable
private Thread outputThread;
private final Map<String, String> params;
private volatile boolean running;
private final EglBase14.Context sharedContext;
@Nullable
private volatile Exception shutdownException;
private final Integer surfaceColorFormat;
@Nullable
private EglBase14 textureEglBase;
@Nullable
private Surface textureInputSurface;
private boolean useSurfaceMode;
private int width;
private final Integer yuvColorFormat;
private final YuvFormat yuvFormat;
private final GlRectDrawer textureDrawer = new GlRectDrawer();
private final VideoFrameDrawer videoFrameDrawer = new VideoFrameDrawer();
private final BlockingDeque<EncodedImage.Builder> outputBuilders = new LinkedBlockingDeque();
private final ThreadUtils.ThreadChecker outputThreadChecker = new ThreadUtils.ThreadChecker();
private final BusyCount outputBuffersBusyCount = new BusyCount(null);
/* renamed from: org.webrtc.HardwareVideoEncoder$1 reason: invalid class name */
/* loaded from: classes3.dex */
public class AnonymousClass1 extends Thread {
public AnonymousClass1() {
}
@Override // java.lang.Thread, java.lang.Runnable
public void run() {
while (HardwareVideoEncoder.access$100(HardwareVideoEncoder.this)) {
HardwareVideoEncoder.this.deliverEncodedImage();
}
HardwareVideoEncoder.access$200(HardwareVideoEncoder.this);
}
}
/* loaded from: classes3.dex */
public static class BusyCount {
private int count;
private final Object countLock;
private BusyCount() {
this.countLock = new Object();
}
public /* synthetic */ BusyCount(AnonymousClass1 r1) {
this();
}
public void decrement() {
synchronized (this.countLock) {
int i = this.count - 1;
this.count = i;
if (i == 0) {
this.countLock.notifyAll();
}
}
}
public void increment() {
synchronized (this.countLock) {
this.count++;
}
}
public void waitForZero() {
boolean z2;
synchronized (this.countLock) {
z2 = false;
while (this.count > 0) {
try {
this.countLock.wait();
} catch (InterruptedException e) {
Logging.e(HardwareVideoEncoder.TAG, "Interrupted while waiting on busy count", e);
z2 = true;
}
}
}
if (z2) {
Thread.currentThread().interrupt();
}
}
}
/* JADX WARN: Failed to restore enum class, 'enum' modifier removed */
/* loaded from: classes3.dex */
public static abstract class YuvFormat extends Enum<YuvFormat> {
private static final /* synthetic */ YuvFormat[] $VALUES;
public static final YuvFormat I420;
public static final YuvFormat NV12;
/* JADX WARN: Failed to restore enum class, 'enum' modifier removed */
/* renamed from: org.webrtc.HardwareVideoEncoder$YuvFormat$1 reason: invalid class name */
/* loaded from: classes3.dex */
public final class AnonymousClass1 extends YuvFormat {
public AnonymousClass1(String str, int i) {
super(str, i, null);
}
@Override // org.webrtc.HardwareVideoEncoder.YuvFormat
public void fillBuffer(ByteBuffer byteBuffer, VideoFrame.Buffer buffer) {
VideoFrame.I420Buffer i420 = buffer.toI420();
YuvHelper.I420Copy(i420.getDataY(), i420.getStrideY(), i420.getDataU(), i420.getStrideU(), i420.getDataV(), i420.getStrideV(), byteBuffer, i420.getWidth(), i420.getHeight());
i420.release();
}
}
/* JADX WARN: Failed to restore enum class, 'enum' modifier removed */
/* renamed from: org.webrtc.HardwareVideoEncoder$YuvFormat$2 reason: invalid class name */
/* loaded from: classes3.dex */
public final class AnonymousClass2 extends YuvFormat {
public AnonymousClass2(String str, int i) {
super(str, i, null);
}
@Override // org.webrtc.HardwareVideoEncoder.YuvFormat
public void fillBuffer(ByteBuffer byteBuffer, VideoFrame.Buffer buffer) {
VideoFrame.I420Buffer i420 = buffer.toI420();
YuvHelper.I420ToNV12(i420.getDataY(), i420.getStrideY(), i420.getDataU(), i420.getStrideU(), i420.getDataV(), i420.getStrideV(), byteBuffer, i420.getWidth(), i420.getHeight());
i420.release();
}
}
static {
AnonymousClass1 r0 = new AnonymousClass1("I420", 0);
I420 = r0;
AnonymousClass2 r1 = new AnonymousClass2("NV12", 1);
NV12 = r1;
$VALUES = new YuvFormat[]{r0, r1};
}
private YuvFormat(String str, int i) {
}
public /* synthetic */ YuvFormat(String str, int i, AnonymousClass1 r3) {
this(str, i);
}
public static YuvFormat valueOf(int i) {
if (i == 19) {
return I420;
}
if (i == 21 || i == 2141391872 || i == 2141391876) {
return NV12;
}
throw new IllegalArgumentException(a.p("Unsupported colorFormat: ", i));
}
public static YuvFormat valueOf(String str) {
return (YuvFormat) Enum.valueOf(YuvFormat.class, str);
}
public static YuvFormat[] values() {
return (YuvFormat[]) $VALUES.clone();
}
public abstract void fillBuffer(ByteBuffer byteBuffer, VideoFrame.Buffer buffer);
}
public HardwareVideoEncoder(MediaCodecWrapperFactory mediaCodecWrapperFactory, String str, VideoCodecMimeType videoCodecMimeType, Integer num, Integer num2, Map<String, String> map, int i, int i2, BitrateAdjuster bitrateAdjuster, EglBase14.Context context) {
ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker();
this.encodeThreadChecker = threadChecker;
this.mediaCodecWrapperFactory = mediaCodecWrapperFactory;
this.codecName = str;
this.codecType = videoCodecMimeType;
this.surfaceColorFormat = num;
this.yuvColorFormat = num2;
this.yuvFormat = YuvFormat.valueOf(num2.intValue());
this.params = map;
this.keyFrameIntervalSec = i;
this.forcedKeyFrameNs = TimeUnit.MILLISECONDS.toNanos(i2);
this.bitrateAdjuster = bitrateAdjuster;
this.sharedContext = context;
threadChecker.detachThread();
}
public static /* synthetic */ boolean access$100(HardwareVideoEncoder hardwareVideoEncoder) {
return hardwareVideoEncoder.running;
}
public static /* synthetic */ void access$200(HardwareVideoEncoder hardwareVideoEncoder) {
hardwareVideoEncoder.releaseCodecOnOutputThread();
}
private boolean canUseSurface() {
return (this.sharedContext == null || this.surfaceColorFormat == null) ? false : true;
}
private Thread createOutputThread() {
return new AnonymousClass1();
}
private VideoCodecStatus encodeByteBuffer(VideoFrame videoFrame, VideoFrame.Buffer buffer, int i) {
this.encodeThreadChecker.checkIsOnValidThread();
long timestampNs = (videoFrame.getTimestampNs() + 500) / 1000;
try {
int dequeueInputBuffer = this.codec.dequeueInputBuffer(0L);
if (dequeueInputBuffer == -1) {
Logging.d(TAG, "Dropped frame, no input buffers available");
return VideoCodecStatus.NO_OUTPUT;
}
try {
fillInputBuffer(this.codec.getInputBuffers()[dequeueInputBuffer], buffer);
try {
this.codec.queueInputBuffer(dequeueInputBuffer, 0, i, timestampNs, 0);
return VideoCodecStatus.OK;
} catch (IllegalStateException e) {
Logging.e(TAG, "queueInputBuffer failed", e);
return VideoCodecStatus.ERROR;
}
} catch (IllegalStateException e2) {
Logging.e(TAG, "getInputBuffers failed", e2);
return VideoCodecStatus.ERROR;
}
} catch (IllegalStateException e3) {
Logging.e(TAG, "dequeueInputBuffer failed", e3);
return VideoCodecStatus.ERROR;
}
}
private VideoCodecStatus encodeTextureBuffer(VideoFrame videoFrame) {
this.encodeThreadChecker.checkIsOnValidThread();
try {
GLES20.glClear(16384);
this.videoFrameDrawer.drawFrame(new VideoFrame(videoFrame.getBuffer(), 0, videoFrame.getTimestampNs()), this.textureDrawer, null);
this.textureEglBase.swapBuffers(videoFrame.getTimestampNs());
return VideoCodecStatus.OK;
} catch (RuntimeException e) {
Logging.e(TAG, "encodeTexture failed", e);
return VideoCodecStatus.ERROR;
}
}
/* JADX WARN: Code restructure failed: missing block: B:28:0x008d, code lost:
if (r5 == 1) goto L_0x00b2;
*/
/* JADX WARN: Code restructure failed: missing block: B:29:0x008f, code lost:
org.webrtc.Logging.w(org.webrtc.HardwareVideoEncoder.TAG, "Unknown profile level id: " + r1);
*/
/*
Code decompiled incorrectly, please refer to instructions dump.
*/
private VideoCodecStatus initEncodeInternal() {
this.encodeThreadChecker.checkIsOnValidThread();
this.lastKeyFrameNs = -1L;
try {
this.codec = this.mediaCodecWrapperFactory.createByCodecName(this.codecName);
int intValue = (this.useSurfaceMode ? this.surfaceColorFormat : this.yuvColorFormat).intValue();
try {
MediaFormat createVideoFormat = MediaFormat.createVideoFormat(this.codecType.mimeType(), this.width, this.height);
createVideoFormat.setInteger(ModelAuditLogEntry.CHANGE_KEY_BITRATE, this.adjustedBitrate);
createVideoFormat.setInteger(KEY_BITRATE_MODE, 2);
createVideoFormat.setInteger("color-format", intValue);
createVideoFormat.setInteger("frame-rate", this.bitrateAdjuster.getCodecConfigFramerate());
createVideoFormat.setInteger("i-frame-interval", this.keyFrameIntervalSec);
if (this.codecType == VideoCodecMimeType.H264) {
String str = this.params.get("profile-level-id");
if (str == null) {
str = "42e01f";
}
char c = 65535;
int hashCode = str.hashCode();
if (hashCode != 1537948542) {
if (hashCode == 1595523974 && str.equals("640c1f")) {
c = 0;
}
} else if (str.equals("42e01f")) {
c = 1;
}
createVideoFormat.setInteger("profile", 8);
createVideoFormat.setInteger("level", 256);
}
Logging.d(TAG, "Format: " + createVideoFormat);
EGLContext eGLContext = null;
this.codec.configure(createVideoFormat, null, null, 1);
if (this.useSurfaceMode) {
EglBase14.Context context = this.sharedContext;
int[] iArr = EglBase.CONFIG_RECORDABLE;
if (context != null) {
eGLContext = context.getRawContext();
}
this.textureEglBase = new EglBase14Impl(eGLContext, iArr);
Surface createInputSurface = this.codec.createInputSurface();
this.textureInputSurface = createInputSurface;
this.textureEglBase.createSurface(createInputSurface);
this.textureEglBase.makeCurrent();
}
this.codec.start();
this.outputBuffers = this.codec.getOutputBuffers();
this.running = true;
this.outputThreadChecker.detachThread();
Thread createOutputThread = createOutputThread();
this.outputThread = createOutputThread;
createOutputThread.start();
return VideoCodecStatus.OK;
} catch (IllegalStateException e) {
Logging.e(TAG, "initEncodeInternal failed", e);
release();
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
} catch (IOException | IllegalArgumentException unused) {
StringBuilder R = a.R("Cannot create media encoder ");
R.append(this.codecName);
Logging.e(TAG, R.toString());
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
}
private void releaseCodecOnOutputThread() {
this.outputThreadChecker.checkIsOnValidThread();
Logging.d(TAG, "Releasing MediaCodec on output thread");
this.outputBuffersBusyCount.waitForZero();
try {
this.codec.stop();
} catch (Exception e) {
Logging.e(TAG, "Media encoder stop failed", e);
}
try {
this.codec.release();
} catch (Exception e2) {
Logging.e(TAG, "Media encoder release failed", e2);
this.shutdownException = e2;
}
this.configBuffer = null;
Logging.d(TAG, "Release on output thread done");
}
private void requestKeyFrame(long j) {
this.encodeThreadChecker.checkIsOnValidThread();
try {
Bundle bundle = new Bundle();
bundle.putInt("request-sync", 0);
this.codec.setParameters(bundle);
this.lastKeyFrameNs = j;
} catch (IllegalStateException e) {
Logging.e(TAG, "requestKeyFrame failed", e);
}
}
private VideoCodecStatus resetCodec(int i, int i2, boolean z2) {
this.encodeThreadChecker.checkIsOnValidThread();
VideoCodecStatus release = release();
if (release != VideoCodecStatus.OK) {
return release;
}
this.width = i;
this.height = i2;
this.useSurfaceMode = z2;
return initEncodeInternal();
}
private boolean shouldForceKeyFrame(long j) {
this.encodeThreadChecker.checkIsOnValidThread();
long j2 = this.forcedKeyFrameNs;
return j2 > 0 && j > this.lastKeyFrameNs + j2;
}
private VideoCodecStatus updateBitrate() {
this.outputThreadChecker.checkIsOnValidThread();
this.adjustedBitrate = this.bitrateAdjuster.getAdjustedBitrateBps();
try {
Bundle bundle = new Bundle();
bundle.putInt("video-bitrate", this.adjustedBitrate);
this.codec.setParameters(bundle);
return VideoCodecStatus.OK;
} catch (IllegalStateException e) {
Logging.e(TAG, "updateBitrate failed", e);
return VideoCodecStatus.ERROR;
}
}
public /* synthetic */ void a(int i) {
try {
this.codec.releaseOutputBuffer(i, false);
} catch (Exception e) {
Logging.e(TAG, "releaseOutputBuffer failed", e);
}
this.outputBuffersBusyCount.decrement();
}
@Override // org.webrtc.VideoEncoder
public /* synthetic */ long createNativeVideoEncoder() {
return r0.a(this);
}
public void deliverEncodedImage() {
ByteBuffer byteBuffer;
this.outputThreadChecker.checkIsOnValidThread();
try {
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int dequeueOutputBuffer = this.codec.dequeueOutputBuffer(bufferInfo, 100000L);
if (dequeueOutputBuffer >= 0) {
ByteBuffer byteBuffer2 = this.outputBuffers[dequeueOutputBuffer];
byteBuffer2.position(bufferInfo.offset);
byteBuffer2.limit(bufferInfo.offset + bufferInfo.size);
if ((bufferInfo.flags & 2) != 0) {
Logging.d(TAG, "Config frame generated. Offset: " + bufferInfo.offset + ". Size: " + bufferInfo.size);
ByteBuffer allocateDirect = ByteBuffer.allocateDirect(bufferInfo.size);
this.configBuffer = allocateDirect;
allocateDirect.put(byteBuffer2);
return;
}
this.bitrateAdjuster.reportEncodedFrame(bufferInfo.size);
if (this.adjustedBitrate != this.bitrateAdjuster.getAdjustedBitrateBps()) {
updateBitrate();
}
boolean z2 = true;
if ((bufferInfo.flags & 1) == 0) {
z2 = false;
}
if (z2) {
Logging.d(TAG, "Sync frame generated");
}
if (!z2 || this.codecType != VideoCodecMimeType.H264) {
byteBuffer = byteBuffer2.slice();
} else {
Logging.d(TAG, "Prepending config frame of size " + this.configBuffer.capacity() + " to output buffer with offset " + bufferInfo.offset + ", size " + bufferInfo.size);
byteBuffer = ByteBuffer.allocateDirect(bufferInfo.size + this.configBuffer.capacity());
this.configBuffer.rewind();
byteBuffer.put(this.configBuffer);
byteBuffer.put(byteBuffer2);
byteBuffer.rewind();
}
EncodedImage.FrameType frameType = z2 ? EncodedImage.FrameType.VideoFrameKey : EncodedImage.FrameType.VideoFrameDelta;
this.outputBuffersBusyCount.increment();
EncodedImage createEncodedImage = this.outputBuilders.poll().setBuffer(byteBuffer, new n(this, dequeueOutputBuffer)).setFrameType(frameType).createEncodedImage();
this.callback.onEncodedFrame(createEncodedImage, new VideoEncoder.CodecSpecificInfo());
createEncodedImage.release();
} else if (dequeueOutputBuffer == -3) {
this.outputBuffersBusyCount.waitForZero();
this.outputBuffers = this.codec.getOutputBuffers();
}
} catch (IllegalStateException e) {
Logging.e(TAG, "deliverOutput failed", e);
}
}
@Override // org.webrtc.VideoEncoder
public VideoCodecStatus encode(VideoFrame videoFrame, VideoEncoder.EncodeInfo encodeInfo) {
VideoCodecStatus resetCodec;
this.encodeThreadChecker.checkIsOnValidThread();
if (this.codec == null) {
return VideoCodecStatus.UNINITIALIZED;
}
VideoFrame.Buffer buffer = videoFrame.getBuffer();
boolean z2 = buffer instanceof VideoFrame.TextureBuffer;
int width = videoFrame.getBuffer().getWidth();
int height = videoFrame.getBuffer().getHeight();
boolean z3 = canUseSurface() && z2;
if (!((width == this.width && height == this.height && z3 == this.useSurfaceMode) || (resetCodec = resetCodec(width, height, z3)) == VideoCodecStatus.OK)) {
return resetCodec;
}
if (this.outputBuilders.size() > 2) {
Logging.w(TAG, "Dropped frame, encoder queue full");
return VideoCodecStatus.NO_OUTPUT;
}
boolean z4 = false;
for (EncodedImage.FrameType frameType : encodeInfo.frameTypes) {
if (frameType == EncodedImage.FrameType.VideoFrameKey) {
z4 = true;
}
}
if (z4 || shouldForceKeyFrame(videoFrame.getTimestampNs())) {
requestKeyFrame(videoFrame.getTimestampNs());
}
int width2 = ((buffer.getWidth() * buffer.getHeight()) * 3) / 2;
this.outputBuilders.offer(EncodedImage.builder().setCaptureTimeNs(videoFrame.getTimestampNs()).setEncodedWidth(videoFrame.getBuffer().getWidth()).setEncodedHeight(videoFrame.getBuffer().getHeight()).setRotation(videoFrame.getRotation()));
VideoCodecStatus encodeTextureBuffer = this.useSurfaceMode ? encodeTextureBuffer(videoFrame) : encodeByteBuffer(videoFrame, buffer, width2);
if (encodeTextureBuffer != VideoCodecStatus.OK) {
this.outputBuilders.pollLast();
}
return encodeTextureBuffer;
}
public void fillInputBuffer(ByteBuffer byteBuffer, VideoFrame.Buffer buffer) {
this.yuvFormat.fillBuffer(byteBuffer, buffer);
}
@Override // org.webrtc.VideoEncoder
public String getImplementationName() {
return "HWEncoder";
}
@Override // org.webrtc.VideoEncoder
public /* synthetic */ VideoEncoder.ResolutionBitrateLimits[] getResolutionBitrateLimits() {
return r0.b(this);
}
@Override // org.webrtc.VideoEncoder
public VideoEncoder.ScalingSettings getScalingSettings() {
this.encodeThreadChecker.checkIsOnValidThread();
if (this.automaticResizeOn) {
VideoCodecMimeType videoCodecMimeType = this.codecType;
if (videoCodecMimeType == VideoCodecMimeType.VP8) {
return new VideoEncoder.ScalingSettings(29, 95);
}
if (videoCodecMimeType == VideoCodecMimeType.H264) {
return new VideoEncoder.ScalingSettings(24, 37);
}
}
return VideoEncoder.ScalingSettings.OFF;
}
@Override // org.webrtc.VideoEncoder
public VideoCodecStatus initEncode(VideoEncoder.Settings settings, VideoEncoder.Callback callback) {
int i;
this.encodeThreadChecker.checkIsOnValidThread();
this.callback = callback;
this.automaticResizeOn = settings.automaticResizeOn;
this.width = settings.width;
this.height = settings.height;
this.useSurfaceMode = canUseSurface();
int i2 = settings.startBitrate;
if (!(i2 == 0 || (i = settings.maxFramerate) == 0)) {
this.bitrateAdjuster.setTargets(i2 * 1000, i);
}
this.adjustedBitrate = this.bitrateAdjuster.getAdjustedBitrateBps();
StringBuilder R = a.R("initEncode: ");
R.append(this.width);
R.append(" x ");
R.append(this.height);
R.append(". @ ");
R.append(settings.startBitrate);
R.append("kbps. Fps: ");
R.append(settings.maxFramerate);
R.append(" Use surface mode: ");
R.append(this.useSurfaceMode);
Logging.d(TAG, R.toString());
return initEncodeInternal();
}
@Override // org.webrtc.VideoEncoder
public /* synthetic */ boolean isHardwareEncoder() {
return r0.c(this);
}
@Override // org.webrtc.VideoEncoder
public VideoCodecStatus release() {
VideoCodecStatus videoCodecStatus;
this.encodeThreadChecker.checkIsOnValidThread();
if (this.outputThread == null) {
videoCodecStatus = VideoCodecStatus.OK;
} else {
this.running = false;
if (!ThreadUtils.joinUninterruptibly(this.outputThread, 5000L)) {
Logging.e(TAG, "Media encoder release timeout");
videoCodecStatus = VideoCodecStatus.TIMEOUT;
} else if (this.shutdownException != null) {
Logging.e(TAG, "Media encoder release exception", this.shutdownException);
videoCodecStatus = VideoCodecStatus.ERROR;
} else {
videoCodecStatus = VideoCodecStatus.OK;
}
}
this.textureDrawer.release();
this.videoFrameDrawer.release();
EglBase14 eglBase14 = this.textureEglBase;
if (eglBase14 != null) {
eglBase14.release();
this.textureEglBase = null;
}
Surface surface = this.textureInputSurface;
if (surface != null) {
surface.release();
this.textureInputSurface = null;
}
this.outputBuilders.clear();
this.codec = null;
this.outputBuffers = null;
this.outputThread = null;
this.encodeThreadChecker.detachThread();
return videoCodecStatus;
}
@Override // org.webrtc.VideoEncoder
public VideoCodecStatus setRateAllocation(VideoEncoder.BitrateAllocation bitrateAllocation, int i) {
this.encodeThreadChecker.checkIsOnValidThread();
if (i > 30) {
i = 30;
}
this.bitrateAdjuster.setTargets(bitrateAllocation.getSum(), i);
return VideoCodecStatus.OK;
}
}