Commit 9d5fd4f4 by christosts Committed by Ian Baker

DefaultExtractorsFactory: lazily load flac extension

PiperOrigin-RevId: 406332026
parent 80c5e00b
...@@ -19,6 +19,7 @@ import static androidx.media3.common.FileTypes.inferFileTypeFromResponseHeaders; ...@@ -19,6 +19,7 @@ import static androidx.media3.common.FileTypes.inferFileTypeFromResponseHeaders;
import static androidx.media3.common.FileTypes.inferFileTypeFromUri; import static androidx.media3.common.FileTypes.inferFileTypeFromUri;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.FileTypes; import androidx.media3.common.FileTypes;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
...@@ -47,6 +48,7 @@ import java.util.ArrayList; ...@@ -47,6 +48,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* An {@link ExtractorsFactory} that provides an array of extractors for the following formats: * An {@link ExtractorsFactory} that provides an array of extractors for the following formats:
...@@ -101,32 +103,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { ...@@ -101,32 +103,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
FileTypes.JPEG, FileTypes.JPEG,
}; };
@Nullable private static final FlacExtensionLoader FLAC_EXTENSION_LOADER = new FlacExtensionLoader();
private static final Constructor<? extends Extractor> FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR;
static {
@Nullable Constructor<? extends Extractor> flacExtensionExtractorConstructor = null;
try {
@SuppressWarnings("nullness:argument")
boolean isFlacNativeLibraryAvailable =
Boolean.TRUE.equals(
Class.forName("androidx.media3.decoder.flac.FlacLibrary")
.getMethod("isAvailable")
.invoke(/* obj= */ null));
if (isFlacNativeLibraryAvailable) {
flacExtensionExtractorConstructor =
Class.forName("androidx.media3.decoder.flac.FlacExtractor")
.asSubclass(Extractor.class)
.getConstructor(int.class);
}
} catch (ClassNotFoundException e) {
// Expected if the app was built without the FLAC extension.
} catch (Exception e) {
// The FLAC extension is present, but instantiation failed.
throw new RuntimeException("Error instantiating FLAC extension", e);
}
FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR = flacExtensionExtractorConstructor;
}
private boolean constantBitrateSeekingEnabled; private boolean constantBitrateSeekingEnabled;
private boolean constantBitrateSeekingAlwaysEnabled; private boolean constantBitrateSeekingAlwaysEnabled;
...@@ -379,13 +356,9 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { ...@@ -379,13 +356,9 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
: 0))); : 0)));
break; break;
case FileTypes.FLAC: case FileTypes.FLAC:
if (FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) { @Nullable Extractor flacExtractor = FLAC_EXTENSION_LOADER.getExtractor(flacFlags);
try { if (flacExtractor != null) {
extractors.add(FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance(flacFlags)); extractors.add(flacExtractor);
} catch (Exception e) {
// Should never happen.
throw new IllegalStateException("Unexpected error creating FLAC extractor", e);
}
} else { } else {
extractors.add(new FlacExtractor(flacFlags)); extractors.add(new FlacExtractor(flacFlags));
} }
...@@ -432,4 +405,60 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { ...@@ -432,4 +405,60 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
break; break;
} }
} }
private static final class FlacExtensionLoader {
private final AtomicBoolean extensionLoaded;
@GuardedBy("extensionLoaded")
@Nullable
private Constructor<? extends Extractor> extractorConstructor;
public FlacExtensionLoader() {
extensionLoaded = new AtomicBoolean(false);
}
@Nullable
public Extractor getExtractor(int flags) {
@Nullable
Constructor<? extends Extractor> extractorConstructor = maybeLoadExtractorConstructor();
if (extractorConstructor == null) {
return null;
}
try {
return extractorConstructor.newInstance(flags);
} catch (Exception e) {
throw new IllegalStateException("Unexpected error creating FLAC extractor", e);
}
}
@Nullable
private Constructor<? extends Extractor> maybeLoadExtractorConstructor() {
synchronized (extensionLoaded) {
if (extensionLoaded.get()) {
return extractorConstructor;
}
try {
@SuppressWarnings("nullness:argument")
boolean isFlacNativeLibraryAvailable =
Boolean.TRUE.equals(
Class.forName("androidx.media3.decoder.flac.FlacLibrary")
.getMethod("isAvailable")
.invoke(/* obj= */ null));
if (isFlacNativeLibraryAvailable) {
extractorConstructor =
Class.forName("androidx.media3.decoder.flac.FlacExtractor")
.asSubclass(Extractor.class)
.getConstructor(int.class);
}
} catch (ClassNotFoundException e) {
// Expected if the app was built without the FLAC extension.
} catch (Exception e) {
// The FLAC extension is present, but instantiation failed.
throw new RuntimeException("Error instantiating FLAC extension", e);
}
extensionLoaded.set(true);
return extractorConstructor;
}
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment