Skip to content

Commit bc3f515

Browse files
committed
Do not flush eac3(joc) and ac4 decoders on reuse
eac3(joc) and ac4 decoders do not need to be flushed to be reused for the next compatible track or across adapative bitrate transitions. This change allows for gapless playback on devices with Dolby decoders that require internal re-initialization on flush.
1 parent a80f551 commit bc3f515

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfo.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,18 @@ public DecoderReuseEvaluation canReuseCodec(Format oldFormat, Format newFormat)
516516
}
517517
}
518518

519+
// For eac3, eac3-joc and ac4 formats, adaptation is possible without reconfiguration or
520+
// flushing.
521+
if (discardReasons == 0 && (MimeTypes.AUDIO_E_AC3_JOC.equals(mimeType)
522+
|| MimeTypes.AUDIO_E_AC3.equals(mimeType) || MimeTypes.AUDIO_AC4.equals(mimeType))) {
523+
return new DecoderReuseEvaluation(
524+
name,
525+
oldFormat,
526+
newFormat,
527+
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION,
528+
/* discardReasons= */ 0);
529+
}
530+
519531
if (!oldFormat.initializationDataEquals(newFormat)) {
520532
discardReasons |= DISCARD_REASON_INITIALIZATION_DATA_CHANGED;
521533
}

libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecInfoTest.java

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
package androidx.media3.exoplayer.mediacodec;
1717

1818
import static androidx.media3.common.MimeTypes.AUDIO_AAC;
19+
import static androidx.media3.common.MimeTypes.AUDIO_AC4;
20+
import static androidx.media3.common.MimeTypes.AUDIO_E_AC3;
21+
import static androidx.media3.common.MimeTypes.AUDIO_E_AC3_JOC;
1922
import static androidx.media3.common.MimeTypes.VIDEO_AV1;
2023
import static androidx.media3.common.MimeTypes.VIDEO_H264;
2124
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED;
@@ -74,6 +77,33 @@ public final class MediaCodecInfoTest {
7477
.setInitializationData(ImmutableList.of(new byte[] {4, 4, 1, 0, 0}))
7578
.build();
7679

80+
private static final Format FORMAT_EAC3 =
81+
new Format.Builder()
82+
.setSampleMimeType(AUDIO_E_AC3)
83+
.setChannelCount(6)
84+
.setSampleRate(48000)
85+
.setAverageBitrate(5000)
86+
.setInitializationData(ImmutableList.of(new byte[] {4, 4, 1, 0, 0}))
87+
.build();
88+
89+
private static final Format FORMAT_EAC3JOC =
90+
new Format.Builder()
91+
.setSampleMimeType(AUDIO_E_AC3_JOC)
92+
.setChannelCount(12)
93+
.setSampleRate(48000)
94+
.setAverageBitrate(5000)
95+
.setInitializationData(ImmutableList.of(new byte[] {4, 4, 1, 0, 0}))
96+
.build();
97+
98+
private static final Format FORMAT_AC4 =
99+
new Format.Builder()
100+
.setSampleMimeType(AUDIO_AC4)
101+
.setChannelCount(21)
102+
.setSampleRate(48000)
103+
.setAverageBitrate(5000)
104+
.setInitializationData(ImmutableList.of(new byte[] {4, 4, 1, 0, 0}))
105+
.build();
106+
77107
@Test
78108
public void canReuseCodec_withDifferentMimeType_returnsNo() {
79109
MediaCodecInfo codecInfo = buildH264CodecInfo(/* adaptive= */ true);
@@ -318,6 +348,63 @@ public void canReuseCodec_differentVideoCrop_returnsNo() {
318348
DISCARD_REASON_WORKAROUND));
319349
}
320350

351+
@Test
352+
public void canReuseCodec_eac3_returnsYesWithoutReconfiguration() {
353+
MediaCodecInfo codecInfo = buildEac3CodecInfo();
354+
355+
Format variantFormat =
356+
FORMAT_EAC3
357+
.buildUpon()
358+
.setInitializationData(ImmutableList.of(new byte[] {0}))
359+
.build();
360+
assertThat(codecInfo.canReuseCodec(FORMAT_EAC3, variantFormat))
361+
.isEqualTo(
362+
new DecoderReuseEvaluation(
363+
codecInfo.name,
364+
FORMAT_EAC3,
365+
variantFormat,
366+
DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION,
367+
/* discardReasons= */ 0));
368+
}
369+
370+
@Test
371+
public void canReuseCodec_eac3joc_returnsYesWithoutReconfiguration() {
372+
MediaCodecInfo codecInfo = buildEac3JocCodecInfo();
373+
374+
Format variantFormat =
375+
FORMAT_EAC3JOC
376+
.buildUpon()
377+
.setInitializationData(ImmutableList.of(new byte[] {0}))
378+
.build();
379+
assertThat(codecInfo.canReuseCodec(FORMAT_EAC3JOC, variantFormat))
380+
.isEqualTo(
381+
new DecoderReuseEvaluation(
382+
codecInfo.name,
383+
FORMAT_EAC3JOC,
384+
variantFormat,
385+
DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION,
386+
/* discardReasons= */ 0));
387+
}
388+
389+
@Test
390+
public void canReuseCodec_ac4_returnsYesWithoutReconfiguration() {
391+
MediaCodecInfo codecInfo = buildAc4CodecInfo();
392+
393+
Format variantFormat =
394+
FORMAT_AC4
395+
.buildUpon()
396+
.setInitializationData(ImmutableList.of(new byte[] {0}))
397+
.build();
398+
assertThat(codecInfo.canReuseCodec(FORMAT_AC4, variantFormat))
399+
.isEqualTo(
400+
new DecoderReuseEvaluation(
401+
codecInfo.name,
402+
FORMAT_AC4,
403+
variantFormat,
404+
DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION,
405+
/* discardReasons= */ 0));
406+
}
407+
321408
private static MediaCodecInfo buildH264CodecInfo(boolean adaptive) {
322409
return new MediaCodecInfo(
323410
"h264",
@@ -348,6 +435,51 @@ private static MediaCodecInfo buildAacCodecInfo() {
348435
/* detachedSurfaceSupported= */ false);
349436
}
350437

438+
private static MediaCodecInfo buildEac3CodecInfo() {
439+
return new MediaCodecInfo(
440+
"eac3joc",
441+
AUDIO_E_AC3,
442+
AUDIO_E_AC3,
443+
/* capabilities= */ null,
444+
/* hardwareAccelerated= */ false,
445+
/* softwareOnly= */ true,
446+
/* vendor= */ true,
447+
/* adaptive= */ false,
448+
/* tunneling= */ false,
449+
/* secure= */ false,
450+
/* detachedSurfaceSupported= */ false);
451+
}
452+
453+
private static MediaCodecInfo buildEac3JocCodecInfo() {
454+
return new MediaCodecInfo(
455+
"eac3joc",
456+
AUDIO_E_AC3_JOC,
457+
AUDIO_E_AC3_JOC,
458+
/* capabilities= */ null,
459+
/* hardwareAccelerated= */ false,
460+
/* softwareOnly= */ true,
461+
/* vendor= */ true,
462+
/* adaptive= */ false,
463+
/* tunneling= */ false,
464+
/* secure= */ false,
465+
/* detachedSurfaceSupported= */ false);
466+
}
467+
468+
private static MediaCodecInfo buildAc4CodecInfo() {
469+
return new MediaCodecInfo(
470+
"ac4",
471+
AUDIO_AC4,
472+
AUDIO_AC4,
473+
/* capabilities= */ null,
474+
/* hardwareAccelerated= */ false,
475+
/* softwareOnly= */ true,
476+
/* vendor= */ true,
477+
/* adaptive= */ false,
478+
/* tunneling= */ false,
479+
/* secure= */ false,
480+
/* detachedSurfaceSupported= */ false);
481+
}
482+
351483
private static ColorInfo buildHdrColorInfo(@C.ColorSpace int colorSpace) {
352484
return new ColorInfo.Builder()
353485
.setColorSpace(colorSpace)

0 commit comments

Comments
 (0)