Skip to content

Commit

Permalink
Explicitly mark DecoderOutputBuffer as shouldBeSkipped if needed
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tonihei authored and copybara-github committed Oct 3, 2023
1 parent 1bb501a commit c8aac24
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 11 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package androidx.media3.decoder;

import androidx.annotation.CallSuper;
import androidx.media3.common.C;
import androidx.media3.common.util.UnstableApi;

Expand All @@ -25,6 +26,7 @@ public abstract class Buffer {
private @C.BufferFlags int flags;

/** Clears the buffer. */
@CallSuper
public void clear() {
flags = 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}. */
Expand All @@ -40,6 +41,21 @@ public interface Owner<S extends DecoderOutputBuffer> {
*/
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ private boolean decode() throws InterruptedException {
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);
}
Expand Down Expand Up @@ -262,7 +263,7 @@ private boolean decode() throws InterruptedException {
synchronized (lock) {
if (flushed) {
outputBuffer.release();
} else if (outputBuffer.isDecodeOnly()) {
} else if (outputBuffer.isDecodeOnly() || outputBuffer.shouldBeSkipped) {
skippedOutputBufferCount++;
outputBuffer.release();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected Gav1DecoderException decode(
"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;
Expand All @@ -139,9 +139,9 @@ public void release() {

@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ protected FfmpegDecoderException decode(
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ protected OpusDecoderException decode(
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ protected VideoDecoderOutputBuffer createOutputBuffer() {

@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);
Expand Down Expand Up @@ -169,11 +169,13 @@ protected VpxDecoderException decode(
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;
}
Expand Down

0 comments on commit c8aac24

Please sign in to comment.