mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Send decode-only Opus samples in bypass mode for seekPreRoll skip
As Opus decoders skip some bytes prior to playback during a seek, the renderer for bypass playback should send samples to the decoder even if they would be decode-only. #minor-release PiperOrigin-RevId: 574494666 (cherry picked from commit 00193e0304a5ea2c20012fabf77f82f29e218372)
This commit is contained in:
parent
fe60d0d7b4
commit
111ac63695
@ -2279,7 +2279,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
// Process any batched data.
|
// Process any batched data.
|
||||||
checkState(!outputStreamEnded);
|
checkState(!outputStreamEnded);
|
||||||
if (bypassBatchBuffer.hasSamples()) {
|
if (bypassBatchBuffer.hasSamples()) {
|
||||||
boolean isDecodeOnly = bypassBatchBuffer.getLastSampleTimeUs() < getLastResetPositionUs();
|
boolean isDecodeOnly =
|
||||||
|
bypassBatchBuffer.getLastSampleTimeUs() < getLastResetPositionUs()
|
||||||
|
&& (outputFormat == null
|
||||||
|
|| !Objects.equals(outputFormat.sampleMimeType, MimeTypes.AUDIO_OPUS));
|
||||||
if (processOutputBuffer(
|
if (processOutputBuffer(
|
||||||
positionUs,
|
positionUs,
|
||||||
elapsedRealtimeUs,
|
elapsedRealtimeUs,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.exoplayer.e2etest;
|
package androidx.media3.exoplayer.e2etest;
|
||||||
|
|
||||||
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED;
|
import static androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_REQUIRED;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -40,12 +40,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class OggOpusPlaybackTest {
|
public final class OggOpusPlaybackTest {
|
||||||
|
|
||||||
public static final String INPUT_FILE = "bear.opus";
|
public static final String INPUT_FILE = "bear.opus";
|
||||||
|
|
||||||
@ -53,25 +54,31 @@ public class OggOpusPlaybackTest {
|
|||||||
public ShadowMediaCodecConfig mediaCodecConfig =
|
public ShadowMediaCodecConfig mediaCodecConfig =
|
||||||
ShadowMediaCodecConfig.forAllSupportedMimeTypes();
|
ShadowMediaCodecConfig.forAllSupportedMimeTypes();
|
||||||
|
|
||||||
@Test
|
public FakeClock fakeClock;
|
||||||
public void checkOggOpusEncodings() throws Exception {
|
public OffloadRenderersFactory offloadRenderersFactory;
|
||||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
public DefaultTrackSelector trackSelector;
|
||||||
OffloadRenderersFactory offloadRenderersFactory =
|
|
||||||
new OffloadRenderersFactory(applicationContext);
|
@Before
|
||||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector(applicationContext);
|
public void setUp() {
|
||||||
|
fakeClock = new FakeClock(/* isAutoAdvancing= */ true);
|
||||||
|
offloadRenderersFactory =
|
||||||
|
new OffloadRenderersFactory(ApplicationProvider.getApplicationContext());
|
||||||
|
trackSelector = new DefaultTrackSelector(ApplicationProvider.getApplicationContext());
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
trackSelector
|
trackSelector
|
||||||
.buildUponParameters()
|
.buildUponParameters()
|
||||||
.setAudioOffloadPreferences(
|
.setAudioOffloadPreferences(
|
||||||
new AudioOffloadPreferences.Builder()
|
new AudioOffloadPreferences.Builder()
|
||||||
.setAudioOffloadMode(AUDIO_OFFLOAD_MODE_ENABLED)
|
.setAudioOffloadMode(AUDIO_OFFLOAD_MODE_REQUIRED)
|
||||||
.setIsGaplessSupportRequired(false)
|
|
||||||
.setIsSpeedChangeSupportRequired(false)
|
|
||||||
.build())
|
.build())
|
||||||
.build());
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void oggOpusPlayback_generatesCorrectOggOpusEncodings() throws Exception {
|
||||||
ExoPlayer player =
|
ExoPlayer player =
|
||||||
new ExoPlayer.Builder(applicationContext, offloadRenderersFactory)
|
new ExoPlayer.Builder(ApplicationProvider.getApplicationContext(), offloadRenderersFactory)
|
||||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
.setClock(fakeClock)
|
||||||
.setTrackSelector(trackSelector)
|
.setTrackSelector(trackSelector)
|
||||||
.build();
|
.build();
|
||||||
player.setMediaItem(MediaItem.fromUri("asset:///media/ogg/" + INPUT_FILE));
|
player.setMediaItem(MediaItem.fromUri("asset:///media/ogg/" + INPUT_FILE));
|
||||||
@ -82,12 +89,33 @@ public class OggOpusPlaybackTest {
|
|||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
applicationContext,
|
ApplicationProvider.getApplicationContext(),
|
||||||
offloadRenderersFactory,
|
offloadRenderersFactory,
|
||||||
"playbackdumps/ogg/" + INPUT_FILE + ".oggOpus.dump");
|
"playbackdumps/ogg/" + INPUT_FILE + ".oggOpus.dump");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class OffloadRenderersFactory extends DefaultRenderersFactory
|
@Test
|
||||||
|
public void oggOpusPlayback_withSeek_generatesCorrectOggOpusEncodings() throws Exception {
|
||||||
|
ExoPlayer player =
|
||||||
|
new ExoPlayer.Builder(ApplicationProvider.getApplicationContext(), offloadRenderersFactory)
|
||||||
|
.setClock(fakeClock)
|
||||||
|
.setTrackSelector(trackSelector)
|
||||||
|
.build();
|
||||||
|
player.setMediaItem(MediaItem.fromUri("asset:///media/ogg/" + INPUT_FILE));
|
||||||
|
player.prepare();
|
||||||
|
player.seekTo(/* positionMs= */ 1415);
|
||||||
|
player.play();
|
||||||
|
|
||||||
|
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
offloadRenderersFactory,
|
||||||
|
"playbackdumps/ogg/" + INPUT_FILE + ".oggOpusWithSeek.dump");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class OffloadRenderersFactory extends DefaultRenderersFactory
|
||||||
implements Dumper.Dumpable {
|
implements Dumper.Dumpable {
|
||||||
|
|
||||||
private DumpingAudioSink dumpingAudioSink;
|
private DumpingAudioSink dumpingAudioSink;
|
||||||
@ -117,7 +145,8 @@ public class OggOpusPlaybackTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DumpingAudioSink extends ForwardingAudioSink implements Dumper.Dumpable {
|
private static final class DumpingAudioSink extends ForwardingAudioSink
|
||||||
|
implements Dumper.Dumpable {
|
||||||
/** All handleBuffer interactions recorded with this audio sink. */
|
/** All handleBuffer interactions recorded with this audio sink. */
|
||||||
private final List<CapturedInputBuffer> capturedInteractions;
|
private final List<CapturedInputBuffer> capturedInteractions;
|
||||||
|
|
||||||
@ -174,14 +203,14 @@ public class OggOpusPlaybackTest {
|
|||||||
buffer.position(originalPosition);
|
buffer.position(originalPosition);
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Data record */
|
/** Data record */
|
||||||
private static class CapturedInputBuffer {
|
private static final class CapturedInputBuffer {
|
||||||
private final byte[] contents;
|
private final byte[] contents;
|
||||||
|
|
||||||
private CapturedInputBuffer(byte[] contents) {
|
private CapturedInputBuffer(byte[] contents) {
|
||||||
this.contents = contents;
|
this.contents = contents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
SinkDump (OggOpus):
|
||||||
|
buffers.length = 6
|
||||||
|
buffers[0] = length 207, hash D462AF66
|
||||||
|
buffers[1] = length 3891, hash FE9EE7C1
|
||||||
|
buffers[2] = length 3732, hash C2249BC1
|
||||||
|
buffers[3] = length 3731, hash A9384B0F
|
||||||
|
buffers[4] = length 4091, hash 9631FA86
|
||||||
|
buffers[5] = length 776, hash 4BC27E65
|
Loading…
x
Reference in New Issue
Block a user