Enable adaptive playback on non-Intel devices

This commit is contained in:
Cameron Gutman 2017-11-18 16:37:17 -08:00
parent f55d6308ce
commit 4deb881ec8
2 changed files with 75 additions and 45 deletions

View File

@ -33,6 +33,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
private byte[] vpsBuffer; private byte[] vpsBuffer;
private byte[] spsBuffer; private byte[] spsBuffer;
private byte[] ppsBuffer;
private boolean submittedCsd;
private boolean submitCsdNextCall;
private MediaCodec videoDecoder; private MediaCodec videoDecoder;
private Thread rendererThread; private Thread rendererThread;
@ -151,7 +154,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// shared between AVC and HEVC decoders on the same device. // shared between AVC and HEVC decoders on the same device.
if (avcDecoder != null) { if (avcDecoder != null) {
directSubmit = MediaCodecHelper.decoderCanDirectSubmit(avcDecoder.getName()); directSubmit = MediaCodecHelper.decoderCanDirectSubmit(avcDecoder.getName());
adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder.getName()); adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder);
refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName()); refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName());
refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(avcDecoder.getName()); refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(avcDecoder.getName());
@ -743,29 +746,44 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
else if (decodeUnitType == MoonBridge.BUFFER_TYPE_PPS) { else if (decodeUnitType == MoonBridge.BUFFER_TYPE_PPS) {
numPpsIn++; numPpsIn++;
inputBufferIndex = dequeueInputBuffer(); // If this is the first CSD blob or we aren't supporting
if (inputBufferIndex < 0) { // adaptive playback, we will submit the CSD blob in a
// We're being torn down now // separate input buffer.
return MoonBridge.DR_NEED_IDR; if (!submittedCsd || !adaptivePlayback) {
} inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) {
// We're being torn down now
return MoonBridge.DR_NEED_IDR;
}
buf = getEmptyInputBuffer(inputBufferIndex); buf = getEmptyInputBuffer(inputBufferIndex);
if (buf == null) { if (buf == null) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_NEED_IDR; return MoonBridge.DR_NEED_IDR;
} }
// When we get the PPS, submit the VPS and SPS together with // When we get the PPS, submit the VPS and SPS together with
// the PPS, as required by AOSP docs on use of MediaCodec. // the PPS, as required by AOSP docs on use of MediaCodec.
if (vpsBuffer != null) { if (vpsBuffer != null) {
buf.put(vpsBuffer); buf.put(vpsBuffer);
} }
if (spsBuffer != null) { if (spsBuffer != null) {
buf.put(spsBuffer); buf.put(spsBuffer);
} }
// This is the CSD blob // This is the CSD blob
codecFlags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG; codecFlags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
}
else {
// Batch this to submit together with the next I-frame
ppsBuffer = new byte[decodeUnitLength];
System.arraycopy(decodeUnitData, 0, ppsBuffer, 0, decodeUnitLength);
// Next call will be I-frame data
submitCsdNextCall = true;
return MoonBridge.DR_OK;
}
} }
else { else {
inputBufferIndex = dequeueInputBuffer(); inputBufferIndex = dequeueInputBuffer();
@ -779,6 +797,20 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_NEED_IDR; return MoonBridge.DR_NEED_IDR;
} }
if (submitCsdNextCall) {
if (vpsBuffer != null) {
buf.put(vpsBuffer);
}
if (spsBuffer != null) {
buf.put(spsBuffer);
}
if (ppsBuffer != null) {
buf.put(ppsBuffer);
}
submitCsdNextCall = false;
}
} }
// Copy data from our buffer list into the input buffer // Copy data from our buffer list into the input buffer
@ -790,14 +822,18 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return MoonBridge.DR_NEED_IDR; return MoonBridge.DR_NEED_IDR;
} }
if (needsBaselineSpsHack) { if ((codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
needsBaselineSpsHack = false; submittedCsd = true;
if (!replaySps()) { if (needsBaselineSpsHack) {
return MoonBridge.DR_NEED_IDR; needsBaselineSpsHack = false;
if (!replaySps()) {
return MoonBridge.DR_NEED_IDR;
}
LimeLog.info("SPS replay complete");
} }
LimeLog.info("SPS replay complete");
} }
return MoonBridge.DR_OK; return MoonBridge.DR_OK;

View File

@ -27,7 +27,7 @@ public class MediaCodecHelper {
private static final List<String> blacklistedDecoderPrefixes; private static final List<String> blacklistedDecoderPrefixes;
private static final List<String> spsFixupBitstreamFixupDecoderPrefixes; private static final List<String> spsFixupBitstreamFixupDecoderPrefixes;
private static final List<String> whitelistedAdaptiveResolutionPrefixes; private static final List<String> blacklistedAdaptivePlaybackPrefixes;
private static final List<String> deprioritizedHevcDecoders; private static final List<String> deprioritizedHevcDecoders;
private static final List<String> baselineProfileHackPrefixes; private static final List<String> baselineProfileHackPrefixes;
private static final List<String> directSubmitPrefixes; private static final List<String> directSubmitPrefixes;
@ -93,11 +93,10 @@ public class MediaCodecHelper {
baselineProfileHackPrefixes = new LinkedList<>(); baselineProfileHackPrefixes = new LinkedList<>();
baselineProfileHackPrefixes.add("omx.intel"); baselineProfileHackPrefixes.add("omx.intel");
whitelistedAdaptiveResolutionPrefixes = new LinkedList<>(); // The Intel decoder on Lollipop on Nexus Player would increase latency badly
whitelistedAdaptiveResolutionPrefixes.add("omx.nvidia"); // if adaptive playback was enabled so let's avoid it to be safe.
whitelistedAdaptiveResolutionPrefixes.add("omx.qcom"); blacklistedAdaptivePlaybackPrefixes = new LinkedList<>();
whitelistedAdaptiveResolutionPrefixes.add("omx.sec"); blacklistedAdaptivePlaybackPrefixes.add("omx.intel");
whitelistedAdaptiveResolutionPrefixes.add("omx.TI");
constrainedHighProfilePrefixes = new LinkedList<>(); constrainedHighProfilePrefixes = new LinkedList<>();
constrainedHighProfilePrefixes.add("omx.intel"); constrainedHighProfilePrefixes.add("omx.intel");
@ -208,19 +207,14 @@ public class MediaCodecHelper {
return System.nanoTime() / 1000000L; return System.nanoTime() / 1000000L;
} }
@TargetApi(Build.VERSION_CODES.KITKAT) public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo) {
public static boolean decoderSupportsAdaptivePlayback(String decoderName) {
/*
FIXME: Intel's decoder on Nexus Player forces the high latency path if adaptive playback is enabled
so we'll keep it off for now, since we don't know whether other devices also do the same
if (isDecoderInList(whitelistedAdaptiveResolutionPrefixes, decoderName)) {
LimeLog.info("Adaptive playback supported (whitelist)");
return true;
}
// Possibly enable adaptive playback on KitKat and above // Possibly enable adaptive playback on KitKat and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
LimeLog.info("Decoder blacklisted for adaptive playback");
return false;
}
try { try {
if (decoderInfo.getCapabilitiesForType("video/avc"). if (decoderInfo.getCapabilitiesForType("video/avc").
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)) isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
@ -232,7 +226,7 @@ public class MediaCodecHelper {
} catch (Exception e) { } catch (Exception e) {
// Tolerate buggy codecs // Tolerate buggy codecs
} }
}*/ }
return false; return false;
} }