Explicitly set max input size for H264 decoders.

This works around an issue where some devices, such as the Acer Iconia,
don't allocate large enough input buffers for H264.

Issue: #616
Issue: #714
This commit is contained in:
Oliver Woodman 2015-09-28 12:38:35 +01:00
parent decb7f58c7
commit 15c2f9c328
3 changed files with 38 additions and 11 deletions

View file

@ -196,7 +196,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
}
@Override
protected void configureCodec(MediaCodec codec, String codecName,
protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive,
android.media.MediaFormat format, android.media.MediaCrypto crypto) {
String mimeType = format.getString(android.media.MediaFormat.KEY_MIME);
if (RAW_DECODER_NAME.equals(codecName) && !MimeTypes.AUDIO_RAW.equals(mimeType)) {

View file

@ -269,10 +269,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
*
* @param codec The {@link MediaCodec} to configure.
* @param codecName The name of the codec.
* @param codecIsAdaptive Whether the codec is adaptive.
* @param format The format for which the codec is being configured.
* @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption.
*/
protected void configureCodec(MediaCodec codec, String codecName,
protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive,
android.media.MediaFormat format, MediaCrypto crypto) {
codec.configure(format, null, crypto, 0);
}
@ -320,28 +321,29 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR));
}
String decoderName = decoderInfo.name;
String codecName = decoderInfo.name;
codecIsAdaptive = decoderInfo.adaptive;
codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(decoderName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(decoderName);
codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
try {
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
TraceUtil.beginSection("createByCodecName(" + decoderName + ")");
codec = MediaCodec.createByCodecName(decoderName);
TraceUtil.beginSection("createByCodecName(" + codecName + ")");
codec = MediaCodec.createByCodecName(codecName);
TraceUtil.endSection();
TraceUtil.beginSection("configureCodec");
configureCodec(codec, decoderName, format.getFrameworkMediaFormatV16(), mediaCrypto);
configureCodec(codec, codecName, codecIsAdaptive, format.getFrameworkMediaFormatV16(),
mediaCrypto);
TraceUtil.endSection();
TraceUtil.beginSection("codec.start()");
codec.start();
TraceUtil.endSection();
long codecInitializedTimestamp = SystemClock.elapsedRealtime();
notifyDecoderInitialized(decoderName, codecInitializedTimestamp,
notifyDecoderInitialized(codecName, codecInitializedTimestamp,
codecInitializedTimestamp - codecInitializingTimestamp);
inputBuffers = codec.getInputBuffers();
outputBuffers = codec.getOutputBuffers();
} catch (Exception e) {
notifyAndThrowDecoderInitError(new DecoderInitializationException(format, e, decoderName));
notifyAndThrowDecoderInitError(new DecoderInitializationException(format, e, codecName));
}
codecHotswapTimeMs = getState() == TrackRenderer.STATE_STARTED ?
SystemClock.elapsedRealtime() : -1;

View file

@ -21,6 +21,7 @@ import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.TraceUtil;
import com.google.android.exoplayer.util.Util;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaCrypto;
@ -378,8 +379,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
// Override configureCodec to provide the surface.
@Override
protected void configureCodec(MediaCodec codec, String codecName,
protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive,
android.media.MediaFormat format, MediaCrypto crypto) {
maybeSetMaxInputSize(format, codecIsAdaptive);
codec.configure(format, surface, crypto, 0);
codec.setVideoScalingMode(videoScalingMode);
}
@ -548,6 +550,29 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
maybeNotifyDrawnToSurface();
}
@SuppressLint("InlinedApi")
private void maybeSetMaxInputSize(android.media.MediaFormat format, boolean codecIsAdaptive) {
if (!MimeTypes.VIDEO_H264.equals(format.getString(android.media.MediaFormat.KEY_MIME))) {
// Only set a max input size for H264 for now.
return;
}
if (format.containsKey(android.media.MediaFormat.KEY_MAX_INPUT_SIZE)) {
// Already set. The source of the format may know better, so do nothing.
return;
}
int maxHeight = format.getInteger(android.media.MediaFormat.KEY_HEIGHT);
if (codecIsAdaptive && format.containsKey(android.media.MediaFormat.KEY_MAX_HEIGHT)) {
maxHeight = Math.max(maxHeight, format.getInteger(android.media.MediaFormat.KEY_MAX_HEIGHT));
}
int maxWidth = format.getInteger(android.media.MediaFormat.KEY_WIDTH);
if (codecIsAdaptive && format.containsKey(android.media.MediaFormat.KEY_MAX_WIDTH)) {
maxWidth = Math.max(maxHeight, format.getInteger(android.media.MediaFormat.KEY_MAX_WIDTH));
}
// H264 requires compression ratio of at least 2, and uses macroblocks.
int maxInputSize = ((maxWidth + 15) / 16) * ((maxHeight + 15) / 16) * 192;
format.setInteger(android.media.MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize);
}
private void maybeNotifyVideoSizeChanged() {
if (eventHandler == null || eventListener == null
|| (lastReportedWidth == currentWidth && lastReportedHeight == currentHeight