mirror of
https://github.com/samsonjs/media.git
synced 2026-04-19 13:35:47 +00:00
Update bypass decode-only logic to timestamp-based pattern
This aligns the bypass code with the MediaCodec logic to not use buffer.isDecodeOnly and instead rely on a timestamp comparison with the last reset time. Overall, the change should not introduce a functional difference and is covered by existing end-to-end tests with bypass playbacks. Splitting bypass batch buffers by decoder-only flag is technically wrong for formats where not every buffer is a keyframe, and this change also leaves a TODO to explain this known shortcoming. PiperOrigin-RevId: 556800038
This commit is contained in:
parent
a48b99214e
commit
3ccb920930
3 changed files with 17 additions and 51 deletions
|
|
@ -105,9 +105,6 @@ import java.nio.ByteBuffer;
|
|||
setFlags(C.BUFFER_FLAG_KEY_FRAME);
|
||||
}
|
||||
}
|
||||
if (buffer.isDecodeOnly()) {
|
||||
setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
}
|
||||
@Nullable ByteBuffer bufferData = buffer.data;
|
||||
if (bufferData != null) {
|
||||
ensureSpaceForWrite(bufferData.remaining());
|
||||
|
|
@ -125,9 +122,6 @@ import java.nio.ByteBuffer;
|
|||
if (sampleCount >= maxSampleCount) {
|
||||
return false;
|
||||
}
|
||||
if (buffer.isDecodeOnly() != isDecodeOnly()) {
|
||||
return false;
|
||||
}
|
||||
@Nullable ByteBuffer bufferData = buffer.data;
|
||||
if (bufferData != null
|
||||
&& data != null
|
||||
|
|
|
|||
|
|
@ -2252,6 +2252,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
// Process any batched data.
|
||||
checkState(!outputStreamEnded);
|
||||
if (bypassBatchBuffer.hasSamples()) {
|
||||
boolean isDecodeOnly = bypassBatchBuffer.getLastSampleTimeUs() < getLastResetPositionUs();
|
||||
if (processOutputBuffer(
|
||||
positionUs,
|
||||
elapsedRealtimeUs,
|
||||
|
|
@ -2261,7 +2262,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
/* bufferFlags= */ 0,
|
||||
bypassBatchBuffer.getSampleCount(),
|
||||
bypassBatchBuffer.getFirstSampleTimeUs(),
|
||||
bypassBatchBuffer.isDecodeOnly(),
|
||||
isDecodeOnly,
|
||||
bypassBatchBuffer.isEndOfStream(),
|
||||
outputFormat)) {
|
||||
// The batch buffer has been fully processed.
|
||||
|
|
@ -2344,7 +2345,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
&& inputFormat.sampleMimeType.equals(MimeTypes.AUDIO_OPUS)) {
|
||||
oggOpusAudioPacketizer.packetize(bypassSampleBuffer, inputFormat.initializationData);
|
||||
}
|
||||
if (!bypassBatchBuffer.append(bypassSampleBuffer)) {
|
||||
if (!haveBypassBatchBufferAndNewSampleSameDecodeOnlyState()
|
||||
|| !bypassBatchBuffer.append(bypassSampleBuffer)) {
|
||||
bypassSampleBufferPending = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -2355,6 +2357,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean haveBypassBatchBufferAndNewSampleSameDecodeOnlyState() {
|
||||
// TODO: b/295800114 - Splitting the batch buffer by decode-only state isn't safe for formats
|
||||
// where not every sample is a keyframe because the downstream component may receive encoded
|
||||
// data starting from a non-keyframe sample.
|
||||
if (!bypassBatchBuffer.hasSamples()) {
|
||||
return true;
|
||||
}
|
||||
long lastResetPositionUs = getLastResetPositionUs();
|
||||
boolean batchBufferIsDecodeOnly = bypassBatchBuffer.getLastSampleTimeUs() < lastResetPositionUs;
|
||||
boolean sampleBufferIsDecodeOnly = bypassSampleBuffer.timeUs < lastResetPositionUs;
|
||||
return batchBufferIsDecodeOnly == sampleBufferIsDecodeOnly;
|
||||
}
|
||||
|
||||
private static boolean isMediaCodecException(IllegalStateException error) {
|
||||
if (Util.SDK_INT >= 21 && isMediaCodecExceptionV21(error)) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -104,49 +104,6 @@ public final class BatchBufferTest {
|
|||
assertThat(batchBuffer.getLastSampleTimeUs()).isEqualTo(customMaxSampleCount - 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendFirstSample_withDecodeOnlyFlag_setsDecodeOnlyFlag() {
|
||||
initSampleBuffer();
|
||||
sampleBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
batchBuffer.append(sampleBuffer);
|
||||
|
||||
assertThat(batchBuffer.isDecodeOnly()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendSecondSample_toDecodeOnlyBuffer_withDecodeOnlyFlag_succeeds() {
|
||||
initSampleBuffer();
|
||||
sampleBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
batchBuffer.append(sampleBuffer);
|
||||
|
||||
initSampleBuffer();
|
||||
sampleBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
|
||||
assertThat(batchBuffer.append(sampleBuffer)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendSecondSample_toDecodeOnlyBuffer_withoutDecodeOnlyFlag_fails() {
|
||||
initSampleBuffer();
|
||||
sampleBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
batchBuffer.append(sampleBuffer);
|
||||
|
||||
initSampleBuffer();
|
||||
|
||||
assertThat(batchBuffer.append(sampleBuffer)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendSecondSample_toNonDecodeOnlyBuffer_withDecodeOnlyFlag_fails() {
|
||||
initSampleBuffer();
|
||||
batchBuffer.append(sampleBuffer);
|
||||
|
||||
initSampleBuffer();
|
||||
sampleBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
|
||||
|
||||
assertThat(batchBuffer.append(sampleBuffer)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendSecondSample_withKeyframeFlag_setsKeyframeFlag() {
|
||||
initSampleBuffer();
|
||||
|
|
|
|||
Loading…
Reference in a new issue