blob: 9306a146d57c83a07b8bca03e871bb310e0487dc [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.extractor;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
import com.google.android.exoplayer2.extractor.flac.FlacExtractor;
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.Ac4Extractor;
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.ts.TsPayloadReader;
import com.google.android.exoplayer2.extractor.wav.WavExtractor;
import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.lang.reflect.Constructor;
/**
* An {@link ExtractorsFactory} that provides an array of extractors for the following formats:
*
* <ul>
* <li>MP4, including M4A ({@link Mp4Extractor})
* <li>fMP4 ({@link FragmentedMp4Extractor})
* <li>Matroska and WebM ({@link MatroskaExtractor})
* <li>Ogg Vorbis/FLAC ({@link OggExtractor}
* <li>MP3 ({@link Mp3Extractor})
* <li>AAC ({@link AdtsExtractor})
* <li>MPEG TS ({@link TsExtractor})
* <li>MPEG PS ({@link PsExtractor})
* <li>FLV ({@link FlvExtractor})
* <li>WAV ({@link WavExtractor})
* <li>AC3 ({@link Ac3Extractor})
* <li>AC4 ({@link Ac4Extractor})
* <li>AMR ({@link AmrExtractor})
* <li>FLAC
* <ul>
* <li>If available, the FLAC extension extractor is used.
* <li>Otherwise, the core {@link FlacExtractor} is used. Note that Android devices do not
* generally include a FLAC decoder before API 27. This can be worked around by using
* the FLAC extension or the FFmpeg extension.
* </ul>
* </ul>
*/
public final class DefaultExtractorsFactory implements ExtractorsFactory {
@Nullable
private static final Constructor<? extends Extractor> FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR;
static {
@Nullable Constructor<? extends Extractor> flacExtensionExtractorConstructor = null;
try {
// LINT.IfChange
@SuppressWarnings("nullness:argument.type.incompatible")
boolean isFlacNativeLibraryAvailable =
Boolean.TRUE.equals(
Class.forName("com.google.android.exoplayer2.ext.flac.FlacLibrary")
.getMethod("isAvailable")
.invoke(/* obj= */ null));
if (isFlacNativeLibraryAvailable) {
flacExtensionExtractorConstructor =
Class.forName("com.google.android.exoplayer2.ext.flac.FlacExtractor")
.asSubclass(Extractor.class)
.getConstructor();
}
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
} 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;
@AdtsExtractor.Flags private int adtsFlags;
@AmrExtractor.Flags private int amrFlags;
@FlacExtractor.Flags private int coreFlacFlags;
@MatroskaExtractor.Flags private int matroskaFlags;
@Mp4Extractor.Flags private int mp4Flags;
@FragmentedMp4Extractor.Flags private int fragmentedMp4Flags;
@Mp3Extractor.Flags private int mp3Flags;
@TsExtractor.Mode private int tsMode;
@DefaultTsPayloadReaderFactory.Flags private int tsFlags;
public DefaultExtractorsFactory() {
tsMode = TsExtractor.MODE_SINGLE_PMT;
}
/**
* Convenience method to set whether approximate seeking using constant bitrate assumptions should
* be enabled for all extractors that support it. If set to true, the flags required to enable
* this functionality will be OR'd with those passed to the setters when creating extractor
* instances. If set to false then the flags passed to the setters will be used without
* modification.
*
* @param constantBitrateSeekingEnabled Whether approximate seeking using a constant bitrate
* assumption should be enabled for all extractors that support it.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setConstantBitrateSeekingEnabled(
boolean constantBitrateSeekingEnabled) {
this.constantBitrateSeekingEnabled = constantBitrateSeekingEnabled;
return this;
}
/**
* Sets flags for {@link AdtsExtractor} instances created by the factory.
*
* @see AdtsExtractor#AdtsExtractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setAdtsExtractorFlags(
@AdtsExtractor.Flags int flags) {
this.adtsFlags = flags;
return this;
}
/**
* Sets flags for {@link AmrExtractor} instances created by the factory.
*
* @see AmrExtractor#AmrExtractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setAmrExtractorFlags(@AmrExtractor.Flags int flags) {
this.amrFlags = flags;
return this;
}
/**
* Sets flags for {@link FlacExtractor} instances created by the factory.
*
* @see FlacExtractor#FlacExtractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setCoreFlacExtractorFlags(
@FlacExtractor.Flags int flags) {
this.coreFlacFlags = flags;
return this;
}
/**
* Sets flags for {@link MatroskaExtractor} instances created by the factory.
*
* @see MatroskaExtractor#MatroskaExtractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setMatroskaExtractorFlags(
@MatroskaExtractor.Flags int flags) {
this.matroskaFlags = flags;
return this;
}
/**
* Sets flags for {@link Mp4Extractor} instances created by the factory.
*
* @see Mp4Extractor#Mp4Extractor(int)
* @param flags The flags to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setMp4ExtractorFlags(@Mp4Extractor.Flags int flags) {
this.mp4Flags = flags;
return this;
}
/**
* 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 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 the mode for {@link TsExtractor} instances created by the factory.
*
* @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory)
* @param mode The mode to use.
* @return The factory, for convenience.
*/
public synchronized DefaultExtractorsFactory setTsExtractorMode(@TsExtractor.Mode int mode) {
tsMode = mode;
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 synchronized Extractor[] createExtractors() {
Extractor[] extractors = new Extractor[14];
// Extractors order is optimized according to
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.
extractors[0] = new FlvExtractor();
if (FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) {
try {
extractors[1] = FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance();
} catch (Exception e) {
// Should never happen.
throw new IllegalStateException("Unexpected error creating FLAC extractor", e);
}
} else {
extractors[1] = new FlacExtractor(coreFlacFlags);
}
extractors[2] = new WavExtractor();
extractors[3] = new FragmentedMp4Extractor(fragmentedMp4Flags);
extractors[4] = new Mp4Extractor(mp4Flags);
extractors[5] =
new AmrExtractor(
amrFlags
| (constantBitrateSeekingEnabled
? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[6] = new PsExtractor();
extractors[7] = new OggExtractor();
extractors[8] = new TsExtractor(tsMode, tsFlags);
extractors[9] = new MatroskaExtractor(matroskaFlags);
extractors[10] =
new AdtsExtractor(
adtsFlags
| (constantBitrateSeekingEnabled
? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[11] = new Ac3Extractor();
extractors[12] = new Ac4Extractor();
extractors[13] =
new Mp3Extractor(
mp3Flags
| (constantBitrateSeekingEnabled
? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
return extractors;
}
}