Propagate output format in tunneling mode

From API 23 this uses the timed format queue. Before API 23 the
format is notified as soon as the buffer is queued.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=213830729
This commit is contained in:
andrewlewis 2018-09-20 09:48:44 -07:00 committed by Oliver Woodman
parent 300dc05e85
commit 03fe503f1c
2 changed files with 61 additions and 29 deletions

View File

@ -497,6 +497,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return false; return false;
} }
/**
* Polls the pending output format queue for a given buffer timestamp. If a format is present, it
* is removed and returned. Otherwise returns {@code null}. Subclasses should only call this
* method if they are taking over responsibility for output format propagation (e.g., when using
* video tunneling).
*/
protected final @Nullable Format updateOutputFormatForTime(long presentationTimeUs) {
Format format = formatQueue.pollFloor(presentationTimeUs);
if (format != null) {
outputFormat = format;
}
return format;
}
protected final MediaCodec getCodec() { protected final MediaCodec getCodec() {
return codec; return codec;
} }
@ -1297,10 +1311,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size); outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
} }
shouldSkipOutputBuffer = shouldSkipOutputBuffer(outputBufferInfo.presentationTimeUs); shouldSkipOutputBuffer = shouldSkipOutputBuffer(outputBufferInfo.presentationTimeUs);
Format format = formatQueue.pollFloor(outputBufferInfo.presentationTimeUs); updateOutputFormatForTime(outputBufferInfo.presentationTimeUs);
if (format != null) {
outputFormat = format;
}
} }
boolean processedOutputBuffer; boolean processedOutputBuffer;

View File

@ -566,7 +566,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
buffersInCodecCount++; buffersInCodecCount++;
lastInputTimeUs = Math.max(buffer.timeUs, lastInputTimeUs); lastInputTimeUs = Math.max(buffer.timeUs, lastInputTimeUs);
if (Util.SDK_INT < 23 && tunneling) { if (Util.SDK_INT < 23 && tunneling) {
maybeNotifyRenderedFirstFrame(); // In tunneled mode before API 23 we don't have a way to know when the buffer is output, so
// treat it as if it were output immediately.
onProcessedTunneledBuffer(buffer.timeUs);
} }
} }
@ -575,29 +577,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
boolean hasCrop = outputFormat.containsKey(KEY_CROP_RIGHT) boolean hasCrop = outputFormat.containsKey(KEY_CROP_RIGHT)
&& outputFormat.containsKey(KEY_CROP_LEFT) && outputFormat.containsKey(KEY_CROP_BOTTOM) && outputFormat.containsKey(KEY_CROP_LEFT) && outputFormat.containsKey(KEY_CROP_BOTTOM)
&& outputFormat.containsKey(KEY_CROP_TOP); && outputFormat.containsKey(KEY_CROP_TOP);
currentWidth = hasCrop int width =
? outputFormat.getInteger(KEY_CROP_RIGHT) - outputFormat.getInteger(KEY_CROP_LEFT) + 1 hasCrop
: outputFormat.getInteger(MediaFormat.KEY_WIDTH); ? outputFormat.getInteger(KEY_CROP_RIGHT) - outputFormat.getInteger(KEY_CROP_LEFT) + 1
currentHeight = hasCrop : outputFormat.getInteger(MediaFormat.KEY_WIDTH);
? outputFormat.getInteger(KEY_CROP_BOTTOM) - outputFormat.getInteger(KEY_CROP_TOP) + 1 int height =
: outputFormat.getInteger(MediaFormat.KEY_HEIGHT); hasCrop
currentPixelWidthHeightRatio = pendingPixelWidthHeightRatio; ? outputFormat.getInteger(KEY_CROP_BOTTOM) - outputFormat.getInteger(KEY_CROP_TOP) + 1
if (Util.SDK_INT >= 21) { : outputFormat.getInteger(MediaFormat.KEY_HEIGHT);
// On API level 21 and above the decoder applies the rotation when rendering to the surface. processOutputFormat(codec, width, height);
// 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 format changes.
codec.setVideoScalingMode(scalingMode);
} }
@Override @Override
@ -705,6 +693,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 format changes.
codec.setVideoScalingMode(scalingMode);
}
private void notifyFrameMetadataListener( private void notifyFrameMetadataListener(
long presentationTimeUs, long releaseTimeNs, Format format) { long presentationTimeUs, long releaseTimeNs, Format format) {
if (frameMetadataListener != null) { if (frameMetadataListener != null) {
@ -722,6 +732,17 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
return outputStreamOffsetUs; return outputStreamOffsetUs;
} }
/** Called when a buffer was processed in tunneling mode. */
protected void onProcessedTunneledBuffer(long presentationTimeUs) {
@Nullable Format format = updateOutputFormatForTime(presentationTimeUs);
if (format != null) {
processOutputFormat(getCodec(), format.width, format.height);
}
maybeNotifyVideoSizeChanged();
maybeNotifyRenderedFirstFrame();
onProcessedOutputBuffer(presentationTimeUs);
}
/** /**
* Called when an output buffer is successfully processed. * Called when an output buffer is successfully processed.
* *
@ -1463,7 +1484,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// Stale event. // Stale event.
return; return;
} }
maybeNotifyRenderedFirstFrame(); onProcessedTunneledBuffer(presentationTimeUs);
} }
} }