Commit 1536a2ce by olly Committed by bachinger

Rollback of https://github.com/google/ExoPlayer/commit/e26a61b903739014271ab0886bb5db75afb3f1fd

*** Original commit ***

Improve `Format` propagation within the `MediaCodecRenderer`.

For example, fix handling of pixel aspect ratio changes in
playlists where video resolution does not change.

Issue:#6646

***

PiperOrigin-RevId: 282903626
parent 69a2cb86
...@@ -10,13 +10,6 @@ ...@@ -10,13 +10,6 @@
* Require an end time or duration for SubRip (SRT) and SubStation Alpha * Require an end time or duration for SubRip (SRT) and SubStation Alpha
(SSA/ASS) subtitles. This applies to both sidecar files & subtitles (SSA/ASS) subtitles. This applies to both sidecar files & subtitles
[embedded in Matroska streams](https://matroska.org/technical/specs/subtitles/index.html). [embedded in Matroska streams](https://matroska.org/technical/specs/subtitles/index.html).
* Improve `Format` propagation within the `MediaCodecRenderer` and subclasses.
For example, fix handling of pixel aspect ratio changes in playlists where
video resolution does not change.
([#6646](https://github.com/google/ExoPlayer/issues/6646)).
* Rename `MediaCodecRenderer.onOutputFormatChanged` to
`MediaCodecRenderer.onOutputMediaFormatChanged`, further
clarifying the distinction between `Format` and `MediaFormat`.
* Reconfigure audio sink when PCM encoding changes * Reconfigure audio sink when PCM encoding changes
([#6601](https://github.com/google/ExoPlayer/issues/6601)). ([#6601](https://github.com/google/ExoPlayer/issues/6601)).
* Make `MediaSourceEventListener.LoadEventInfo` and * Make `MediaSourceEventListener.LoadEventInfo` and
......
...@@ -475,10 +475,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -475,10 +475,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
protected @KeepCodecResult int canKeepCodec( protected @KeepCodecResult int canKeepCodec(
MediaCodec codec, MediaCodecInfo codecInfo, Format oldFormat, Format newFormat) { MediaCodec codec, MediaCodecInfo codecInfo, Format oldFormat, Format newFormat) {
// TODO: We currently rely on recreating the codec when encoder delay or padding is non-zero. // TODO: We currently rely on recreating the codec when encoder delay or padding is non-zero.
// Re-creating the codec is necessary to guarantee that onOutputMediaFormatChanged is called, // Re-creating the codec is necessary to guarantee that onOutputFormatChanged is called, which
// which is where encoder delay and padding are propagated to the sink. We should find a better // is where encoder delay and padding are propagated to the sink. We should find a better way to
// way to propagate these values, and then allow the codec to be re-used in cases where this // propagate these values, and then allow the codec to be re-used in cases where this would
// would otherwise be possible. // otherwise be possible.
if (getCodecMaxInputSize(codecInfo, newFormat) > codecMaxInputSize if (getCodecMaxInputSize(codecInfo, newFormat) > codecMaxInputSize
|| oldFormat.encoderDelay != 0 || oldFormat.encoderDelay != 0
|| oldFormat.encoderPadding != 0 || oldFormat.encoderPadding != 0
...@@ -558,7 +558,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -558,7 +558,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
@Override @Override
protected void onOutputMediaFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat) protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat)
throws ExoPlaybackException { throws ExoPlaybackException {
@C.Encoding int encoding; @C.Encoding int encoding;
MediaFormat mediaFormat; MediaFormat mediaFormat;
......
...@@ -565,7 +565,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -565,7 +565,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return true; return true;
} }
/* /**
* Returns whether the codec needs the renderer to propagate the end-of-stream signal directly, * Returns whether the codec needs the renderer to propagate the end-of-stream signal directly,
* rather than by using an end-of-stream buffer queued to the codec. * rather than by using an end-of-stream buffer queued to the codec.
*/ */
...@@ -574,17 +574,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -574,17 +574,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Polls the pending output format queue for a given buffer timestamp. If a format is present, * Polls the pending output format queue for a given buffer timestamp. If a format is present, it
* {@link #onOutputFormatChanged(Format)} is called. Subclasses should only call this method if * is removed and returned. Otherwise returns {@code null}. Subclasses should only call this
* they are taking over responsibility for output format propagation (e.g., when using video * method if they are taking over responsibility for output format propagation (e.g., when using
* tunneling). * video tunneling).
*/ */
protected final void updateOutputFormatForTime(long presentationTimeUs) { protected final @Nullable Format updateOutputFormatForTime(long presentationTimeUs) {
@Nullable Format format = formatQueue.pollFloor(presentationTimeUs); Format format = formatQueue.pollFloor(presentationTimeUs);
if (format != null) { if (format != null) {
outputFormat = format; outputFormat = format;
onOutputFormatChanged(outputFormat);
} }
return format;
} }
protected final MediaCodec getCodec() { protected final MediaCodec getCodec() {
...@@ -1307,23 +1307,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1307,23 +1307,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @param outputMediaFormat The new output {@link MediaFormat}. * @param outputMediaFormat The new output {@link MediaFormat}.
* @throws ExoPlaybackException Thrown if an error occurs handling the new output media format. * @throws ExoPlaybackException Thrown if an error occurs handling the new output media format.
*/ */
protected void onOutputMediaFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat) protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat)
throws ExoPlaybackException { throws ExoPlaybackException {
// Do nothing. // Do nothing.
} }
/** /**
* Called when the output {@link Format} changes from the format queue.
*
* <p>The default implementation is a no-op.
*
* @param outputFormat The new output {@link Format}.
*/
protected void onOutputFormatChanged(Format outputFormat) {
// Do nothing.
}
/**
* Handles supplemental data associated with an input buffer. * Handles supplemental data associated with an input buffer.
* *
* <p>The default implementation is a no-op. * <p>The default implementation is a no-op.
...@@ -1517,7 +1506,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1517,7 +1506,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (outputIndex < 0) { if (outputIndex < 0) {
if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED /* (-2) */) { if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED /* (-2) */) {
processOutputMediaFormat(); processOutputFormat();
return true; return true;
} else if (outputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED /* (-3) */) { } else if (outputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED /* (-3) */) {
processOutputBuffersChanged(); processOutputBuffersChanged();
...@@ -1609,7 +1598,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1609,7 +1598,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** Processes a new output {@link MediaFormat}. */ /** Processes a new output {@link MediaFormat}. */
private void processOutputMediaFormat() throws ExoPlaybackException { private void processOutputFormat() throws ExoPlaybackException {
MediaFormat mediaFormat = codec.getOutputFormat(); MediaFormat mediaFormat = codec.getOutputFormat();
if (codecAdaptationWorkaroundMode != ADAPTATION_WORKAROUND_MODE_NEVER if (codecAdaptationWorkaroundMode != ADAPTATION_WORKAROUND_MODE_NEVER
&& mediaFormat.getInteger(MediaFormat.KEY_WIDTH) == ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT && mediaFormat.getInteger(MediaFormat.KEY_WIDTH) == ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
...@@ -1622,7 +1611,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1622,7 +1611,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codecNeedsMonoChannelCountWorkaround) { if (codecNeedsMonoChannelCountWorkaround) {
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
} }
onOutputMediaFormatChanged(codec, mediaFormat); onOutputFormatChanged(codec, mediaFormat);
} }
/** /**
......
...@@ -143,9 +143,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -143,9 +143,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private int buffersInCodecCount; private int buffersInCodecCount;
private long lastRenderTimeUs; private long lastRenderTimeUs;
private int pendingRotationDegrees;
private float pendingPixelWidthHeightRatio;
@Nullable private MediaFormat currentMediaFormat; @Nullable private MediaFormat currentMediaFormat;
private int mediaFormatWidth;
private int mediaFormatHeight;
private int currentWidth; private int currentWidth;
private int currentHeight; private int currentHeight;
private int currentUnappliedRotationDegrees; private int currentUnappliedRotationDegrees;
...@@ -353,9 +353,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -353,9 +353,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
joiningDeadlineMs = C.TIME_UNSET; joiningDeadlineMs = C.TIME_UNSET;
currentWidth = Format.NO_VALUE; currentWidth = Format.NO_VALUE;
currentHeight = Format.NO_VALUE; currentHeight = Format.NO_VALUE;
mediaFormatWidth = Format.NO_VALUE;
mediaFormatHeight = Format.NO_VALUE;
currentPixelWidthHeightRatio = Format.NO_VALUE; currentPixelWidthHeightRatio = Format.NO_VALUE;
pendingPixelWidthHeightRatio = Format.NO_VALUE;
scalingMode = C.VIDEO_SCALING_MODE_DEFAULT; scalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
clearReportedVideoSize(); clearReportedVideoSize();
} }
...@@ -750,7 +749,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -750,7 +749,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override @Override
protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
super.onInputFormatChanged(formatHolder); super.onInputFormatChanged(formatHolder);
eventDispatcher.inputFormatChanged(formatHolder.format); Format newFormat = formatHolder.format;
eventDispatcher.inputFormatChanged(newFormat);
pendingPixelWidthHeightRatio = newFormat.pixelWidthHeightRatio;
pendingRotationDegrees = newFormat.rotationDegrees;
} }
/** /**
...@@ -771,56 +773,26 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -771,56 +773,26 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} }
@Override @Override
protected void onOutputMediaFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat) { protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputMediaFormat) {
currentMediaFormat = outputMediaFormat; currentMediaFormat = outputMediaFormat;
boolean hasCrop = boolean hasCrop =
outputMediaFormat.containsKey(KEY_CROP_RIGHT) outputMediaFormat.containsKey(KEY_CROP_RIGHT)
&& outputMediaFormat.containsKey(KEY_CROP_LEFT) && outputMediaFormat.containsKey(KEY_CROP_LEFT)
&& outputMediaFormat.containsKey(KEY_CROP_BOTTOM) && outputMediaFormat.containsKey(KEY_CROP_BOTTOM)
&& outputMediaFormat.containsKey(KEY_CROP_TOP); && outputMediaFormat.containsKey(KEY_CROP_TOP);
mediaFormatWidth = int width =
hasCrop hasCrop
? outputMediaFormat.getInteger(KEY_CROP_RIGHT) ? outputMediaFormat.getInteger(KEY_CROP_RIGHT)
- outputMediaFormat.getInteger(KEY_CROP_LEFT) - outputMediaFormat.getInteger(KEY_CROP_LEFT)
+ 1 + 1
: outputMediaFormat.getInteger(MediaFormat.KEY_WIDTH); : outputMediaFormat.getInteger(MediaFormat.KEY_WIDTH);
mediaFormatHeight = int height =
hasCrop hasCrop
? outputMediaFormat.getInteger(KEY_CROP_BOTTOM) ? outputMediaFormat.getInteger(KEY_CROP_BOTTOM)
- outputMediaFormat.getInteger(KEY_CROP_TOP) - outputMediaFormat.getInteger(KEY_CROP_TOP)
+ 1 + 1
: outputMediaFormat.getInteger(MediaFormat.KEY_HEIGHT); : outputMediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
processOutputFormat(codec, width, height);
// Must be applied each time the output MediaFormat changes.
codec.setVideoScalingMode(scalingMode);
}
@Override
protected void onOutputFormatChanged(Format outputFormat) {
if (tunneling) {
currentWidth = outputFormat.width;
currentHeight = outputFormat.height;
} else {
currentWidth = mediaFormatWidth;
currentHeight = mediaFormatHeight;
}
currentPixelWidthHeightRatio = outputFormat.pixelWidthHeightRatio;
if (Util.SDK_INT >= 21) {
// On API level 21 and above the decoder applies the rotation when rendering to the surface.
// Hence currentUnappliedRotation should always be 0. For 90 and 270 degree rotations, we need
// to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
if (outputFormat.rotationDegrees == 90 || outputFormat.rotationDegrees == 270) {
int rotatedHeight = currentWidth;
currentWidth = currentHeight;
currentHeight = rotatedHeight;
currentPixelWidthHeightRatio = 1 / currentPixelWidthHeightRatio;
}
} else {
// On API level 20 and below the decoder does not apply the rotation.
currentUnappliedRotationDegrees = outputFormat.rotationDegrees;
}
} }
@Override @Override
...@@ -973,6 +945,28 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -973,6 +945,28 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
return false; return false;
} }
private void processOutputFormat(MediaCodec codec, int width, int height) {
currentWidth = width;
currentHeight = height;
currentPixelWidthHeightRatio = pendingPixelWidthHeightRatio;
if (Util.SDK_INT >= 21) {
// On API level 21 and above the decoder applies the rotation when rendering to the surface.
// Hence currentUnappliedRotation should always be 0. For 90 and 270 degree rotations, we need
// to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
if (pendingRotationDegrees == 90 || pendingRotationDegrees == 270) {
int rotatedHeight = currentWidth;
currentWidth = currentHeight;
currentHeight = rotatedHeight;
currentPixelWidthHeightRatio = 1 / currentPixelWidthHeightRatio;
}
} else {
// On API level 20 and below the decoder does not apply the rotation.
currentUnappliedRotationDegrees = pendingRotationDegrees;
}
// Must be applied each time the output MediaFormat changes.
codec.setVideoScalingMode(scalingMode);
}
private void notifyFrameMetadataListener( private void notifyFrameMetadataListener(
long presentationTimeUs, long releaseTimeNs, Format format, MediaFormat mediaFormat) { long presentationTimeUs, long releaseTimeNs, Format format, MediaFormat mediaFormat) {
if (frameMetadataListener != null) { if (frameMetadataListener != null) {
...@@ -992,7 +986,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -992,7 +986,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
/** Called when a buffer was processed in tunneling mode. */ /** Called when a buffer was processed in tunneling mode. */
protected void onProcessedTunneledBuffer(long presentationTimeUs) { protected void onProcessedTunneledBuffer(long presentationTimeUs) {
updateOutputFormatForTime(presentationTimeUs); @Nullable Format format = updateOutputFormatForTime(presentationTimeUs);
if (format != null) {
processOutputFormat(getCodec(), format.width, format.height);
}
maybeNotifyVideoSizeChanged(); maybeNotifyVideoSizeChanged();
maybeNotifyRenderedFirstFrame(); maybeNotifyRenderedFirstFrame();
onProcessedOutputBuffer(presentationTimeUs); onProcessedOutputBuffer(presentationTimeUs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment