Add Extractor.getUnderlyingImplementation

This change uses this new method everywhere we currently `instanceof`
check an `Extractor` directly. This allows us to introduce
wrapping/delegating `Extractor` instances - because the `instanceof`
checks will continue to operate on the underlying instance.

HLS is a slightly different case, because it directly re-instantiates
`Extractor` instances, which is not compatible with an arbitrary
wrapping structure. Luckily the only `Extractor` instances that HLS
re-instantiates do not support muxed subtitles, so won't be wrapped
in the first place (although future changes might use the
delegating-`Extractor` pattern for other purposes, which might affect
HLS).

PiperOrigin-RevId: 542550928
This commit is contained in:
ibaker 2023-06-22 14:17:47 +00:00 committed by Tofunmi Adigun-Hameed
parent 7e475146dd
commit bc06039f7f
4 changed files with 35 additions and 9 deletions

View File

@ -40,6 +40,10 @@
* Fix typo when determining `rotationDegrees`. Changed
`projectionPosePitch` to `projectionPoseRoll`
([#461](https://github.com/androidx/media/pull/461)).
* Remove the assumption that `Extractor` instances can be directly
inspected with `instanceof`. If you want runtime access to the
implementation details of an `Extractor` you must first call
`Extractor.getUnderlyingInstance`.
* Audio:
* Audio Offload:
* Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of

View File

@ -108,8 +108,12 @@ public final class BundledExtractorsAdapter implements ProgressiveMediaExtractor
@Override
public void disableSeekingOnMp3Streams() {
if (extractor instanceof Mp3Extractor) {
((Mp3Extractor) extractor).disableSeeking();
if (extractor == null) {
return;
}
Extractor underlyingExtractor = extractor.getUnderlyingImplementation();
if (underlyingExtractor instanceof Mp3Extractor) {
((Mp3Extractor) underlyingExtractor).disableSeeking();
}
}

View File

@ -15,9 +15,10 @@
*/
package androidx.media3.exoplayer.hls;
import static androidx.media3.common.util.Assertions.checkState;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.Format;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.TimestampAdjuster;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.extractor.Extractor;
@ -71,20 +72,26 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract
@Override
public boolean isPackedAudioExtractor() {
return extractor instanceof AdtsExtractor
|| extractor instanceof Ac3Extractor
|| extractor instanceof Ac4Extractor
|| extractor instanceof Mp3Extractor;
Extractor underlyingExtractor = extractor.getUnderlyingImplementation();
return underlyingExtractor instanceof AdtsExtractor
|| underlyingExtractor instanceof Ac3Extractor
|| underlyingExtractor instanceof Ac4Extractor
|| underlyingExtractor instanceof Mp3Extractor;
}
@Override
public boolean isReusable() {
return extractor instanceof TsExtractor || extractor instanceof FragmentedMp4Extractor;
Extractor underlyingExtractor = extractor.getUnderlyingImplementation();
return underlyingExtractor instanceof TsExtractor
|| underlyingExtractor instanceof FragmentedMp4Extractor;
}
@Override
public HlsMediaChunkExtractor recreate() {
Assertions.checkState(!isReusable());
checkState(!isReusable());
checkState(
extractor.getUnderlyingImplementation() == extractor,
"Can't recreate wrapped extractors. Outer type: " + extractor.getClass());
Extractor newExtractorInstance;
if (extractor instanceof WebvttExtractor) {
newExtractorInstance =

View File

@ -120,4 +120,15 @@ public interface Extractor {
/** Releases all kept resources. */
void release();
/**
* Returns the 'real' {@code Extractor} implementation if this is a delegating instance, or {@code
* this} if this instance does the extraction directly without delegating (the default behaviour).
*
* <p>{@code Extractor} implementations that operate by delegating to another {@code Extractor}
* should override this method to return that delegate.
*/
default Extractor getUnderlyingImplementation() {
return this;
}
}