593 lines
25 KiB
Java
593 lines
25 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 c.d.b.a.a;
|
|
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)
|
|
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;
|
|
private final BusyCount outputBuffersBusyCount;
|
|
private final BlockingDeque<EncodedImage.Builder> outputBuilders = new LinkedBlockingDeque();
|
|
@Nullable
|
|
private Thread outputThread;
|
|
private final ThreadUtils.ThreadChecker outputThreadChecker;
|
|
private final Map<String, String> params;
|
|
private volatile boolean running;
|
|
private final EglBase14.Context sharedContext;
|
|
@Nullable
|
|
private volatile Exception shutdownException;
|
|
private final Integer surfaceColorFormat;
|
|
private final GlRectDrawer textureDrawer = new GlRectDrawer();
|
|
@Nullable
|
|
private EglBase14 textureEglBase;
|
|
@Nullable
|
|
private Surface textureInputSurface;
|
|
private boolean useSurfaceMode;
|
|
private final VideoFrameDrawer videoFrameDrawer = new VideoFrameDrawer();
|
|
private int width;
|
|
private final Integer yuvColorFormat;
|
|
private final YuvFormat yuvFormat;
|
|
|
|
/* renamed from: org.webrtc.HardwareVideoEncoder$1 reason: invalid class name */
|
|
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);
|
|
}
|
|
}
|
|
|
|
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", "Interrupted while waiting on busy count", e);
|
|
z2 = true;
|
|
}
|
|
}
|
|
}
|
|
if (z2) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum YuvFormat {
|
|
I420 {
|
|
@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();
|
|
}
|
|
},
|
|
NV12 {
|
|
@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();
|
|
}
|
|
};
|
|
|
|
public /* synthetic */ YuvFormat(AnonymousClass1 r3) {
|
|
this();
|
|
}
|
|
|
|
public static YuvFormat valueOf(int i) {
|
|
if (i == 19) {
|
|
return I420;
|
|
}
|
|
if (i == 21 || i == 2141391872 || i == 2141391876) {
|
|
return NV12;
|
|
}
|
|
throw new IllegalArgumentException(a.j("Unsupported colorFormat: ", i));
|
|
}
|
|
|
|
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.outputThreadChecker = new ThreadUtils.ThreadChecker();
|
|
this.outputBuffersBusyCount = new BusyCount(null);
|
|
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((long) 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(0);
|
|
if (dequeueInputBuffer == -1) {
|
|
Logging.d("HardwareVideoEncoder", "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("HardwareVideoEncoder", "queueInputBuffer failed", e);
|
|
return VideoCodecStatus.ERROR;
|
|
}
|
|
} catch (IllegalStateException e2) {
|
|
Logging.e("HardwareVideoEncoder", "getInputBuffers failed", e2);
|
|
return VideoCodecStatus.ERROR;
|
|
}
|
|
} catch (IllegalStateException e3) {
|
|
Logging.e("HardwareVideoEncoder", "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("HardwareVideoEncoder", "encodeTexture failed", e);
|
|
return VideoCodecStatus.ERROR;
|
|
}
|
|
}
|
|
|
|
private VideoCodecStatus initEncodeInternal() {
|
|
this.encodeThreadChecker.checkIsOnValidThread();
|
|
this.lastKeyFrameNs = -1;
|
|
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("bitrate", this.adjustedBitrate);
|
|
createVideoFormat.setInteger("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 c2 = 65535;
|
|
int hashCode = str.hashCode();
|
|
if (hashCode != 1537948542) {
|
|
if (hashCode == 1595523974 && str.equals("640c1f")) {
|
|
c2 = 0;
|
|
}
|
|
} else if (str.equals("42e01f")) {
|
|
c2 = 1;
|
|
}
|
|
if (c2 == 0) {
|
|
createVideoFormat.setInteger("profile", 8);
|
|
createVideoFormat.setInteger("level", 256);
|
|
} else if (c2 != 1) {
|
|
Logging.w("HardwareVideoEncoder", "Unknown profile level id: " + str);
|
|
}
|
|
}
|
|
Logging.d("HardwareVideoEncoder", "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("HardwareVideoEncoder", "initEncodeInternal failed", e);
|
|
release();
|
|
return VideoCodecStatus.FALLBACK_SOFTWARE;
|
|
}
|
|
} catch (IOException | IllegalArgumentException unused) {
|
|
StringBuilder K = a.K("Cannot create media encoder ");
|
|
K.append(this.codecName);
|
|
Logging.e("HardwareVideoEncoder", K.toString());
|
|
return VideoCodecStatus.FALLBACK_SOFTWARE;
|
|
}
|
|
}
|
|
|
|
private void releaseCodecOnOutputThread() {
|
|
this.outputThreadChecker.checkIsOnValidThread();
|
|
Logging.d("HardwareVideoEncoder", "Releasing MediaCodec on output thread");
|
|
this.outputBuffersBusyCount.waitForZero();
|
|
try {
|
|
this.codec.stop();
|
|
} catch (Exception e) {
|
|
Logging.e("HardwareVideoEncoder", "Media encoder stop failed", e);
|
|
}
|
|
try {
|
|
this.codec.release();
|
|
} catch (Exception e2) {
|
|
Logging.e("HardwareVideoEncoder", "Media encoder release failed", e2);
|
|
this.shutdownException = e2;
|
|
}
|
|
this.configBuffer = null;
|
|
Logging.d("HardwareVideoEncoder", "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("HardwareVideoEncoder", "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("HardwareVideoEncoder", "updateBitrate failed", e);
|
|
return VideoCodecStatus.ERROR;
|
|
}
|
|
}
|
|
|
|
public /* synthetic */ void a(int i) {
|
|
try {
|
|
this.codec.releaseOutputBuffer(i, false);
|
|
} catch (Exception e) {
|
|
Logging.e("HardwareVideoEncoder", "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, 100000);
|
|
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("HardwareVideoEncoder", "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("HardwareVideoEncoder", "Sync frame generated");
|
|
}
|
|
if (!z2 || this.codecType != VideoCodecMimeType.H264) {
|
|
byteBuffer = byteBuffer2.slice();
|
|
} else {
|
|
Logging.d("HardwareVideoEncoder", "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("HardwareVideoEncoder", "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("HardwareVideoEncoder", "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 K = a.K("initEncode: ");
|
|
K.append(this.width);
|
|
K.append(" x ");
|
|
K.append(this.height);
|
|
K.append(". @ ");
|
|
K.append(settings.startBitrate);
|
|
K.append("kbps. Fps: ");
|
|
K.append(settings.maxFramerate);
|
|
K.append(" Use surface mode: ");
|
|
K.append(this.useSurfaceMode);
|
|
Logging.d("HardwareVideoEncoder", K.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, 5000)) {
|
|
Logging.e("HardwareVideoEncoder", "Media encoder release timeout");
|
|
videoCodecStatus = VideoCodecStatus.TIMEOUT;
|
|
} else if (this.shutdownException != null) {
|
|
Logging.e("HardwareVideoEncoder", "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;
|
|
}
|
|
}
|