mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 19:42:45 +00:00
Workaround the case where a buggy codec causes findSafeDecoder to fail
This commit is contained in:
parent
c02e1ed006
commit
ae298fbc51
@ -198,16 +198,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
controllerHandler = new ControllerHandler(conn);
|
controllerHandler = new ControllerHandler(conn);
|
||||||
|
|
||||||
decoderRenderer = new ConfigurableDecoderRenderer();
|
decoderRenderer = new ConfigurableDecoderRenderer();
|
||||||
|
decoderRenderer.initializeWithFlags(drFlags);
|
||||||
try {
|
|
||||||
decoderRenderer.initializeWithFlags(drFlags);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Dialog.displayDialog(this, "Hardware Decoder Failure",
|
|
||||||
"The hardware decoder failed to initialize. First, try restarting your device."+
|
|
||||||
"If the issue persists, please send an email to the app developer. Forcing software decoding" +
|
|
||||||
"can circumvent this error if needed.", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceHolder sh = sv.getHolder();
|
SurfaceHolder sh = sv.getHolder();
|
||||||
if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) {
|
if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) {
|
||||||
|
@ -22,10 +22,10 @@ public class ConfigurableDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
return decoderRenderer.setup(width, height, redrawRate, renderTarget, drFlags);
|
return decoderRenderer.setup(width, height, redrawRate, renderTarget, drFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeWithFlags(int drFlags) throws Exception {
|
public void initializeWithFlags(int drFlags) {
|
||||||
if ((drFlags & VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING) != 0 ||
|
if ((drFlags & VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING) != 0 ||
|
||||||
((drFlags & VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING) == 0 &&
|
((drFlags & VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING) == 0 &&
|
||||||
MediaCodecDecoderRenderer.findSafeDecoder() != null)) {
|
MediaCodecDecoderRenderer.findProbableSafeDecoder() != null)) {
|
||||||
decoderRenderer = new MediaCodecDecoderRenderer();
|
decoderRenderer = new MediaCodecDecoderRenderer();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -42,7 +42,9 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
static {
|
static {
|
||||||
blacklistedDecoderPrefixes = new LinkedList<String>();
|
blacklistedDecoderPrefixes = new LinkedList<String>();
|
||||||
|
|
||||||
// Nothing here right now :)
|
// Software decoders that don't support H264 high profile
|
||||||
|
blacklistedDecoderPrefixes.add("omx.google");
|
||||||
|
blacklistedDecoderPrefixes.add("AVCDecoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -70,7 +72,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dumpDecoders() {
|
public static void dumpDecoders() throws Exception {
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||||
|
|
||||||
@ -91,10 +93,50 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static MediaCodecInfo findFirstDecoder() {
|
||||||
|
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||||
|
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||||
|
|
||||||
|
// Skip encoders
|
||||||
|
if (codecInfo.isEncoder()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for explicitly blacklisted decoders
|
||||||
|
if (isDecoderInList(blacklistedDecoderPrefixes, codecInfo.getName())) {
|
||||||
|
LimeLog.info("Skipping blacklisted decoder: "+codecInfo.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a decoder that supports H.264
|
||||||
|
for (String mime : codecInfo.getSupportedTypes()) {
|
||||||
|
if (mime.equalsIgnoreCase("video/avc")) {
|
||||||
|
LimeLog.info("First decoder choice is "+codecInfo.getName());
|
||||||
|
return codecInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaCodecInfo findProbableSafeDecoder() {
|
||||||
|
// First look for decoders we know are safe
|
||||||
|
try {
|
||||||
|
// If this function completes, it will determine if the decoder is safe
|
||||||
|
return findKnownSafeDecoder();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Some buggy devices seem to throw exceptions
|
||||||
|
// from getCapabilitiesForType() so we'll just assume
|
||||||
|
// they're okay and go with the first one we find
|
||||||
|
return findFirstDecoder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We declare this method as explicitly throwing Exception
|
// We declare this method as explicitly throwing Exception
|
||||||
// since some bad decoders can throw IllegalArgumentExceptions unexpectedly
|
// since some bad decoders can throw IllegalArgumentExceptions unexpectedly
|
||||||
// and we want to be sure all callers are handling this possibility
|
// and we want to be sure all callers are handling this possibility
|
||||||
public static MediaCodecInfo findSafeDecoder() throws Exception {
|
private static MediaCodecInfo findKnownSafeDecoder() throws Exception {
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||||
|
|
||||||
@ -135,31 +177,32 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) {
|
public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) {
|
||||||
//dumpDecoders();
|
//dumpDecoders();
|
||||||
|
|
||||||
// It's nasty to put all this in a try-catch block,
|
MediaCodecInfo decoder = findProbableSafeDecoder();
|
||||||
// but codecs have been known to throw all sorts of crazy runtime exceptions
|
if (decoder == null) {
|
||||||
|
decoder = findFirstDecoder();
|
||||||
|
}
|
||||||
|
if (decoder == null) {
|
||||||
|
LimeLog.severe("No available hardware decoder!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Codecs have been known to throw all sorts of crazy runtime exceptions
|
||||||
// due to implementation problems
|
// due to implementation problems
|
||||||
try {
|
try {
|
||||||
MediaCodecInfo safeDecoder = findSafeDecoder();
|
videoDecoder = MediaCodec.createByCodecName(decoder.getName());
|
||||||
if (safeDecoder != null) {
|
|
||||||
videoDecoder = MediaCodec.createByCodecName(safeDecoder.getName());
|
|
||||||
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, safeDecoder.getName());
|
|
||||||
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, safeDecoder.getName());
|
|
||||||
if (needsSpsBitstreamFixup) {
|
|
||||||
LimeLog.info("Decoder "+safeDecoder.getName()+" needs SPS bitstream restrictions fixup");
|
|
||||||
}
|
|
||||||
if (needsSpsNumRefFixup) {
|
|
||||||
LimeLog.info("Decoder "+safeDecoder.getName()+" needs SPS ref num fixup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
videoDecoder = MediaCodec.createDecoderByType("video/avc");
|
|
||||||
needsSpsBitstreamFixup = false;
|
|
||||||
needsSpsNumRefFixup = false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoder.getName());
|
||||||
|
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, decoder.getName());
|
||||||
|
if (needsSpsBitstreamFixup) {
|
||||||
|
LimeLog.info("Decoder "+decoder.getName()+" needs SPS bitstream restrictions fixup");
|
||||||
|
}
|
||||||
|
if (needsSpsNumRefFixup) {
|
||||||
|
LimeLog.info("Decoder "+decoder.getName()+" needs SPS ref num fixup");
|
||||||
|
}
|
||||||
|
|
||||||
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
||||||
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
|
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
|
||||||
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
|
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user