Fix Samsung MediaCodec encoder reports incorrect timestmp in EOS

PiperOrigin-RevId: 492023573
This commit is contained in:
claincly 2022-11-30 22:46:25 +00:00 committed by Ian Baker
parent c7aa54cb41
commit 65fe41bc2c

View File

@ -64,6 +64,12 @@ import org.checkerframework.dataflow.qual.Pure;
private final EncoderWrapper encoderWrapper; private final EncoderWrapper encoderWrapper;
private final DecoderInputBuffer encoderOutputBuffer; private final DecoderInputBuffer encoderOutputBuffer;
/**
* The timestamp of the last buffer processed before {@linkplain
* FrameProcessor.Listener#onFrameProcessingEnded() frame processing has ended}.
*/
private volatile long finalFramePresentationTimeUs;
public VideoTranscodingSamplePipeline( public VideoTranscodingSamplePipeline(
Context context, Context context,
Format inputFormat, Format inputFormat,
@ -109,6 +115,8 @@ import org.checkerframework.dataflow.qual.Pure;
/* mediaCodecName= */ null, /* mediaCodecName= */ null,
TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED); TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED);
} }
finalFramePresentationTimeUs = C.TIME_UNSET;
} }
decoderInputBuffer = decoderInputBuffer =
@ -151,6 +159,8 @@ import org.checkerframework.dataflow.qual.Pure;
frameProcessorFactory.create( frameProcessorFactory.create(
context, context,
new FrameProcessor.Listener() { new FrameProcessor.Listener() {
private long lastProcessedFramePresentationTimeUs;
@Override @Override
public void onOutputSizeChanged(int width, int height) { public void onOutputSizeChanged(int width, int height) {
try { try {
@ -163,7 +173,8 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void onOutputFrameAvailable(long presentationTimeUs) { public void onOutputFrameAvailable(long presentationTimeUs) {
// Do nothing as frames are released automatically. // Frames are released automatically.
lastProcessedFramePresentationTimeUs = presentationTimeUs;
} }
@Override @Override
@ -175,6 +186,8 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
public void onFrameProcessingEnded() { public void onFrameProcessingEnded() {
VideoTranscodingSamplePipeline.this.finalFramePresentationTimeUs =
lastProcessedFramePresentationTimeUs;
try { try {
encoderWrapper.signalEndOfInputStream(); encoderWrapper.signalEndOfInputStream();
} catch (TransformationException exception) { } catch (TransformationException exception) {
@ -264,6 +277,16 @@ import org.checkerframework.dataflow.qual.Pure;
return null; return null;
} }
MediaCodec.BufferInfo bufferInfo = checkNotNull(encoderWrapper.getOutputBufferInfo()); MediaCodec.BufferInfo bufferInfo = checkNotNull(encoderWrapper.getOutputBufferInfo());
if (finalFramePresentationTimeUs != C.TIME_UNSET
&& bufferInfo.size > 0
&& bufferInfo.presentationTimeUs == 0) {
// Internal ref b/235045165: Some encoder incorrectly set a zero presentation time on the
// penultimate buffer (before EOS), and sets the actual timestamp on the EOS buffer. Use the
// last processed frame presentation time instead.
// bufferInfo.presentationTimeUs should never be 0 because we apply streamOffsetUs to the
// buffer presentationTimeUs.
bufferInfo.presentationTimeUs = finalFramePresentationTimeUs;
}
encoderOutputBuffer.timeUs = bufferInfo.presentationTimeUs; encoderOutputBuffer.timeUs = bufferInfo.presentationTimeUs;
encoderOutputBuffer.setFlags(bufferInfo.flags); encoderOutputBuffer.setFlags(bufferInfo.flags);
return encoderOutputBuffer; return encoderOutputBuffer;