Explicitly mark DecoderOutputBuffer as shouldBeSkipped if needed
In some cases, SimpleDecoder output needs to be skipped for rendering because the decoder produces no data. This is one of the remaining usages of BUFFER_FLAG_DECODE_ONLY at the moment and can be more directly solved without using the flag. SimpleDecoder still needs to check the flag though for backwards compatbility with custom decoders while the flag is not completely removed. PiperOrigin-RevId: 570345233
This commit is contained in:
parent
1bb501ab50
commit
c8aac24ffd
@ -29,6 +29,9 @@
|
||||
* Smooth Streaming Extension:
|
||||
* RTSP Extension:
|
||||
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
|
||||
* Add `DecoderOutputBuffer.shouldBeSkipped` to directly mark output
|
||||
buffers that don't need to be presented. This is preferred over
|
||||
`C.BUFFER_FLAG_DECODE_ONLY`.
|
||||
* MIDI extension:
|
||||
* Leanback extension:
|
||||
* Cast Extension:
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package androidx.media3.decoder;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
@ -25,6 +26,7 @@ public abstract class Buffer {
|
||||
private @C.BufferFlags int flags;
|
||||
|
||||
/** Clears the buffer. */
|
||||
@CallSuper
|
||||
public void clear() {
|
||||
flags = 0;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package androidx.media3.decoder;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
/** Output buffer decoded by a {@link Decoder}. */
|
||||
@ -40,6 +41,21 @@ public abstract class DecoderOutputBuffer extends Buffer {
|
||||
*/
|
||||
public int skippedOutputBufferCount;
|
||||
|
||||
/**
|
||||
* Whether this buffer should be skipped, usually because the decoding process generated no data
|
||||
* or invalid data.
|
||||
*/
|
||||
public boolean shouldBeSkipped;
|
||||
|
||||
/** Releases the output buffer for reuse. Must be called when the buffer is no longer needed. */
|
||||
public abstract void release();
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void clear() {
|
||||
super.clear();
|
||||
timeUs = 0;
|
||||
skippedOutputBufferCount = 0;
|
||||
shouldBeSkipped = false;
|
||||
}
|
||||
}
|
||||
|
@ -232,6 +232,7 @@ public abstract class SimpleDecoder<
|
||||
if (inputBuffer.isEndOfStream()) {
|
||||
outputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
} else {
|
||||
outputBuffer.timeUs = inputBuffer.timeUs;
|
||||
if (inputBuffer.isDecodeOnly()) {
|
||||
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
}
|
||||
@ -262,7 +263,7 @@ public abstract class SimpleDecoder<
|
||||
synchronized (lock) {
|
||||
if (flushed) {
|
||||
outputBuffer.release();
|
||||
} else if (outputBuffer.isDecodeOnly()) {
|
||||
} else if (outputBuffer.isDecodeOnly() || outputBuffer.shouldBeSkipped) {
|
||||
skippedOutputBufferCount++;
|
||||
outputBuffer.release();
|
||||
} else {
|
||||
|
@ -117,7 +117,7 @@ public final class Gav1Decoder
|
||||
"gav1GetFrame error: " + gav1GetErrorMessage(gav1DecoderContext));
|
||||
}
|
||||
if (getFrameResult == GAV1_DECODE_ONLY) {
|
||||
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
}
|
||||
if (!decodeOnly) {
|
||||
outputBuffer.format = inputBuffer.format;
|
||||
@ -139,9 +139,9 @@ public final class Gav1Decoder
|
||||
|
||||
@Override
|
||||
protected void releaseOutputBuffer(VideoDecoderOutputBuffer outputBuffer) {
|
||||
// Decode only frames do not acquire a reference on the internal decoder buffer and thus do not
|
||||
// Skipped frames do not acquire a reference on the internal decoder buffer and thus do not
|
||||
// require a call to gav1ReleaseFrame.
|
||||
if (outputBuffer.mode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV && !outputBuffer.isDecodeOnly()) {
|
||||
if (outputBuffer.mode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV && !outputBuffer.shouldBeSkipped) {
|
||||
gav1ReleaseFrame(gav1DecoderContext, outputBuffer);
|
||||
}
|
||||
super.releaseOutputBuffer(outputBuffer);
|
||||
|
@ -113,13 +113,13 @@ import java.util.List;
|
||||
return new FfmpegDecoderException("Error decoding (see logcat).");
|
||||
} else if (result == AUDIO_DECODER_ERROR_INVALID_DATA) {
|
||||
// Treat invalid data errors as non-fatal to match the behavior of MediaCodec. No output will
|
||||
// be produced for this buffer, so mark it as decode-only to ensure that the audio sink's
|
||||
// be produced for this buffer, so mark it as skipped to ensure that the audio sink's
|
||||
// position is reset when more audio is produced.
|
||||
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
return null;
|
||||
} else if (result == 0) {
|
||||
// There's no need to output empty buffers.
|
||||
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
return null;
|
||||
}
|
||||
if (!hasOutputFormat) {
|
||||
|
@ -229,7 +229,7 @@ public final class OpusDecoder
|
||||
int skipBytes = skipSamples * bytesPerSample;
|
||||
if (result <= skipBytes) {
|
||||
skipSamples -= result / bytesPerSample;
|
||||
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
outputData.position(result);
|
||||
} else {
|
||||
skipSamples = 0;
|
||||
|
@ -102,9 +102,9 @@ public final class VpxDecoder
|
||||
|
||||
@Override
|
||||
protected void releaseOutputBuffer(VideoDecoderOutputBuffer outputBuffer) {
|
||||
// Decode only frames do not acquire a reference on the internal decoder buffer and thus do not
|
||||
// Skipped frames do not acquire a reference on the internal decoder buffer and thus do not
|
||||
// require a call to vpxReleaseFrame.
|
||||
if (outputMode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV && !outputBuffer.isDecodeOnly()) {
|
||||
if (outputMode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV && !outputBuffer.shouldBeSkipped) {
|
||||
vpxReleaseFrame(vpxDecContext, outputBuffer);
|
||||
}
|
||||
super.releaseOutputBuffer(outputBuffer);
|
||||
@ -169,11 +169,13 @@ public final class VpxDecoder
|
||||
outputBuffer.init(inputBuffer.timeUs, outputMode, lastSupplementalData);
|
||||
int getFrameResult = vpxGetFrame(vpxDecContext, outputBuffer);
|
||||
if (getFrameResult == 1) {
|
||||
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
} else if (getFrameResult == -1) {
|
||||
return new VpxDecoderException("Buffer initialization failed.");
|
||||
}
|
||||
outputBuffer.format = inputBuffer.format;
|
||||
} else {
|
||||
outputBuffer.shouldBeSkipped = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user