diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java index 4c223408f8..a1bf1f04ac 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java @@ -303,8 +303,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer } /** - * Configures a newly created {@link MediaCodec}. Sub-classes should override this method if they - * wish to configure the codec with a non-null surface. + * Configures a newly created {@link MediaCodec}. * * @param codec The {@link MediaCodec} to configure. * @param format The format for which the codec is being configured. diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java index 8355d8f114..a742a4f22a 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java @@ -110,6 +110,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { private final long allowedJoiningTimeUs; private final int videoScalingMode; private final int maxDroppedFrameCountToNotify; + private final boolean deviceNeedsAutoFrcWorkaround; private int adaptiveMaxWidth; private int adaptiveMaxHeight; @@ -208,6 +209,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { this.allowedJoiningTimeUs = allowedJoiningTimeMs * 1000; this.eventListener = eventListener; this.maxDroppedFrameCountToNotify = maxDroppedFrameCountToNotify; + deviceNeedsAutoFrcWorkaround = deviceNeedsAutoFrcWorkaround(); joiningDeadlineUs = -1; currentWidth = -1; currentHeight = -1; @@ -544,6 +546,10 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { private android.media.MediaFormat getFrameworkMediaFormat(Format format) { android.media.MediaFormat frameworkMediaFormat = format.getFrameworkMediaFormatV16(); + if (deviceNeedsAutoFrcWorkaround) { + frameworkMediaFormat.setInteger("auto-frc", 0); + } + // Set the maximum adaptive video dimensions if applicable. if (adaptiveMaxWidth != Format.NO_VALUE && adaptiveMaxHeight != Format.NO_VALUE) { frameworkMediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, adaptiveMaxWidth); @@ -651,4 +657,22 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { droppedFrameAccumulationStartTimeMs = now; } + /** + * Returns whether the device is known to enable frame-rate conversion logic that negatively + * impacts ExoPlayer. + *
+ * If true is returned then we explicitly disable the feature. + * + * @return True if the device is known to enable frame-rate conversion logic that negatively + * impacts ExoPlayer. False otherwise. + */ + private static boolean deviceNeedsAutoFrcWorkaround() { + // nVidia Shield prior to M tries to adjust the playback rate to better map the frame-rate of + // content to the refresh rate of the display. For example playback of 23.976fps content is + // adjusted to play at 1.001x speed when the output display is 60Hz. Unfortunately the + // implementation causes ExoPlayer's reported playback position to drift out of sync. Captions + // also lose sync [Internal: b/26453592]. + return Util.SDK_INT <= 22 && "foster".equals(Util.DEVICE) && "NVIDIA".equals(Util.MANUFACTURER); + } + }