Add an extractor flag for ignoring edit lists
Issue: #3358 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=172464053
This commit is contained in:
parent
2c10e6f1c3
commit
f9249d23ea
@ -67,6 +67,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @MatroskaExtractor.Flags int matroskaFlags;
|
private @MatroskaExtractor.Flags int matroskaFlags;
|
||||||
|
private @Mp4Extractor.Flags int mp4Flags;
|
||||||
private @FragmentedMp4Extractor.Flags int fragmentedMp4Flags;
|
private @FragmentedMp4Extractor.Flags int fragmentedMp4Flags;
|
||||||
private @Mp3Extractor.Flags int mp3Flags;
|
private @Mp3Extractor.Flags int mp3Flags;
|
||||||
private @TsExtractor.Mode int tsMode;
|
private @TsExtractor.Mode int tsMode;
|
||||||
@ -89,6 +90,18 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
return this;
|
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.
|
* Sets flags for {@link FragmentedMp4Extractor} instances created by the factory.
|
||||||
*
|
*
|
||||||
@ -145,7 +158,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
Extractor[] extractors = new Extractor[FLAC_EXTRACTOR_CONSTRUCTOR == null ? 11 : 12];
|
Extractor[] extractors = new Extractor[FLAC_EXTRACTOR_CONSTRUCTOR == null ? 11 : 12];
|
||||||
extractors[0] = new MatroskaExtractor(matroskaFlags);
|
extractors[0] = new MatroskaExtractor(matroskaFlags);
|
||||||
extractors[1] = new FragmentedMp4Extractor(fragmentedMp4Flags);
|
extractors[1] = new FragmentedMp4Extractor(fragmentedMp4Flags);
|
||||||
extractors[2] = new Mp4Extractor();
|
extractors[2] = new Mp4Extractor(mp4Flags);
|
||||||
extractors[3] = new Mp3Extractor(mp3Flags);
|
extractors[3] = new Mp3Extractor(mp3Flags);
|
||||||
extractors[4] = new AdtsExtractor();
|
extractors[4] = new AdtsExtractor();
|
||||||
extractors[5] = new Ac3Extractor();
|
extractors[5] = new Ac3Extractor();
|
||||||
|
@ -60,11 +60,13 @@ import java.util.List;
|
|||||||
* @param duration The duration in units of the timescale declared in the mvhd atom, or
|
* @param duration The duration in units of the timescale declared in the mvhd atom, or
|
||||||
* {@link C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
|
* {@link C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
|
||||||
* @param drmInitData {@link DrmInitData} to be included in the format.
|
* @param drmInitData {@link DrmInitData} to be included in the format.
|
||||||
|
* @param ignoreEditLists Whether to ignore any edit lists in the trak box.
|
||||||
* @param isQuickTime True for QuickTime media. False otherwise.
|
* @param isQuickTime True for QuickTime media. False otherwise.
|
||||||
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
|
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
|
||||||
*/
|
*/
|
||||||
public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd, long duration,
|
public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd, long duration,
|
||||||
DrmInitData drmInitData, boolean isQuickTime) throws ParserException {
|
DrmInitData drmInitData, boolean ignoreEditLists, boolean isQuickTime)
|
||||||
|
throws ParserException {
|
||||||
Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia);
|
Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia);
|
||||||
int trackType = parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data);
|
int trackType = parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data);
|
||||||
if (trackType == C.TRACK_TYPE_UNKNOWN) {
|
if (trackType == C.TRACK_TYPE_UNKNOWN) {
|
||||||
@ -88,11 +90,17 @@ import java.util.List;
|
|||||||
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
|
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
|
||||||
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id,
|
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id,
|
||||||
tkhdData.rotationDegrees, mdhdData.second, drmInitData, isQuickTime);
|
tkhdData.rotationDegrees, mdhdData.second, drmInitData, isQuickTime);
|
||||||
|
long[] editListDurations = null;
|
||||||
|
long[] editListMediaTimes = null;
|
||||||
|
if (!ignoreEditLists) {
|
||||||
Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts));
|
Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts));
|
||||||
|
editListDurations = edtsData.first;
|
||||||
|
editListMediaTimes = edtsData.second;
|
||||||
|
}
|
||||||
return stsdData.format == null ? null
|
return stsdData.format == null ? null
|
||||||
: new Track(tkhdData.id, trackType, mdhdData.first, movieTimescale, durationUs,
|
: new Track(tkhdData.id, trackType, mdhdData.first, movieTimescale, durationUs,
|
||||||
stsdData.format, stsdData.requiredSampleTransformation, stsdData.trackEncryptionBoxes,
|
stsdData.format, stsdData.requiredSampleTransformation, stsdData.trackEncryptionBoxes,
|
||||||
stsdData.nalUnitLengthFieldLength, edtsData.first, edtsData.second);
|
stsdData.nalUnitLengthFieldLength, editListDurations, editListMediaTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +74,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef(flag = true, value = {FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME,
|
@IntDef(flag = true, value = {FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME,
|
||||||
FLAG_WORKAROUND_IGNORE_TFDT_BOX, FLAG_ENABLE_EMSG_TRACK, FLAG_ENABLE_CEA608_TRACK,
|
FLAG_WORKAROUND_IGNORE_TFDT_BOX, FLAG_ENABLE_EMSG_TRACK, FLAG_ENABLE_CEA608_TRACK,
|
||||||
FLAG_SIDELOADED})
|
FLAG_SIDELOADED, FLAG_WORKAROUND_IGNORE_EDIT_LISTS})
|
||||||
public @interface Flags {}
|
public @interface Flags {}
|
||||||
/**
|
/**
|
||||||
* Flag to work around an issue in some video streams where every frame is marked as a sync frame.
|
* Flag to work around an issue in some video streams where every frame is marked as a sync frame.
|
||||||
@ -103,6 +103,10 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||||||
* container.
|
* container.
|
||||||
*/
|
*/
|
||||||
private static final int FLAG_SIDELOADED = 16;
|
private static final int FLAG_SIDELOADED = 16;
|
||||||
|
/**
|
||||||
|
* Flag to ignore any edit lists in the stream.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_WORKAROUND_IGNORE_EDIT_LISTS = 32;
|
||||||
|
|
||||||
private static final String TAG = "FragmentedMp4Extractor";
|
private static final String TAG = "FragmentedMp4Extractor";
|
||||||
private static final int SAMPLE_GROUP_TYPE_seig = Util.getIntegerCodeForString("seig");
|
private static final int SAMPLE_GROUP_TYPE_seig = Util.getIntegerCodeForString("seig");
|
||||||
@ -432,7 +436,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||||||
Atom.ContainerAtom atom = moov.containerChildren.get(i);
|
Atom.ContainerAtom atom = moov.containerChildren.get(i);
|
||||||
if (atom.type == Atom.TYPE_trak) {
|
if (atom.type == Atom.TYPE_trak) {
|
||||||
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), duration,
|
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), duration,
|
||||||
drmInitData, false);
|
drmInitData, (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, false);
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
tracks.put(track.id, track);
|
tracks.put(track.id, track);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import com.google.android.exoplayer2.extractor.PositionHolder;
|
|||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||||
import com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom;
|
import com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom;
|
||||||
|
import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor.Flags;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.NalUnitUtil;
|
import com.google.android.exoplayer2.util.NalUnitUtil;
|
||||||
@ -57,6 +58,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags controlling the behavior of the extractor.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef(flag = true, value = {FLAG_WORKAROUND_IGNORE_EDIT_LISTS})
|
||||||
|
public @interface Flags {}
|
||||||
|
/**
|
||||||
|
* Flag to ignore any edit lists in the stream.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_WORKAROUND_IGNORE_EDIT_LISTS = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser states.
|
* Parser states.
|
||||||
*/
|
*/
|
||||||
@ -76,6 +88,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
|||||||
*/
|
*/
|
||||||
private static final long RELOAD_MINIMUM_SEEK_DISTANCE = 256 * 1024;
|
private static final long RELOAD_MINIMUM_SEEK_DISTANCE = 256 * 1024;
|
||||||
|
|
||||||
|
private final @Flags int flags;
|
||||||
|
|
||||||
// Temporary arrays.
|
// Temporary arrays.
|
||||||
private final ParsableByteArray nalStartCode;
|
private final ParsableByteArray nalStartCode;
|
||||||
private final ParsableByteArray nalLength;
|
private final ParsableByteArray nalLength;
|
||||||
@ -98,7 +112,21 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
|||||||
private long durationUs;
|
private long durationUs;
|
||||||
private boolean isQuickTime;
|
private boolean isQuickTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new extractor for unfragmented MP4 streams.
|
||||||
|
*/
|
||||||
public Mp4Extractor() {
|
public Mp4Extractor() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new extractor for unfragmented MP4 streams, using the specified flags to control the
|
||||||
|
* extractor's behavior.
|
||||||
|
*
|
||||||
|
* @param flags Flags that control the extractor's behavior.
|
||||||
|
*/
|
||||||
|
public Mp4Extractor(@Flags int flags) {
|
||||||
|
this.flags = flags;
|
||||||
atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE);
|
atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE);
|
||||||
containerAtoms = new Stack<>();
|
containerAtoms = new Stack<>();
|
||||||
nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE);
|
nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE);
|
||||||
@ -345,7 +373,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd),
|
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd),
|
||||||
C.TIME_UNSET, null, isQuickTime);
|
C.TIME_UNSET, null, (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, isQuickTime);
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -81,12 +81,12 @@ public final class Track {
|
|||||||
/**
|
/**
|
||||||
* Durations of edit list segments in the movie timescale. Null if there is no edit list.
|
* Durations of edit list segments in the movie timescale. Null if there is no edit list.
|
||||||
*/
|
*/
|
||||||
public final long[] editListDurations;
|
@Nullable public final long[] editListDurations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Media times for edit list segments in the track timescale. Null if there is no edit list.
|
* Media times for edit list segments in the track timescale. Null if there is no edit list.
|
||||||
*/
|
*/
|
||||||
public final long[] editListMediaTimes;
|
@Nullable public final long[] editListMediaTimes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For H264 video tracks, the length in bytes of the NALUnitLength field in each sample. 0 for
|
* For H264 video tracks, the length in bytes of the NALUnitLength field in each sample. 0 for
|
||||||
@ -99,7 +99,7 @@ public final class Track {
|
|||||||
public Track(int id, int type, long timescale, long movieTimescale, long durationUs,
|
public Track(int id, int type, long timescale, long movieTimescale, long durationUs,
|
||||||
Format format, @Transformation int sampleTransformation,
|
Format format, @Transformation int sampleTransformation,
|
||||||
@Nullable TrackEncryptionBox[] sampleDescriptionEncryptionBoxes, int nalUnitLengthFieldLength,
|
@Nullable TrackEncryptionBox[] sampleDescriptionEncryptionBoxes, int nalUnitLengthFieldLength,
|
||||||
long[] editListDurations, long[] editListMediaTimes) {
|
@Nullable long[] editListDurations, @Nullable long[] editListMediaTimes) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.timescale = timescale;
|
this.timescale = timescale;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user