From 9d5fd4f4021eeff958ef5fbac8deb54417daf858 Mon Sep 17 00:00:00 2001 From: christosts Date: Fri, 29 Oct 2021 12:34:43 +0100 Subject: [PATCH] DefaultExtractorsFactory: lazily load flac extension PiperOrigin-RevId: 406332026 --- .../extractor/DefaultExtractorsFactory.java | 95 ++++++++++++------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java index ec02740dd0..f5ee3432f1 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java @@ -19,6 +19,7 @@ import static androidx.media3.common.FileTypes.inferFileTypeFromResponseHeaders; import static androidx.media3.common.FileTypes.inferFileTypeFromUri; import android.net.Uri; +import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; import androidx.media3.common.FileTypes; import androidx.media3.common.PlaybackException; @@ -47,6 +48,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; /** * An {@link ExtractorsFactory} that provides an array of extractors for the following formats: @@ -101,32 +103,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { FileTypes.JPEG, }; - @Nullable - private static final Constructor FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR; - - static { - @Nullable Constructor 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 static final FlacExtensionLoader FLAC_EXTENSION_LOADER = new FlacExtensionLoader(); private boolean constantBitrateSeekingEnabled; private boolean constantBitrateSeekingAlwaysEnabled; @@ -379,13 +356,9 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { : 0))); break; case FileTypes.FLAC: - if (FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) { - try { - extractors.add(FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance(flacFlags)); - } catch (Exception e) { - // Should never happen. - throw new IllegalStateException("Unexpected error creating FLAC extractor", e); - } + @Nullable Extractor flacExtractor = FLAC_EXTENSION_LOADER.getExtractor(flacFlags); + if (flacExtractor != null) { + extractors.add(flacExtractor); } else { extractors.add(new FlacExtractor(flacFlags)); } @@ -432,4 +405,60 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { break; } } + + private static final class FlacExtensionLoader { + private final AtomicBoolean extensionLoaded; + + @GuardedBy("extensionLoaded") + @Nullable + private Constructor extractorConstructor; + + public FlacExtensionLoader() { + extensionLoaded = new AtomicBoolean(false); + } + + @Nullable + public Extractor getExtractor(int flags) { + @Nullable + Constructor 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 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; + } + } + } }