mirror of
https://github.com/androidx/media.git
synced 2025-05-11 09:39:52 +08:00
Simplify output buffer handling in transformer
We can dequeue as part of getting output buffers (or output buffer info) in `MediaCodecAdapterWrapper`, which simplifies the caller slightly. Also try to make minor clarifications in method naming in `TransformerAudioRenderer`. #minor-release PiperOrigin-RevId: 354890796
This commit is contained in:
parent
50344e2703
commit
17ca191fb5
@ -182,66 +182,24 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
inputBuffer.data = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues an output buffer, if available.
|
||||
*
|
||||
* <p>Once this method returns {@code true}, call {@link #getOutputBuffer()} to access the
|
||||
* dequeued buffer.
|
||||
*
|
||||
* @return Whether an output buffer is available.
|
||||
*/
|
||||
public boolean maybeDequeueOutputBuffer() {
|
||||
if (outputBufferIndex >= 0) {
|
||||
return true;
|
||||
}
|
||||
if (outputStreamEnded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outputBufferIndex = codec.dequeueOutputBufferIndex(outputBufferInfo);
|
||||
if (outputBufferIndex < 0) {
|
||||
if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
outputFormat = getFormat(codec.getOutputFormat());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
outputStreamEnded = true;
|
||||
if (outputBufferInfo.size == 0) {
|
||||
releaseOutputBuffer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
||||
// Encountered a CSD buffer, skip it.
|
||||
releaseOutputBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
outputBuffer = checkNotNull(codec.getOutputBuffer(outputBufferIndex));
|
||||
outputBuffer.position(outputBufferInfo.offset);
|
||||
outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the current output format, if available. */
|
||||
@Nullable
|
||||
public Format getOutputFormat() {
|
||||
// The format is updated when dequeueing a 'special' buffer index, so attempt to dequeue now.
|
||||
maybeDequeueOutputBuffer();
|
||||
return outputFormat;
|
||||
}
|
||||
|
||||
/** Returns the current output {@link ByteBuffer}, if available. */
|
||||
@Nullable
|
||||
public ByteBuffer getOutputBuffer() {
|
||||
return outputBuffer;
|
||||
return maybeDequeueOutputBuffer() ? outputBuffer : null;
|
||||
}
|
||||
|
||||
/** Returns the {@link BufferInfo} associated with the current output buffer, if available. */
|
||||
@Nullable
|
||||
public BufferInfo getOutputBufferInfo() {
|
||||
return outputBuffer == null ? null : outputBufferInfo;
|
||||
return maybeDequeueOutputBuffer() ? outputBufferInfo : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -267,6 +225,45 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
codec.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is already an output buffer pending. Otherwise attempts to dequeue an
|
||||
* output buffer and returns whether there is a new output buffer.
|
||||
*/
|
||||
private boolean maybeDequeueOutputBuffer() {
|
||||
if (outputBufferIndex >= 0) {
|
||||
return true;
|
||||
}
|
||||
if (outputStreamEnded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outputBufferIndex = codec.dequeueOutputBufferIndex(outputBufferInfo);
|
||||
if (outputBufferIndex < 0) {
|
||||
if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
outputFormat = getFormat(codec.getOutputFormat());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
outputStreamEnded = true;
|
||||
if (outputBufferInfo.size == 0) {
|
||||
releaseOutputBuffer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
||||
// Encountered a CSD buffer, skip it.
|
||||
releaseOutputBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
outputBuffer = checkNotNull(codec.getOutputBuffer(outputBufferIndex));
|
||||
outputBuffer.position(outputBufferInfo.offset);
|
||||
outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Format getFormat(MediaFormat mediaFormat) {
|
||||
ImmutableList.Builder<byte[]> csdBuffers = new ImmutableList.Builder<>();
|
||||
int csdIndex = 0;
|
||||
|
@ -114,11 +114,8 @@ import java.nio.ByteBuffer;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!setupDecoder()) {
|
||||
return;
|
||||
}
|
||||
setupEncoderAndMaybeSonic();
|
||||
|
||||
if (ensureDecoderConfigured()) {
|
||||
if (ensureEncoderAndAudioProcessingConfigured()) {
|
||||
while (drainEncoderToFeedMuxer()) {}
|
||||
if (sonicAudioProcessor.isActive()) {
|
||||
while (drainSonicToFeedEncoder()) {}
|
||||
@ -126,8 +123,10 @@ import java.nio.ByteBuffer;
|
||||
} else {
|
||||
while (drainDecoderToFeedEncoder()) {}
|
||||
}
|
||||
}
|
||||
while (feedDecoderInputFromSource()) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to write encoder output data to the muxer, and returns whether it may be possible to
|
||||
@ -136,8 +135,6 @@ import java.nio.ByteBuffer;
|
||||
private boolean drainEncoderToFeedMuxer() {
|
||||
MediaCodecAdapterWrapper encoder = checkNotNull(this.encoder);
|
||||
if (!hasEncoderOutputFormat) {
|
||||
// Dequeue output format change.
|
||||
encoder.maybeDequeueOutputBuffer();
|
||||
@Nullable Format encoderOutputFormat = encoder.getOutputFormat();
|
||||
if (encoderOutputFormat == null) {
|
||||
return false;
|
||||
@ -147,19 +144,15 @@ import java.nio.ByteBuffer;
|
||||
}
|
||||
|
||||
if (encoder.isEnded()) {
|
||||
// Encoder output stream ended and output is empty or null so end muxer track.
|
||||
muxerWrapper.endTrack(getTrackType());
|
||||
muxerWrapperTrackEnded = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!encoder.maybeDequeueOutputBuffer()) {
|
||||
@Nullable ByteBuffer encoderOutputBuffer = encoder.getOutputBuffer();
|
||||
if (encoderOutputBuffer == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteBuffer encoderOutputBuffer = checkNotNull(encoder.getOutputBuffer());
|
||||
BufferInfo encoderOutputBufferInfo = checkNotNull(encoder.getOutputBufferInfo());
|
||||
|
||||
if (!muxerWrapper.writeSample(
|
||||
getTrackType(),
|
||||
encoderOutputBuffer,
|
||||
@ -187,19 +180,15 @@ import java.nio.ByteBuffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!decoder.maybeDequeueOutputBuffer()) {
|
||||
@Nullable ByteBuffer decoderOutputBuffer = decoder.getOutputBuffer();
|
||||
if (decoderOutputBuffer == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSpeedChanging(checkNotNull(decoder.getOutputBufferInfo()))) {
|
||||
flushSonicAndSetSpeed(currentSpeed);
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteBuffer decoderOutputBuffer = checkNotNull(decoder.getOutputBuffer());
|
||||
|
||||
feedEncoder(decoderOutputBuffer);
|
||||
|
||||
if (!decoderOutputBuffer.hasRemaining()) {
|
||||
decoder.releaseOutputBuffer();
|
||||
}
|
||||
@ -246,8 +235,8 @@ import java.nio.ByteBuffer;
|
||||
drainingSonicForSpeedChange = false;
|
||||
}
|
||||
|
||||
// Sonic invalidates the output buffer when more input is queued, so we don't queue if there is
|
||||
// output still to be processed.
|
||||
// Sonic invalidates any previous output buffer when more input is queued, so we don't queue if
|
||||
// there is output still to be processed.
|
||||
if (sonicOutputBuffer.hasRemaining()) {
|
||||
return false;
|
||||
}
|
||||
@ -256,20 +245,17 @@ import java.nio.ByteBuffer;
|
||||
sonicAudioProcessor.queueEndOfStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
checkState(!sonicAudioProcessor.isEnded());
|
||||
|
||||
if (!decoder.maybeDequeueOutputBuffer()) {
|
||||
@Nullable ByteBuffer decoderOutputBuffer = decoder.getOutputBuffer();
|
||||
if (decoderOutputBuffer == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSpeedChanging(checkNotNull(decoder.getOutputBufferInfo()))) {
|
||||
sonicAudioProcessor.queueEndOfStream();
|
||||
drainingSonicForSpeedChange = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteBuffer decoderOutputBuffer = checkNotNull(decoder.getOutputBuffer());
|
||||
sonicAudioProcessor.queueInput(decoderOutputBuffer);
|
||||
if (!decoderOutputBuffer.hasRemaining()) {
|
||||
decoder.releaseOutputBuffer();
|
||||
@ -337,18 +323,23 @@ import java.nio.ByteBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link #encoder} and Sonic (if applicable), if they have not been configured
|
||||
* yet.
|
||||
* Attempts to configure the {@link #encoder} and Sonic (if applicable), if they have not been
|
||||
* configured yet, and returns whether they have been configured.
|
||||
*/
|
||||
private void setupEncoderAndMaybeSonic() throws ExoPlaybackException {
|
||||
private boolean ensureEncoderAndAudioProcessingConfigured() throws ExoPlaybackException {
|
||||
if (encoder != null) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
MediaCodecAdapterWrapper decoder = checkNotNull(this.decoder);
|
||||
@Nullable Format decoderOutputFormat = decoder.getOutputFormat();
|
||||
if (decoderOutputFormat == null) {
|
||||
return false;
|
||||
}
|
||||
// TODO(b/161127201): Use the decoder output format once the decoder is fed before setting up
|
||||
// the encoder.
|
||||
AudioFormat outputAudioFormat =
|
||||
new AudioFormat(
|
||||
checkNotNull(inputFormat).sampleRate, inputFormat.channelCount, C.ENCODING_PCM_16BIT);
|
||||
decoderOutputFormat.sampleRate,
|
||||
decoderOutputFormat.channelCount,
|
||||
decoderOutputFormat.pcmEncoding);
|
||||
if (transformation.flattenForSlowMotion) {
|
||||
try {
|
||||
outputAudioFormat = sonicAudioProcessor.configure(outputAudioFormat);
|
||||
@ -370,13 +361,14 @@ import java.nio.ByteBuffer;
|
||||
throw createRendererException(e);
|
||||
}
|
||||
encoderInputAudioFormat = outputAudioFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to configure the {@link #decoder} if it has not been configured yet, and returns
|
||||
* whether the decoder has been configured.
|
||||
*/
|
||||
private boolean setupDecoder() throws ExoPlaybackException {
|
||||
private boolean ensureDecoderConfigured() throws ExoPlaybackException {
|
||||
if (decoder != null) {
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user