Avoid throwing an exception for sample default values

Allows playback of content when the default value is
not valid, but not used for any samples.

Issue: #7207
PiperOrigin-RevId: 306631376
This commit is contained in:
aquilescanta 2020-04-15 14:33:01 +01:00 committed by Oliver Woodman
parent bdc0db30fd
commit 2df9491383
2 changed files with 48 additions and 20 deletions

View File

@ -1,5 +1,11 @@
# Release notes #
### Next release ###
* Avoid throwing an exception while parsing fragmented MP4 default sample
values where the most-significant bit is set
([#7207](https://github.com/google/ExoPlayer/issues/7207)).
### 2.11.4 (2020-04-08) ###
* Add `SimpleExoPlayer.setWakeMode` to allow automatic `WifiLock` and `WakeLock`

View File

@ -664,9 +664,9 @@ public class FragmentedMp4Extractor implements Extractor {
private static Pair<Integer, DefaultSampleValues> parseTrex(ParsableByteArray trex) {
trex.setPosition(Atom.FULL_HEADER_SIZE);
int trackId = trex.readInt();
int defaultSampleDescriptionIndex = trex.readUnsignedIntToInt() - 1;
int defaultSampleDuration = trex.readUnsignedIntToInt();
int defaultSampleSize = trex.readUnsignedIntToInt();
int defaultSampleDescriptionIndex = trex.readInt() - 1;
int defaultSampleDuration = trex.readInt();
int defaultSampleSize = trex.readInt();
int defaultSampleFlags = trex.readInt();
return Pair.create(trackId, new DefaultSampleValues(defaultSampleDescriptionIndex,
@ -751,8 +751,9 @@ public class FragmentedMp4Extractor implements Extractor {
}
}
private static void parseTruns(ContainerAtom traf, TrackBundle trackBundle, long decodeTime,
@Flags int flags) {
private static void parseTruns(
ContainerAtom traf, TrackBundle trackBundle, long decodeTime, @Flags int flags)
throws ParserException {
int trunCount = 0;
int totalSampleCount = 0;
List<LeafAtom> leafChildren = traf.leafChildren;
@ -871,13 +872,20 @@ public class FragmentedMp4Extractor implements Extractor {
DefaultSampleValues defaultSampleValues = trackBundle.defaultSampleValues;
int defaultSampleDescriptionIndex =
((atomFlags & 0x02 /* default_sample_description_index_present */) != 0)
? tfhd.readUnsignedIntToInt() - 1 : defaultSampleValues.sampleDescriptionIndex;
int defaultSampleDuration = ((atomFlags & 0x08 /* default_sample_duration_present */) != 0)
? tfhd.readUnsignedIntToInt() : defaultSampleValues.duration;
int defaultSampleSize = ((atomFlags & 0x10 /* default_sample_size_present */) != 0)
? tfhd.readUnsignedIntToInt() : defaultSampleValues.size;
int defaultSampleFlags = ((atomFlags & 0x20 /* default_sample_flags_present */) != 0)
? tfhd.readUnsignedIntToInt() : defaultSampleValues.flags;
? tfhd.readInt() - 1
: defaultSampleValues.sampleDescriptionIndex;
int defaultSampleDuration =
((atomFlags & 0x08 /* default_sample_duration_present */) != 0)
? tfhd.readInt()
: defaultSampleValues.duration;
int defaultSampleSize =
((atomFlags & 0x10 /* default_sample_size_present */) != 0)
? tfhd.readInt()
: defaultSampleValues.size;
int defaultSampleFlags =
((atomFlags & 0x20 /* default_sample_flags_present */) != 0)
? tfhd.readInt()
: defaultSampleValues.flags;
trackBundle.fragment.header = new DefaultSampleValues(defaultSampleDescriptionIndex,
defaultSampleDuration, defaultSampleSize, defaultSampleFlags);
return trackBundle;
@ -910,16 +918,22 @@ public class FragmentedMp4Extractor implements Extractor {
/**
* Parses a trun atom (defined in 14496-12).
*
* @param trackBundle The {@link TrackBundle} that contains the {@link TrackFragment} into
* which parsed data should be placed.
* @param trackBundle The {@link TrackBundle} that contains the {@link TrackFragment} into which
* parsed data should be placed.
* @param index Index of the track run in the fragment.
* @param decodeTime The decode time of the first sample in the fragment run.
* @param flags Flags to allow any required workaround to be executed.
* @param trun The trun atom to decode.
* @return The starting position of samples for the next run.
*/
private static int parseTrun(TrackBundle trackBundle, int index, long decodeTime,
@Flags int flags, ParsableByteArray trun, int trackRunStart) {
private static int parseTrun(
TrackBundle trackBundle,
int index,
long decodeTime,
@Flags int flags,
ParsableByteArray trun,
int trackRunStart)
throws ParserException {
trun.setPosition(Atom.HEADER_SIZE);
int fullAtom = trun.readInt();
int atomFlags = Atom.parseFullAtomFlags(fullAtom);
@ -937,7 +951,7 @@ public class FragmentedMp4Extractor implements Extractor {
boolean firstSampleFlagsPresent = (atomFlags & 0x04 /* first_sample_flags_present */) != 0;
int firstSampleFlags = defaultSampleValues.flags;
if (firstSampleFlagsPresent) {
firstSampleFlags = trun.readUnsignedIntToInt();
firstSampleFlags = trun.readInt();
}
boolean sampleDurationsPresent = (atomFlags & 0x100 /* sample_duration_present */) != 0;
@ -972,9 +986,10 @@ public class FragmentedMp4Extractor implements Extractor {
long cumulativeTime = index > 0 ? fragment.nextFragmentDecodeTime : decodeTime;
for (int i = trackRunStart; i < trackRunEnd; i++) {
// Use trun values if present, otherwise tfhd, otherwise trex.
int sampleDuration = sampleDurationsPresent ? trun.readUnsignedIntToInt()
: defaultSampleValues.duration;
int sampleSize = sampleSizesPresent ? trun.readUnsignedIntToInt() : defaultSampleValues.size;
int sampleDuration =
checkNonNegative(sampleDurationsPresent ? trun.readInt() : defaultSampleValues.duration);
int sampleSize =
checkNonNegative(sampleSizesPresent ? trun.readInt() : defaultSampleValues.size);
int sampleFlags = (i == 0 && firstSampleFlagsPresent) ? firstSampleFlags
: sampleFlagsPresent ? trun.readInt() : defaultSampleValues.flags;
if (sampleCompositionTimeOffsetsPresent) {
@ -1000,6 +1015,13 @@ public class FragmentedMp4Extractor implements Extractor {
return trackRunEnd;
}
private static int checkNonNegative(int value) throws ParserException {
if (value < 0) {
throw new ParserException("Unexpected negtive value: " + value);
}
return value;
}
private static void parseUuid(ParsableByteArray uuid, TrackFragment out,
byte[] extendedTypeScratch) throws ParserException {
uuid.setPosition(Atom.HEADER_SIZE);