diff --git a/library/core/build.gradle b/library/core/build.gradle index 49ed791a788..8ab63af26fc 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -20,7 +20,6 @@ android { defaultConfig { minSdkVersion project.ext.minSdkVersion targetSdkVersion project.ext.targetSdkVersion - consumerProguardFiles 'proguard-rules.txt' } sourceSets { diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt deleted file mode 100644 index c5d752f4c64..00000000000 --- a/library/core/proguard-rules.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Accessed via reflection in SubtitleDecoderFactory.DEFAULT --keepclassmembers class com.google.android.exoplayer2.text.cea.Cea608Decoder { - public (java.lang.String, int); -} --keepclassmembers class com.google.android.exoplayer2.text.cea.Cea708Decoder { - public (int); -} --keepclassmembers class com.google.android.exoplayer2.text.dvb.DvbDecoder { - public (java.util.List); -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java index 29fad1fbdeb..4ea8452956a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java @@ -15,141 +15,118 @@ */ package com.google.android.exoplayer2.extractor; -import java.util.ArrayList; -import java.util.List; +import com.google.android.exoplayer2.extractor.flv.FlvExtractor; +import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; +import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor; +import com.google.android.exoplayer2.extractor.ogg.OggExtractor; +import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; +import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; +import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; +import com.google.android.exoplayer2.extractor.ts.PsExtractor; +import com.google.android.exoplayer2.extractor.ts.TsExtractor; +import com.google.android.exoplayer2.extractor.wav.WavExtractor; +import java.lang.reflect.Constructor; /** * An {@link ExtractorsFactory} that provides an array of extractors for the following formats: * *
    - *
  • MP4, including M4A ({@link com.google.android.exoplayer2.extractor.mp4.Mp4Extractor})
  • - *
  • fMP4 ({@link com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor})
  • - *
  • Matroska and WebM ({@link com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor}) - *
  • - *
  • Ogg Vorbis/FLAC ({@link com.google.android.exoplayer2.extractor.ogg.OggExtractor}
  • - *
  • MP3 ({@link com.google.android.exoplayer2.extractor.mp3.Mp3Extractor})
  • - *
  • AAC ({@link com.google.android.exoplayer2.extractor.ts.AdtsExtractor})
  • - *
  • MPEG TS ({@link com.google.android.exoplayer2.extractor.ts.TsExtractor})
  • - *
  • MPEG PS ({@link com.google.android.exoplayer2.extractor.ts.PsExtractor})
  • - *
  • FLV ({@link com.google.android.exoplayer2.extractor.flv.FlvExtractor})
  • - *
  • WAV ({@link com.google.android.exoplayer2.extractor.wav.WavExtractor})
  • + *
  • MP4, including M4A ({@link Mp4Extractor})
  • + *
  • fMP4 ({@link FragmentedMp4Extractor})
  • + *
  • Matroska and WebM ({@link MatroskaExtractor})
  • + *
  • Ogg Vorbis/FLAC ({@link OggExtractor}
  • + *
  • MP3 ({@link Mp3Extractor})
  • + *
  • AAC ({@link AdtsExtractor})
  • + *
  • MPEG TS ({@link TsExtractor})
  • + *
  • MPEG PS ({@link PsExtractor})
  • + *
  • FLV ({@link FlvExtractor})
  • + *
  • WAV ({@link WavExtractor})
  • + *
  • AC3 ({@link Ac3Extractor})
  • *
  • FLAC (only available if the FLAC extension is built and included)
  • *
*/ public final class DefaultExtractorsFactory implements ExtractorsFactory { - // Lazily initialized default extractor classes in priority order. - private static List> defaultExtractorClasses; + private static final Constructor FLAC_EXTRACTOR_CONSTRUCTOR; + static { + Constructor flacExtractorConstructor = null; + try { + flacExtractorConstructor = + Class.forName("com.google.android.exoplayer2.ext.flac.FlacExtractor") + .asSubclass(Extractor.class).getConstructor(); + } catch (ClassNotFoundException e) { + // Extractor not found. + } catch (NoSuchMethodException e) { + // Constructor not found. + } + FLAC_EXTRACTOR_CONSTRUCTOR = flacExtractorConstructor; + } + + private @FragmentedMp4Extractor.Flags int fragmentedMp4Flags; + private @Mp3Extractor.Flags int mp3Flags; + private @DefaultTsPayloadReaderFactory.Flags int tsFlags; /** - * Creates a new factory for the default extractors. + * Sets flags for {@link FragmentedMp4Extractor} instances created by the factory. + * + * @see FragmentedMp4Extractor#FragmentedMp4Extractor(int) + * @param flags The flags to use. + * @return The factory, for convenience. */ - public DefaultExtractorsFactory() { - synchronized (DefaultExtractorsFactory.class) { - if (defaultExtractorClasses == null) { - // Lazily initialize defaultExtractorClasses. - List> extractorClasses = new ArrayList<>(); - // We reference extractors using reflection so that they can be deleted cleanly. - // Class.forName is used so that automated tools like proguard can detect the use of - // reflection (see http://proguard.sourceforge.net/FAQ.html#forname). - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.mp4.Mp4Extractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.mp3.Mp3Extractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.ts.AdtsExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.ts.Ac3Extractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.ts.TsExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.flv.FlvExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.ogg.OggExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.ts.PsExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.extractor.wav.WavExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - try { - extractorClasses.add( - Class.forName("com.google.android.exoplayer2.ext.flac.FlacExtractor") - .asSubclass(Extractor.class)); - } catch (ClassNotFoundException e) { - // Extractor not found. - } - defaultExtractorClasses = extractorClasses; - } - } + public synchronized DefaultExtractorsFactory setFragmentedMp4ExtractorFlags( + @FragmentedMp4Extractor.Flags int flags) { + this.fragmentedMp4Flags = flags; + return this; + } + + /** + * Sets flags for {@link Mp3Extractor} instances created by the factory. + * + * @see Mp3Extractor#Mp3Extractor(int) + * @param flags The flags to use. + * @return The factory, for convenience. + */ + public synchronized DefaultExtractorsFactory setMp3ExtractorFlags(@Mp3Extractor.Flags int flags) { + mp3Flags = flags; + return this; + } + + /** + * Sets flags for {@link DefaultTsPayloadReaderFactory}s used by {@link TsExtractor} instances + * created by the factory. + * + * @see TsExtractor#TsExtractor(int) + * @param flags The flags to use. + * @return The factory, for convenience. + */ + public synchronized DefaultExtractorsFactory setTsExtractorFlags( + @DefaultTsPayloadReaderFactory.Flags int flags) { + tsFlags = flags; + return this; } @Override - public Extractor[] createExtractors() { - Extractor[] extractors = new Extractor[defaultExtractorClasses.size()]; - for (int i = 0; i < extractors.length; i++) { + public synchronized Extractor[] createExtractors() { + Extractor[] extractors = new Extractor[FLAC_EXTRACTOR_CONSTRUCTOR == null ? 11 : 12]; + extractors[0] = new MatroskaExtractor(); + extractors[1] = new FragmentedMp4Extractor(fragmentedMp4Flags); + extractors[2] = new Mp4Extractor(); + extractors[3] = new Mp3Extractor(mp3Flags); + extractors[4] = new AdtsExtractor(); + extractors[5] = new Ac3Extractor(); + extractors[6] = new TsExtractor(tsFlags); + extractors[7] = new FlvExtractor(); + extractors[8] = new OggExtractor(); + extractors[9] = new PsExtractor(); + extractors[10] = new WavExtractor(); + if (FLAC_EXTRACTOR_CONSTRUCTOR != null) { try { - extractors[i] = defaultExtractorClasses.get(i).getConstructor().newInstance(); + extractors[11] = FLAC_EXTRACTOR_CONSTRUCTOR.newInstance(); } catch (Exception e) { // Should never happen. - throw new IllegalStateException("Unexpected error creating default extractor", e); + throw new IllegalStateException("Unexpected error creating FLAC extractor", e); } } return extractors; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java index 1e391c3eca6..3808d18b9a8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java @@ -39,8 +39,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact @IntDef(flag = true, value = {FLAG_ALLOW_NON_IDR_KEYFRAMES, FLAG_IGNORE_AAC_STREAM, FLAG_IGNORE_H264_STREAM, FLAG_DETECT_ACCESS_UNITS, FLAG_IGNORE_SPLICE_INFO_STREAM, FLAG_OVERRIDE_CAPTION_DESCRIPTORS}) - public @interface Flags { - } + public @interface Flags {} public static final int FLAG_ALLOW_NON_IDR_KEYFRAMES = 1; public static final int FLAG_IGNORE_AAC_STREAM = 1 << 1; public static final int FLAG_IGNORE_H264_STREAM = 1 << 2; @@ -54,11 +53,19 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact private final List closedCaptionFormats; public DefaultTsPayloadReaderFactory() { - this(0, Collections.emptyList()); + this(0); + } + + /** + * @param flags A combination of {@code FLAG_*} values that control the behavior of the created + * readers. + */ + public DefaultTsPayloadReaderFactory(@Flags int flags) { + this(flags, Collections.emptyList()); } /** - * @param flags A combination of {@code FLAG_*} values, which control the behavior of the created + * @param flags A combination of {@code FLAG_*} values that control the behavior of the created * readers. * @param closedCaptionFormats {@link Format}s to be exposed by payload readers for streams with * embedded closed captions when no caption service descriptors are provided. If diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index e242414ff28..b1c1220c453 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -27,6 +27,7 @@ import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory.Flags; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; import com.google.android.exoplayer2.util.Assertions; @@ -122,7 +123,16 @@ public Extractor[] createExtractors() { private TsPayloadReader id3Reader; public TsExtractor() { - this(MODE_NORMAL, new TimestampAdjuster(0), new DefaultTsPayloadReaderFactory()); + this(0); + } + + /** + * @param defaultTsPayloadReaderFlags A combination of {@link DefaultTsPayloadReaderFactory} + * {@code FLAG_*} values that control the behavior of the payload readers. + */ + public TsExtractor(@Flags int defaultTsPayloadReaderFlags) { + this(MODE_NORMAL, new TimestampAdjuster(0), + new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags)); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java index 414a8269d7f..028a8eb8937 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataDecoderFactory.java @@ -58,39 +58,23 @@ public interface MetadataDecoderFactory { @Override public boolean supportsFormat(Format format) { - return getDecoderClass(format.sampleMimeType) != null; + String mimeType = format.sampleMimeType; + return MimeTypes.APPLICATION_ID3.equals(mimeType) + || MimeTypes.APPLICATION_EMSG.equals(mimeType) + || MimeTypes.APPLICATION_SCTE35.equals(mimeType); } @Override public MetadataDecoder createDecoder(Format format) { - try { - Class clazz = getDecoderClass(format.sampleMimeType); - if (clazz == null) { + switch (format.sampleMimeType) { + case MimeTypes.APPLICATION_ID3: + return new Id3Decoder(); + case MimeTypes.APPLICATION_EMSG: + return new EventMessageDecoder(); + case MimeTypes.APPLICATION_SCTE35: + return new SpliceInfoDecoder(); + default: throw new IllegalArgumentException("Attempted to create decoder for unsupported format"); - } - return clazz.asSubclass(MetadataDecoder.class).getConstructor().newInstance(); - } catch (Exception e) { - throw new IllegalStateException("Unexpected error instantiating decoder", e); - } - } - - private Class getDecoderClass(String mimeType) { - if (mimeType == null) { - return null; - } - try { - switch (mimeType) { - case MimeTypes.APPLICATION_ID3: - return Class.forName("com.google.android.exoplayer2.metadata.id3.Id3Decoder"); - case MimeTypes.APPLICATION_EMSG: - return Class.forName("com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder"); - case MimeTypes.APPLICATION_SCTE35: - return Class.forName("com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder"); - default: - return null; - } - } catch (ClassNotFoundException e) { - return null; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index 5f318916b51..f65d5a6e551 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -18,13 +18,13 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.text.cea.Cea608Decoder; import com.google.android.exoplayer2.text.cea.Cea708Decoder; +import com.google.android.exoplayer2.text.dvb.DvbDecoder; import com.google.android.exoplayer2.text.subrip.SubripDecoder; import com.google.android.exoplayer2.text.ttml.TtmlDecoder; import com.google.android.exoplayer2.text.tx3g.Tx3gDecoder; import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; import com.google.android.exoplayer2.util.MimeTypes; -import java.util.List; /** * A factory for {@link SubtitleDecoder} instances. @@ -61,68 +61,47 @@ public interface SubtitleDecoderFactory { *
  • TX3G ({@link Tx3gDecoder})
  • *
  • Cea608 ({@link Cea608Decoder})
  • *
  • Cea708 ({@link Cea708Decoder})
  • + *
  • DVB ({@link DvbDecoder})
  • * */ SubtitleDecoderFactory DEFAULT = new SubtitleDecoderFactory() { @Override public boolean supportsFormat(Format format) { - return getDecoderClass(format.sampleMimeType) != null; + String mimeType = format.sampleMimeType; + return MimeTypes.TEXT_VTT.equals(mimeType) + || MimeTypes.APPLICATION_TTML.equals(mimeType) + || MimeTypes.APPLICATION_MP4VTT.equals(mimeType) + || MimeTypes.APPLICATION_SUBRIP.equals(mimeType) + || MimeTypes.APPLICATION_TX3G.equals(mimeType) + || MimeTypes.APPLICATION_CEA608.equals(mimeType) + || MimeTypes.APPLICATION_MP4CEA608.equals(mimeType) + || MimeTypes.APPLICATION_CEA708.equals(mimeType) + || MimeTypes.APPLICATION_DVBSUBS.equals(mimeType); } @Override public SubtitleDecoder createDecoder(Format format) { - try { - Class clazz = getDecoderClass(format.sampleMimeType); - if (clazz == null) { + switch (format.sampleMimeType) { + case MimeTypes.TEXT_VTT: + return new WebvttDecoder(); + case MimeTypes.APPLICATION_MP4VTT: + return new Mp4WebvttDecoder(); + case MimeTypes.APPLICATION_TTML: + return new TtmlDecoder(); + case MimeTypes.APPLICATION_SUBRIP: + return new SubripDecoder(); + case MimeTypes.APPLICATION_TX3G: + return new Tx3gDecoder(); + case MimeTypes.APPLICATION_CEA608: + case MimeTypes.APPLICATION_MP4CEA608: + return new Cea608Decoder(format.sampleMimeType, format.accessibilityChannel); + case MimeTypes.APPLICATION_CEA708: + return new Cea708Decoder(format.accessibilityChannel); + case MimeTypes.APPLICATION_DVBSUBS: + return new DvbDecoder(format.initializationData); + default: throw new IllegalArgumentException("Attempted to create decoder for unsupported format"); - } - if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA608) - || format.sampleMimeType.equals(MimeTypes.APPLICATION_MP4CEA608)) { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) - .newInstance(format.sampleMimeType, format.accessibilityChannel); - } else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA708)) { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(Integer.TYPE) - .newInstance(format.accessibilityChannel); - } else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_DVBSUBS)) { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(List.class) - .newInstance(format.initializationData); - } else { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance(); - } - } catch (Exception e) { - throw new IllegalStateException("Unexpected error instantiating decoder", e); - } - } - - private Class getDecoderClass(String mimeType) { - if (mimeType == null) { - return null; - } - try { - switch (mimeType) { - case MimeTypes.TEXT_VTT: - return Class.forName("com.google.android.exoplayer2.text.webvtt.WebvttDecoder"); - case MimeTypes.APPLICATION_TTML: - return Class.forName("com.google.android.exoplayer2.text.ttml.TtmlDecoder"); - case MimeTypes.APPLICATION_MP4VTT: - return Class.forName("com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder"); - case MimeTypes.APPLICATION_SUBRIP: - return Class.forName("com.google.android.exoplayer2.text.subrip.SubripDecoder"); - case MimeTypes.APPLICATION_TX3G: - return Class.forName("com.google.android.exoplayer2.text.tx3g.Tx3gDecoder"); - case MimeTypes.APPLICATION_CEA608: - case MimeTypes.APPLICATION_MP4CEA608: - return Class.forName("com.google.android.exoplayer2.text.cea.Cea608Decoder"); - case MimeTypes.APPLICATION_CEA708: - return Class.forName("com.google.android.exoplayer2.text.cea.Cea708Decoder"); - case MimeTypes.APPLICATION_DVBSUBS: - return Class.forName("com.google.android.exoplayer2.text.dvb.DvbDecoder"); - default: - return null; - } - } catch (ClassNotFoundException e) { - return null; } }