From efb49f285e7a83ec39ca5364eb73894b8ec49dc5 Mon Sep 17 00:00:00 2001 From: hmzh Date: Wed, 11 May 2022 14:12:13 +0100 Subject: [PATCH] Refactor MIDI and Flac extractor loaders for deduplication Add MIDI filetype information for use in the ExtractorsFactory PiperOrigin-RevId: 447976272 --- .../androidx/media3/common/FileTypes.java | 16 +++- .../extractor/DefaultExtractorsFactory.java | 79 ++++++++++++++----- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/FileTypes.java b/libraries/common/src/main/java/androidx/media3/common/FileTypes.java index cc5fd41dee..a7ba44cdcc 100644 --- a/libraries/common/src/main/java/androidx/media3/common/FileTypes.java +++ b/libraries/common/src/main/java/androidx/media3/common/FileTypes.java @@ -37,13 +37,14 @@ public final class FileTypes { /** * File types. One of {@link #UNKNOWN}, {@link #AC3}, {@link #AC4}, {@link #ADTS}, {@link #AMR}, * {@link #FLAC}, {@link #FLV}, {@link #MATROSKA}, {@link #MP3}, {@link #MP4}, {@link #OGG}, - * {@link #PS}, {@link #TS}, {@link #WAV}, {@link #WEBVTT} and {@link #JPEG}. + * {@link #PS}, {@link #TS}, {@link #WAV}, {@link #WEBVTT}, {@link #JPEG} and {@link #MIDI}. */ @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @IntDef({ - UNKNOWN, AC3, AC4, ADTS, AMR, FLAC, FLV, MATROSKA, MP3, MP4, OGG, PS, TS, WAV, WEBVTT, JPEG + UNKNOWN, AC3, AC4, ADTS, AMR, FLAC, FLV, MATROSKA, MP3, MP4, OGG, PS, TS, WAV, WEBVTT, JPEG, + MIDI }) public @interface Type {} /** Unknown file type. */ @@ -78,6 +79,8 @@ public final class FileTypes { public static final int WEBVTT = 13; /** File type for the JPEG format. */ public static final int JPEG = 14; + /** File type for the MIDI format. */ + public static final int MIDI = 15; @VisibleForTesting /* package */ static final String HEADER_CONTENT_TYPE = "Content-Type"; @@ -89,6 +92,9 @@ public final class FileTypes { private static final String EXTENSION_AMR = ".amr"; private static final String EXTENSION_FLAC = ".flac"; private static final String EXTENSION_FLV = ".flv"; + private static final String EXTENSION_MID = ".mid"; + private static final String EXTENSION_MIDI = ".midi"; + private static final String EXTENSION_SMF = ".smf"; private static final String EXTENSION_PREFIX_MK = ".mk"; private static final String EXTENSION_WEBM = ".webm"; private static final String EXTENSION_PREFIX_OG = ".og"; @@ -147,6 +153,8 @@ public final class FileTypes { return FileTypes.FLAC; case MimeTypes.VIDEO_FLV: return FileTypes.FLV; + case MimeTypes.AUDIO_MIDI: + return FileTypes.MIDI; case MimeTypes.VIDEO_MATROSKA: case MimeTypes.AUDIO_MATROSKA: case MimeTypes.VIDEO_WEBM: @@ -193,6 +201,10 @@ public final class FileTypes { return FileTypes.FLAC; } else if (filename.endsWith(EXTENSION_FLV)) { return FileTypes.FLV; + } else if (filename.endsWith(EXTENSION_MID) + || filename.endsWith(EXTENSION_MIDI) + || filename.endsWith(EXTENSION_SMF)) { + return FileTypes.MIDI; } else if (filename.startsWith( EXTENSION_PREFIX_MK, /* toffset= */ filename.length() - (EXTENSION_PREFIX_MK.length() + 1)) 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 5470d906a8..65aff22e3a 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DefaultExtractorsFactory.java @@ -44,6 +44,7 @@ import androidx.media3.extractor.ts.TsExtractor; import androidx.media3.extractor.ts.TsPayloadReader; import androidx.media3.extractor.wav.WavExtractor; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -76,6 +77,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * the FLAC extension or the FFmpeg extension. * *
  • JPEG ({@link JpegExtractor}) + *
  • MIDI, if available, the MIDI extension's {@code androidx.media3.decoder.midi.MidiExtractor} + * is used. * */ @UnstableApi @@ -101,9 +104,13 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { FileTypes.AC4, FileTypes.MP3, FileTypes.JPEG, + FileTypes.MIDI, }; - private static final FlacExtensionLoader FLAC_EXTENSION_LOADER = new FlacExtensionLoader(); + private static final ExtensionLoader FLAC_EXTENSION_LOADER = + new ExtensionLoader(DefaultExtractorsFactory::getFlacExtractorConstructor); + private static final ExtensionLoader MIDI_EXTENSION_LOADER = + new ExtensionLoader(DefaultExtractorsFactory::getMidiExtractorConstructor); private boolean constantBitrateSeekingEnabled; private boolean constantBitrateSeekingAlwaysEnabled; @@ -399,6 +406,12 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { case FileTypes.JPEG: extractors.add(new JpegExtractor()); break; + case FileTypes.MIDI: + @Nullable Extractor midiExtractor = MIDI_EXTENSION_LOADER.getExtractor(); + if (midiExtractor != null) { + extractors.add(midiExtractor); + } + break; case FileTypes.WEBVTT: case FileTypes.UNKNOWN: default: @@ -406,28 +419,63 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { } } - private static final class FlacExtensionLoader { + private static Constructor getMidiExtractorConstructor() + throws ClassNotFoundException, NoSuchMethodException { + return Class.forName("androidx.media3.decoder.midi.MidiExtractor") + .asSubclass(Extractor.class) + .getConstructor(); + } + + @Nullable + private static Constructor getFlacExtractorConstructor() + throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + IllegalAccessException { + @SuppressWarnings("nullness:argument") + boolean isFlacNativeLibraryAvailable = + Boolean.TRUE.equals( + Class.forName("androidx.media3.decoder.flac.FlacLibrary") + .getMethod("isAvailable") + .invoke(/* obj= */ null)); + if (isFlacNativeLibraryAvailable) { + return Class.forName("androidx.media3.decoder.flac.FlacExtractor") + .asSubclass(Extractor.class) + .getConstructor(int.class); + } + return null; + } + + private static final class ExtensionLoader { + + public interface ConstructorSupplier { + @Nullable + Constructor getConstructor() + throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, + ClassNotFoundException; + } + + private final ConstructorSupplier constructorSupplier; private final AtomicBoolean extensionLoaded; @GuardedBy("extensionLoaded") @Nullable private Constructor extractorConstructor; - public FlacExtensionLoader() { + public ExtensionLoader(ConstructorSupplier constructorSupplier) { + this.constructorSupplier = constructorSupplier; extensionLoaded = new AtomicBoolean(false); } @Nullable - public Extractor getExtractor(int flags) { + public Extractor getExtractor(Object... constructorParams) { @Nullable Constructor extractorConstructor = maybeLoadExtractorConstructor(); if (extractorConstructor == null) { return null; } try { - return extractorConstructor.newInstance(flags); + return extractorConstructor.newInstance(constructorParams); } catch (Exception e) { - throw new IllegalStateException("Unexpected error creating FLAC extractor", e); + throw new IllegalStateException("Unexpected error creating extractor", e); } } @@ -438,23 +486,12 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { 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); - } + return constructorSupplier.getConstructor(); } catch (ClassNotFoundException e) { - // Expected if the app was built without the FLAC extension. + // Expected if the app was built without the extension. } catch (Exception e) { - // The FLAC extension is present, but instantiation failed. - throw new RuntimeException("Error instantiating FLAC extension", e); + // The extension is present, but instantiation failed. + throw new RuntimeException("Error instantiating extension", e); } extensionLoaded.set(true); return extractorConstructor;