mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Refactor MIDI and Flac extractor loaders for deduplication
Add MIDI filetype information for use in the ExtractorsFactory PiperOrigin-RevId: 447976272
This commit is contained in:
parent
1d89c35f7b
commit
efb49f285e
@ -37,13 +37,14 @@ public final class FileTypes {
|
|||||||
/**
|
/**
|
||||||
* File types. One of {@link #UNKNOWN}, {@link #AC3}, {@link #AC4}, {@link #ADTS}, {@link #AMR},
|
* 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 #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
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@Target(TYPE_USE)
|
@Target(TYPE_USE)
|
||||||
@IntDef({
|
@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 {}
|
public @interface Type {}
|
||||||
/** Unknown file type. */
|
/** Unknown file type. */
|
||||||
@ -78,6 +79,8 @@ public final class FileTypes {
|
|||||||
public static final int WEBVTT = 13;
|
public static final int WEBVTT = 13;
|
||||||
/** File type for the JPEG format. */
|
/** File type for the JPEG format. */
|
||||||
public static final int JPEG = 14;
|
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";
|
@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_AMR = ".amr";
|
||||||
private static final String EXTENSION_FLAC = ".flac";
|
private static final String EXTENSION_FLAC = ".flac";
|
||||||
private static final String EXTENSION_FLV = ".flv";
|
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_PREFIX_MK = ".mk";
|
||||||
private static final String EXTENSION_WEBM = ".webm";
|
private static final String EXTENSION_WEBM = ".webm";
|
||||||
private static final String EXTENSION_PREFIX_OG = ".og";
|
private static final String EXTENSION_PREFIX_OG = ".og";
|
||||||
@ -147,6 +153,8 @@ public final class FileTypes {
|
|||||||
return FileTypes.FLAC;
|
return FileTypes.FLAC;
|
||||||
case MimeTypes.VIDEO_FLV:
|
case MimeTypes.VIDEO_FLV:
|
||||||
return FileTypes.FLV;
|
return FileTypes.FLV;
|
||||||
|
case MimeTypes.AUDIO_MIDI:
|
||||||
|
return FileTypes.MIDI;
|
||||||
case MimeTypes.VIDEO_MATROSKA:
|
case MimeTypes.VIDEO_MATROSKA:
|
||||||
case MimeTypes.AUDIO_MATROSKA:
|
case MimeTypes.AUDIO_MATROSKA:
|
||||||
case MimeTypes.VIDEO_WEBM:
|
case MimeTypes.VIDEO_WEBM:
|
||||||
@ -193,6 +201,10 @@ public final class FileTypes {
|
|||||||
return FileTypes.FLAC;
|
return FileTypes.FLAC;
|
||||||
} else if (filename.endsWith(EXTENSION_FLV)) {
|
} else if (filename.endsWith(EXTENSION_FLV)) {
|
||||||
return FileTypes.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(
|
} else if (filename.startsWith(
|
||||||
EXTENSION_PREFIX_MK,
|
EXTENSION_PREFIX_MK,
|
||||||
/* toffset= */ filename.length() - (EXTENSION_PREFIX_MK.length() + 1))
|
/* toffset= */ filename.length() - (EXTENSION_PREFIX_MK.length() + 1))
|
||||||
|
@ -44,6 +44,7 @@ import androidx.media3.extractor.ts.TsExtractor;
|
|||||||
import androidx.media3.extractor.ts.TsPayloadReader;
|
import androidx.media3.extractor.ts.TsPayloadReader;
|
||||||
import androidx.media3.extractor.wav.WavExtractor;
|
import androidx.media3.extractor.wav.WavExtractor;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -76,6 +77,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* the FLAC extension or the FFmpeg extension.
|
* the FLAC extension or the FFmpeg extension.
|
||||||
* </ul>
|
* </ul>
|
||||||
* <li>JPEG ({@link JpegExtractor})
|
* <li>JPEG ({@link JpegExtractor})
|
||||||
|
* <li>MIDI, if available, the MIDI extension's {@code androidx.media3.decoder.midi.MidiExtractor}
|
||||||
|
* is used.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
@ -101,9 +104,13 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
FileTypes.AC4,
|
FileTypes.AC4,
|
||||||
FileTypes.MP3,
|
FileTypes.MP3,
|
||||||
FileTypes.JPEG,
|
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 constantBitrateSeekingEnabled;
|
||||||
private boolean constantBitrateSeekingAlwaysEnabled;
|
private boolean constantBitrateSeekingAlwaysEnabled;
|
||||||
@ -399,6 +406,12 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
case FileTypes.JPEG:
|
case FileTypes.JPEG:
|
||||||
extractors.add(new JpegExtractor());
|
extractors.add(new JpegExtractor());
|
||||||
break;
|
break;
|
||||||
|
case FileTypes.MIDI:
|
||||||
|
@Nullable Extractor midiExtractor = MIDI_EXTENSION_LOADER.getExtractor();
|
||||||
|
if (midiExtractor != null) {
|
||||||
|
extractors.add(midiExtractor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case FileTypes.WEBVTT:
|
case FileTypes.WEBVTT:
|
||||||
case FileTypes.UNKNOWN:
|
case FileTypes.UNKNOWN:
|
||||||
default:
|
default:
|
||||||
@ -406,28 +419,63 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class FlacExtensionLoader {
|
private static Constructor<? extends Extractor> getMidiExtractorConstructor()
|
||||||
|
throws ClassNotFoundException, NoSuchMethodException {
|
||||||
|
return Class.forName("androidx.media3.decoder.midi.MidiExtractor")
|
||||||
|
.asSubclass(Extractor.class)
|
||||||
|
.getConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Constructor<? extends Extractor> 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<? extends Extractor> getConstructor()
|
||||||
|
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException,
|
||||||
|
ClassNotFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ConstructorSupplier constructorSupplier;
|
||||||
private final AtomicBoolean extensionLoaded;
|
private final AtomicBoolean extensionLoaded;
|
||||||
|
|
||||||
@GuardedBy("extensionLoaded")
|
@GuardedBy("extensionLoaded")
|
||||||
@Nullable
|
@Nullable
|
||||||
private Constructor<? extends Extractor> extractorConstructor;
|
private Constructor<? extends Extractor> extractorConstructor;
|
||||||
|
|
||||||
public FlacExtensionLoader() {
|
public ExtensionLoader(ConstructorSupplier constructorSupplier) {
|
||||||
|
this.constructorSupplier = constructorSupplier;
|
||||||
extensionLoaded = new AtomicBoolean(false);
|
extensionLoaded = new AtomicBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Extractor getExtractor(int flags) {
|
public Extractor getExtractor(Object... constructorParams) {
|
||||||
@Nullable
|
@Nullable
|
||||||
Constructor<? extends Extractor> extractorConstructor = maybeLoadExtractorConstructor();
|
Constructor<? extends Extractor> extractorConstructor = maybeLoadExtractorConstructor();
|
||||||
if (extractorConstructor == null) {
|
if (extractorConstructor == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return extractorConstructor.newInstance(flags);
|
return extractorConstructor.newInstance(constructorParams);
|
||||||
} catch (Exception e) {
|
} 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;
|
return extractorConstructor;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("nullness:argument")
|
return constructorSupplier.getConstructor();
|
||||||
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) {
|
} 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) {
|
} catch (Exception e) {
|
||||||
// The FLAC extension is present, but instantiation failed.
|
// The extension is present, but instantiation failed.
|
||||||
throw new RuntimeException("Error instantiating FLAC extension", e);
|
throw new RuntimeException("Error instantiating extension", e);
|
||||||
}
|
}
|
||||||
extensionLoaded.set(true);
|
extensionLoaded.set(true);
|
||||||
return extractorConstructor;
|
return extractorConstructor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user