mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-22 04:25:01 +00:00
Extract MediaCodecCompat from ScreenEncoder
This commit is contained in:
parent
2460552bb8
commit
48cdbb23a9
2 changed files with 119 additions and 14 deletions
116
server/src/main/java/com/genymobile/scrcpy/MediaCodecCompat.java
Normal file
116
server/src/main/java/com/genymobile/scrcpy/MediaCodecCompat.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue