Fix transcoding drops a few frames.

In the old version, the transcoder uses decoder.isEnded() alone as the criteria
to stop the encoding/muxing process. It's rectified to:

- On decoder ending, signal the encoder of EOS after writing all decoded frames to it.
- On encoder ending, write end track to muxer.

PiperOrigin-RevId: 393322114
This commit is contained in:
claincly 2021-08-27 12:16:53 +01:00 committed by bachinger
parent 9c2b4b860b
commit 58e5ed0afb
6 changed files with 45 additions and 5 deletions

View file

@ -303,6 +303,11 @@ import java.nio.ByteBuffer;
codec.setVideoScalingMode(scalingMode); codec.setVideoScalingMode(scalingMode);
} }
@Override
public void signalEndOfInputStream() {
codec.signalEndOfInputStream();
}
@VisibleForTesting @VisibleForTesting
/* package */ void onError(MediaCodec.CodecException error) { /* package */ void onError(MediaCodec.CodecException error) {
asynchronousMediaCodecCallback.onError(codec, error); asynchronousMediaCodecCallback.onError(codec, error);

View file

@ -242,4 +242,13 @@ public interface MediaCodecAdapter {
/** Whether the adapter needs to be reconfigured before it is used. */ /** Whether the adapter needs to be reconfigured before it is used. */
boolean needsReconfiguration(); boolean needsReconfiguration();
/**
* Signals the encoder of end-of-stream on input. The call can only be used when the encoder
* receives its input from a {@link Surface surface}.
*
* @see MediaCodec#signalEndOfInputStream()
*/
@RequiresApi(18)
void signalEndOfInputStream();
} }

View file

@ -199,6 +199,12 @@ public class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
codec.release(); codec.release();
} }
@Override
@RequiresApi(18)
public void signalEndOfInputStream() {
Api18.signalEndOfInputStream(codec);
}
@Override @Override
@RequiresApi(23) @RequiresApi(23)
public void setOnFrameRenderedListener(OnFrameRenderedListener listener, Handler handler) { public void setOnFrameRenderedListener(OnFrameRenderedListener listener, Handler handler) {
@ -232,5 +238,10 @@ public class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
public static Surface createCodecInputSurface(MediaCodec codec) { public static Surface createCodecInputSurface(MediaCodec codec) {
return codec.createInputSurface(); return codec.createInputSurface();
} }
@DoNotInline
public static void signalEndOfInputStream(MediaCodec codec) {
codec.signalEndOfInputStream();
}
} }
} }

View file

@ -311,6 +311,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
inputBuffer.data = null; inputBuffer.data = null;
} }
@RequiresApi(18)
public void signalEndOfInputStream() {
codec.signalEndOfInputStream();
}
/** Returns the current output format, if available. */ /** Returns the current output format, if available. */
@Nullable @Nullable
public Format getOutputFormat() { public Format getOutputFormat() {

View file

@ -175,8 +175,15 @@ import java.nio.ByteBuffer;
if (decoder.isEnded()) { if (decoder.isEnded()) {
return false; return false;
} }
// Rendering the decoder output queues input to the encoder because they share the same surface. // Rendering the decoder output queues input to the encoder because they share the same surface.
return decoder.maybeDequeueRenderAndReleaseOutputBuffer(); boolean hasProcessedOutputBuffer = decoder.maybeDequeueRenderAndReleaseOutputBuffer();
if (decoder.isEnded()) {
checkNotNull(encoder).signalEndOfInputStream();
// All decoded frames have been rendered to the encoder's input surface.
return false;
}
return hasProcessedOutputBuffer;
} }
private boolean feedMuxerFromEncoder() { private boolean feedMuxerFromEncoder() {
@ -190,10 +197,7 @@ import java.nio.ByteBuffer;
muxerWrapper.addTrackFormat(encoderOutputFormat); muxerWrapper.addTrackFormat(encoderOutputFormat);
} }
// TODO(claincly) May have to use inputStreamBuffer.isEndOfStream result to call if (encoder.isEnded()) {
// decoder.signalEndOfInputStream().
MediaCodecAdapterWrapper decoder = checkNotNull(this.decoder);
if (decoder.isEnded()) {
muxerWrapper.endTrack(getTrackType()); muxerWrapper.endTrack(getTrackType());
muxerWrapperTrackEnded = true; muxerWrapperTrackEnded = true;
return false; return false;

View file

@ -268,6 +268,12 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
delegate.setVideoScalingMode(scalingMode); delegate.setVideoScalingMode(scalingMode);
} }
@RequiresApi(18)
@Override
public void signalEndOfInputStream() {
delegate.signalEndOfInputStream();
}
// Dumpable implementation // Dumpable implementation
@Override @Override