List available encoders on invalid name specified

If an invalid encoder name is given via the --encoder option, list all
the H.264 encoders available on the device.
This commit is contained in:
Romain Vimont 2020-11-07 15:53:48 +01:00
parent 363eeea19e
commit 42ab8fd611
3 changed files with 53 additions and 1 deletions

View file

@ -0,0 +1,23 @@
package com.genymobile.scrcpy;
import android.media.MediaCodecInfo;
public class InvalidEncoderException extends RuntimeException {
private final String name;
private final MediaCodecInfo[] availableEncoders;
public InvalidEncoderException(String name, MediaCodecInfo[] availableEncoders) {
super("There is no encoder having name '" + name + '"');
this.name = name;
this.availableEncoders = availableEncoders;
}
public String getName() {
return name;
}
public MediaCodecInfo[] getAvailableEncoders() {
return availableEncoders;
}
}

View file

@ -5,6 +5,7 @@ import com.genymobile.scrcpy.wrappers.SurfaceControl;
import android.graphics.Rect; import android.graphics.Rect;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.IBinder; import android.os.IBinder;
import android.view.Surface; import android.view.Surface;
@ -12,6 +13,8 @@ import android.view.Surface;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -152,10 +155,26 @@ public class ScreenEncoder implements Device.RotationListener {
IO.writeFully(fd, headerBuffer); IO.writeFully(fd, headerBuffer);
} }
private static MediaCodecInfo[] listEncoders() {
List<MediaCodecInfo> result = new ArrayList<>();
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo codecInfo : list.getCodecInfos()) {
if (codecInfo.isEncoder() && Arrays.asList(codecInfo.getSupportedTypes()).contains(MediaFormat.MIMETYPE_VIDEO_AVC)) {
result.add(codecInfo);
}
}
return result.toArray(new MediaCodecInfo[result.size()]);
}
private static MediaCodec createCodec(String encoderName) throws IOException { private static MediaCodec createCodec(String encoderName) throws IOException {
if (encoderName != null) { if (encoderName != null) {
Ln.d("Creating encoder by name: '" + encoderName + "'"); Ln.d("Creating encoder by name: '" + encoderName + "'");
try {
return MediaCodec.createByCodecName(encoderName); return MediaCodec.createByCodecName(encoderName);
} catch (IllegalArgumentException e) {
MediaCodecInfo[] encoders = listEncoders();
throw new InvalidEncoderException(encoderName, encoders);
}
} }
MediaCodec codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC); MediaCodec codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
Ln.d("Using encoder: '" + codec.getName() + "'"); Ln.d("Using encoder: '" + codec.getName() + "'");

View file

@ -4,6 +4,7 @@ import com.genymobile.scrcpy.wrappers.ContentProvider;
import android.graphics.Rect; import android.graphics.Rect;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
@ -210,6 +211,15 @@ public final class Server {
Ln.e(" scrcpy --display " + id); Ln.e(" scrcpy --display " + id);
} }
} }
} else if (e instanceof InvalidEncoderException) {
InvalidEncoderException iee = (InvalidEncoderException) e;
MediaCodecInfo[] encoders = iee.getAvailableEncoders();
if (encoders != null && encoders.length > 0) {
Ln.e("Try to use one of the available encoders:");
for (MediaCodecInfo encoder : encoders) {
Ln.e(" scrcpy --encoder-name '" + encoder.getName() + "'");
}
}
} }
} }