Extract MediaCodecCompat from ScreenEncoder

This commit is contained in:
Eugen Pechanec 2022-06-25 13:31:57 +02:00
parent 2460552bb8
commit 48cdbb23a9
No known key found for this signature in database
GPG key ID: 1E110C960179440E
2 changed files with 119 additions and 14 deletions

View file

@ -0,0 +1,116 @@
package com.genymobile.scrcpy;
import android.media.MediaCodec;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import java.nio.ByteBuffer;
import static android.media.MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED;
import static android.os.Build.VERSION.SDK_INT;
/**
* Version of {@link MediaCodec} that backports {@link #getOutputBuffer} to Kitkat.
* The backported implementation isn't thread safe.
*/
abstract class MediaCodecCompat {
private final MediaCodec delegate;
MediaCodecCompat(@NonNull MediaCodec delegate) {
this.delegate = delegate;
}
@NonNull
protected MediaCodec getDelegate() {
return delegate;
}
@NonNull
static MediaCodecCompat wrap(@NonNull MediaCodec codec) {
if (SDK_INT >= 21) {
return new Platform(codec);
} else {
return new Backport(codec);
}
}
abstract int dequeueOutputBuffer(
@NonNull MediaCodec.BufferInfo info, long timeoutUs);
@Nullable
abstract ByteBuffer getOutputBuffer(int index);
abstract void releaseOutputBuffer(int index, boolean render);
@SuppressWarnings("deprecation")
private static class Backport extends MediaCodecCompat {
private ByteBuffer[] cachedOutputBuffers = null;
Backport(@NonNull MediaCodec delegate) {
super(delegate);
}
@Override
int dequeueOutputBuffer(
@NonNull MediaCodec.BufferInfo info, long timeoutUs) {
final int res = getDelegate().dequeueOutputBuffer(info, timeoutUs);
if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
cachedOutputBuffers = null;
}
return res;
}
@Nullable
@Override
ByteBuffer getOutputBuffer(int index) {
if (cachedOutputBuffers == null) {
cacheOutputBuffers();
}
if (cachedOutputBuffers == null) {
throw new IllegalStateException();
}
return cachedOutputBuffers[index];
}
@Override
void releaseOutputBuffer(int index, boolean render) {
cachedOutputBuffers = null;
getDelegate().releaseOutputBuffer(index, render);
}
private void cacheOutputBuffers() {
ByteBuffer[] buffers = null;
try {
buffers = getDelegate().getOutputBuffers();
} catch (IllegalStateException e) {
// we don't get buffers in async mode
}
cachedOutputBuffers = buffers;
}
}
@RequiresApi(21)
private static class Platform extends MediaCodecCompat {
Platform(@NonNull MediaCodec delegate) {
super(delegate);
}
@Override
int dequeueOutputBuffer(
@NonNull MediaCodec.BufferInfo info, long timeoutUs) {
return getDelegate().dequeueOutputBuffer(info, timeoutUs);
}
@Nullable
@Override
ByteBuffer getOutputBuffer(int index) {
return getDelegate().getOutputBuffer(index);
}
@Override
void releaseOutputBuffer(int index, boolean render) {
getDelegate().releaseOutputBuffer(index, render);
}
}
}

View file

@ -144,11 +144,10 @@ public class ScreenEncoder implements Device.RotationListener {
return 0;
}
@SuppressWarnings("deprecation") // Android API 19 requires to call deprecated methods
private boolean encode(MediaCodec codec, FileDescriptor fd) throws IOException {
private boolean encode(MediaCodec platformCodec, FileDescriptor fd) throws IOException {
final MediaCodecCompat codec = MediaCodecCompat.wrap(platformCodec);
boolean eof = false;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
ByteBuffer[] cachedOutputBuffers = null;
while (!consumeRotationChange() && !eof) {
int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1);
@ -159,15 +158,7 @@ public class ScreenEncoder implements Device.RotationListener {
break;
}
if (outputBufferId >= 0) {
ByteBuffer codecBuffer;
if (Build.VERSION.SDK_INT >= 21) {
codecBuffer = codec.getOutputBuffer(outputBufferId);
} else {
if (cachedOutputBuffers == null) {
cachedOutputBuffers = codec.getOutputBuffers();
}
codecBuffer = cachedOutputBuffers[outputBufferId];
}
ByteBuffer codecBuffer = codec.getOutputBuffer(outputBufferId);
if (sendFrameMeta) {
writeFrameMeta(fd, bufferInfo, codecBuffer.remaining());
@ -178,8 +169,6 @@ public class ScreenEncoder implements Device.RotationListener {
// If this is not a config packet, then it contains a frame
firstFrameSent = true;
}
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
cachedOutputBuffers = null;
}
} finally {
if (outputBufferId >= 0) {