Skip to content

Commit

Permalink
Fix timestamp rounding error in fMP4 extractor.
Browse files Browse the repository at this point in the history
The sample timestamps are currently rounded to milliseconds, only to
be multiplied by 1000 later. This causes rounding errors where the sample
timestamps don't match the timestamps in the seek table (which are already
in microseconds).

issue:#7086
PiperOrigin-RevId: 307630559
  • Loading branch information
tonihei authored and ojw28 committed May 27, 2020
1 parent d970335 commit b954a5a
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 394 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -962,20 +962,20 @@ private static int parseTrun(

// Offset to the entire video timeline. In the presence of B-frames this is usually used to
// ensure that the first frame's presentation timestamp is zero.
long edtsOffset = 0;
long edtsOffsetUs = 0;

// Currently we only support a single edit that moves the entire media timeline (indicated by
// duration == 0). Other uses of edit lists are uncommon and unsupported.
if (track.editListDurations != null && track.editListDurations.length == 1
&& track.editListDurations[0] == 0) {
edtsOffset =
edtsOffsetUs =
Util.scaleLargeTimestamp(
track.editListMediaTimes[0], C.MILLIS_PER_SECOND, track.timescale);
track.editListMediaTimes[0], C.MICROS_PER_SECOND, track.timescale);
}

int[] sampleSizeTable = fragment.sampleSizeTable;
int[] sampleCompositionTimeOffsetTable = fragment.sampleCompositionTimeOffsetTable;
long[] sampleDecodingTimeTable = fragment.sampleDecodingTimeTable;
int[] sampleCompositionTimeOffsetUsTable = fragment.sampleCompositionTimeOffsetUsTable;
long[] sampleDecodingTimeUsTable = fragment.sampleDecodingTimeUsTable;
boolean[] sampleIsSyncFrameTable = fragment.sampleIsSyncFrameTable;

boolean workaroundEveryVideoFrameIsSyncFrame = track.type == C.TRACK_TYPE_VIDEO
Expand All @@ -999,13 +999,13 @@ private static int parseTrun(
// here, because unsigned integers will still be parsed correctly (unless their top bit is
// set, which is never true in practice because sample offsets are always small).
int sampleOffset = trun.readInt();
sampleCompositionTimeOffsetTable[i] =
(int) ((sampleOffset * C.MILLIS_PER_SECOND) / timescale);
sampleCompositionTimeOffsetUsTable[i] =
(int) ((sampleOffset * C.MICROS_PER_SECOND) / timescale);
} else {
sampleCompositionTimeOffsetTable[i] = 0;
sampleCompositionTimeOffsetUsTable[i] = 0;
}
sampleDecodingTimeTable[i] =
Util.scaleLargeTimestamp(cumulativeTime, C.MILLIS_PER_SECOND, timescale) - edtsOffset;
sampleDecodingTimeUsTable[i] =
Util.scaleLargeTimestamp(cumulativeTime, C.MICROS_PER_SECOND, timescale) - edtsOffsetUs;
sampleSizeTable[i] = sampleSize;
sampleIsSyncFrameTable[i] = ((sampleFlags >> 16) & 0x1) == 0
&& (!workaroundEveryVideoFrameIsSyncFrame || i == 0);
Expand Down Expand Up @@ -1291,7 +1291,7 @@ private boolean readSample(ExtractorInput input) throws IOException, Interrupted
Track track = currentTrackBundle.track;
TrackOutput output = currentTrackBundle.output;
int sampleIndex = currentTrackBundle.currentSampleIndex;
long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L;
long sampleTimeUs = fragment.getSamplePresentationTimeUs(sampleIndex);
if (timestampAdjuster != null) {
sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
}
Expand Down Expand Up @@ -1535,10 +1535,9 @@ public void reset() {
* @param timeUs The seek time, in microseconds.
*/
public void seek(long timeUs) {
long timeMs = C.usToMs(timeUs);
int searchIndex = currentSampleIndex;
while (searchIndex < fragment.sampleCount
&& fragment.getSamplePresentationTime(searchIndex) < timeMs) {
&& fragment.getSamplePresentationTimeUs(searchIndex) < timeUs) {
if (fragment.sampleIsSyncFrameTable[searchIndex]) {
firstSampleToOutputIndex = searchIndex;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,10 @@
* The size of each sample in the fragment.
*/
public int[] sampleSizeTable;
/**
* The composition time offset of each sample in the fragment.
*/
public int[] sampleCompositionTimeOffsetTable;
/**
* The decoding time of each sample in the fragment.
*/
public long[] sampleDecodingTimeTable;
/** The composition time offset of each sample in the fragment, in microseconds. */
public int[] sampleCompositionTimeOffsetUsTable;
/** The decoding time of each sample in the fragment, in microseconds. */
public long[] sampleDecodingTimeUsTable;
/**
* Indicates which samples are sync frames.
*/
Expand Down Expand Up @@ -139,8 +135,8 @@ public void initTables(int trunCount, int sampleCount) {
// likely. The choice of 25% is relatively arbitrary.
int tableSize = (sampleCount * 125) / 100;
sampleSizeTable = new int[tableSize];
sampleCompositionTimeOffsetTable = new int[tableSize];
sampleDecodingTimeTable = new long[tableSize];
sampleCompositionTimeOffsetUsTable = new int[tableSize];
sampleDecodingTimeUsTable = new long[tableSize];
sampleIsSyncFrameTable = new boolean[tableSize];
sampleHasSubsampleEncryptionTable = new boolean[tableSize];
}
Expand Down Expand Up @@ -186,8 +182,14 @@ public void fillEncryptionData(ParsableByteArray source) {
sampleEncryptionDataNeedsFill = false;
}

public long getSamplePresentationTime(int index) {
return sampleDecodingTimeTable[index] + sampleCompositionTimeOffsetTable[index];
/**
* Returns the sample presentation timestamp in microseconds.
*
* @param index The sample index.
* @return The presentation timestamps of this sample in microseconds.
*/
public long getSamplePresentationTimeUs(int index) {
return sampleDecodingTimeUsTable[index] + sampleCompositionTimeOffsetUsTable[index];
}

/** Returns whether the sample at the given index has a subsample encryption table. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ track 0:
flags = 1
data = length 520, hash FEE56928
sample 13:
time = 520000
time = 519999
flags = 1
data = length 599, hash 41F496C5
sample 14:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ track 0:
flags = 1
data = length 520, hash FEE56928
sample 7:
time = 520000
time = 519999
flags = 1
data = length 599, hash 41F496C5
sample 8:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ track 0:
flags = 1
data = length 520, hash FEE56928
sample 1:
time = 520000
time = 519999
flags = 1
data = length 599, hash 41F496C5
sample 2:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ track 0:
crypto mode = 1
encryption key = length 16, hash 9FDDEA52
sample 13:
time = 520000
time = 519999
flags = 1073741825
data = length 616, hash 3F657E23
crypto mode = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ track 0:
crypto mode = 1
encryption key = length 16, hash 9FDDEA52
sample 7:
time = 520000
time = 519999
flags = 1073741825
data = length 616, hash 3F657E23
crypto mode = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ track 0:
crypto mode = 1
encryption key = length 16, hash 9FDDEA52
sample 1:
time = 520000
time = 519999
flags = 1073741825
data = length 616, hash 3F657E23
crypto mode = 1
Expand Down
Loading

0 comments on commit b954a5a

Please sign in to comment.