Transformer: Restrict frame buffer size for all omx decoders API >= 29.
PiperOrigin-RevId: 445119411
This commit is contained in:
parent
826039ad07
commit
0f3e63909c
@ -35,6 +35,8 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public interface Codec {
|
public interface Codec {
|
||||||
|
/** Default value for the pending frame count, which represents applying no limit. */
|
||||||
|
int UNLIMITED_PENDING_FRAME_COUNT = Integer.MAX_VALUE;
|
||||||
|
|
||||||
/** A factory for {@linkplain Codec decoder} instances. */
|
/** A factory for {@linkplain Codec decoder} instances. */
|
||||||
interface DecoderFactory {
|
interface DecoderFactory {
|
||||||
@ -139,6 +141,14 @@ public interface Codec {
|
|||||||
*/
|
*/
|
||||||
Surface getInputSurface();
|
Surface getInputSurface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of frames that may be pending in the output {@code Codec} at a time,
|
||||||
|
* or {@link #UNLIMITED_PENDING_FRAME_COUNT} if it's not necessary to enforce a limit.
|
||||||
|
*/
|
||||||
|
default int getMaxPendingFrameCount() {
|
||||||
|
return UNLIMITED_PENDING_FRAME_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dequeues a writable input buffer, if available.
|
* Dequeues a writable input buffer, if available.
|
||||||
*
|
*
|
||||||
|
@ -30,7 +30,9 @@ import androidx.media3.common.Format;
|
|||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.TraceUtil;
|
import androidx.media3.common.util.TraceUtil;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
|
import com.google.common.base.Ascii;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -120,6 +122,29 @@ public final class DefaultCodec implements Codec {
|
|||||||
return checkStateNotNull(inputSurface);
|
return checkStateNotNull(inputSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxPendingFrameCount() {
|
||||||
|
if (Util.SDK_INT < 29) {
|
||||||
|
// Prior to API 29, decoders may drop frames to keep their output surface from growing out of
|
||||||
|
// bounds. From API 29, the {@link MediaFormat#KEY_ALLOW_FRAME_DROP} key prevents frame
|
||||||
|
// dropping even when the surface is full. Frame dropping is never desired, so allow a maximum
|
||||||
|
// of one frame to be pending at a time.
|
||||||
|
// TODO(b/226330223): Investigate increasing this limit.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (Ascii.toUpperCase(mediaCodec.getCodecInfo().getCanonicalName()).startsWith("OMX.")) {
|
||||||
|
// Some OMX decoders don't correctly track their number of output buffers available, and get
|
||||||
|
// stuck if too many frames are rendered without being processed, so limit the number of
|
||||||
|
// pending frames to avoid getting stuck. This value is experimentally determined. See also
|
||||||
|
// b/213455700, b/230097284, and b/229978305,.
|
||||||
|
// TODO(b/230097284): Add a maximum API check after we know which APIs will never use OMX.
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
// Otherwise don't limit the number of frames that can be pending at a time, to maximize
|
||||||
|
// throughput.
|
||||||
|
return UNLIMITED_PENDING_FRAME_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@EnsuresNonNullIf(expression = "#1.data", result = true)
|
@EnsuresNonNullIf(expression = "#1.data", result = true)
|
||||||
public boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer)
|
public boolean maybeDequeueInputBuffer(DecoderInputBuffer inputBuffer)
|
||||||
|
@ -34,9 +34,6 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
* Pipeline to decode video samples, apply transformations on the raw samples, and re-encode them.
|
* Pipeline to decode video samples, apply transformations on the raw samples, and re-encode them.
|
||||||
*/
|
*/
|
||||||
/* package */ final class VideoTranscodingSamplePipeline implements SamplePipeline {
|
/* package */ final class VideoTranscodingSamplePipeline implements SamplePipeline {
|
||||||
|
|
||||||
private static final int FRAME_COUNT_UNLIMITED = -1;
|
|
||||||
|
|
||||||
private final int outputRotationDegrees;
|
private final int outputRotationDegrees;
|
||||||
private final DecoderInputBuffer decoderInputBuffer;
|
private final DecoderInputBuffer decoderInputBuffer;
|
||||||
private final Codec decoder;
|
private final Codec decoder;
|
||||||
@ -135,7 +132,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
inputFormat,
|
inputFormat,
|
||||||
frameProcessorChain.getInputSurface(),
|
frameProcessorChain.getInputSurface(),
|
||||||
transformationRequest.enableRequestSdrToneMapping);
|
transformationRequest.enableRequestSdrToneMapping);
|
||||||
maxPendingFrameCount = getMaxPendingFrameCount();
|
maxPendingFrameCount = decoder.getMaxPendingFrameCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -254,7 +251,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxPendingFrameCount != FRAME_COUNT_UNLIMITED
|
if (maxPendingFrameCount != Codec.UNLIMITED_PENDING_FRAME_COUNT
|
||||||
&& frameProcessorChain.getPendingFrameCount() == maxPendingFrameCount) {
|
&& frameProcessorChain.getPendingFrameCount() == maxPendingFrameCount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -263,31 +260,4 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
decoder.releaseOutputBuffer(/* render= */ true);
|
decoder.releaseOutputBuffer(/* render= */ true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum number of frames that may be pending in the output {@link
|
|
||||||
* FrameProcessorChain} at a time, or {@link #FRAME_COUNT_UNLIMITED} if it's not necessary to
|
|
||||||
* enforce a limit.
|
|
||||||
*/
|
|
||||||
private static int getMaxPendingFrameCount() {
|
|
||||||
if (Util.SDK_INT < 29) {
|
|
||||||
// Prior to API 29, decoders may drop frames to keep their output surface from growing out of
|
|
||||||
// bounds, while from API 29, the {@link MediaFormat#KEY_ALLOW_FRAME_DROP} key prevents frame
|
|
||||||
// dropping even when the surface is full. We never want frame dropping so allow a maximum of
|
|
||||||
// one frame to be pending at a time.
|
|
||||||
// TODO(b/226330223): Investigate increasing this limit.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (Util.SDK_INT < 33
|
|
||||||
&& ("OnePlus".equals(Util.MANUFACTURER) || "samsung".equals(Util.MANUFACTURER))) {
|
|
||||||
// Some OMX decoders don't correctly track their number of output buffers available, and get
|
|
||||||
// stuck if too many frames are rendered without being processed, so we limit the number of
|
|
||||||
// pending frames to avoid getting stuck. This value is experimentally determined. See also
|
|
||||||
// b/213455700.
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
// Otherwise don't limit the number of frames that can be pending at a time, to maximize
|
|
||||||
// throughput.
|
|
||||||
return FRAME_COUNT_UNLIMITED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user