Commit 95aa5db1 by tonihei Committed by Oliver Woodman

Reenable edit lists without keyframe again but remove samples before keyframe.

Ignoring all edit lists if they don't start with a keyframe causes A/V sync
issues when valid edit lists are applied at the beginning.

This change allows such edit lists again but removes all samples before the
first keyframe (these samples would be ignored by the renderer anyway if at
the beginning OR cause visible distortions when appended to an unrelated
keyframe).

Issue:#4774
Issue:#4348

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=212244407
parent 1a800973
...@@ -120,6 +120,8 @@ ...@@ -120,6 +120,8 @@
[#4634](https://github.com/google/ExoPlayer/issues/4634)). [#4634](https://github.com/google/ExoPlayer/issues/4634)).
* Fix issue where errors of upcoming playlist items are thrown too early * Fix issue where errors of upcoming playlist items are thrown too early
([#4661](https://github.com/google/ExoPlayer/issues/4661)). ([#4661](https://github.com/google/ExoPlayer/issues/4661)).
* Allow edit lists which do not start with a sync sample.
([#4774](https://github.com/google/ExoPlayer/issues/4774)).
* IMA extension: * IMA extension:
* Refine the previous fix for empty ad groups to avoid discarding ad breaks * Refine the previous fix for empty ad groups to avoid discarding ad breaks
unnecessarily ([#4030](https://github.com/google/ExoPlayer/issues/4030)), unnecessarily ([#4030](https://github.com/google/ExoPlayer/issues/4030)),
......
...@@ -382,19 +382,29 @@ import java.util.List; ...@@ -382,19 +382,29 @@ import java.util.List;
int editedSampleCount = 0; int editedSampleCount = 0;
int nextSampleIndex = 0; int nextSampleIndex = 0;
boolean copyMetadata = false; boolean copyMetadata = false;
int[] startIndices = new int[track.editListDurations.length];
int[] endIndices = new int[track.editListDurations.length];
for (int i = 0; i < track.editListDurations.length; i++) { for (int i = 0; i < track.editListDurations.length; i++) {
long editMediaTime = track.editListMediaTimes[i]; long editMediaTime = track.editListMediaTimes[i];
if (editMediaTime != -1) { if (editMediaTime != -1) {
long editDuration = long editDuration =
Util.scaleLargeTimestamp( Util.scaleLargeTimestamp(
track.editListDurations[i], track.timescale, track.movieTimescale); track.editListDurations[i], track.timescale, track.movieTimescale);
int startIndex = Util.binarySearchCeil(timestamps, editMediaTime, true, true); startIndices[i] = Util.binarySearchCeil(timestamps, editMediaTime, true, true);
int endIndex = endIndices[i] =
Util.binarySearchCeil( Util.binarySearchCeil(
timestamps, editMediaTime + editDuration, omitClippedSample, false); timestamps, editMediaTime + editDuration, omitClippedSample, false);
editedSampleCount += endIndex - startIndex; while (startIndices[i] < endIndices[i]
copyMetadata |= nextSampleIndex != startIndex; && (flags[startIndices[i]] & C.BUFFER_FLAG_KEY_FRAME) == 0) {
nextSampleIndex = endIndex; // Applying the edit correctly would require prerolling from the previous sync sample. In
// the current implementation we advance to the next sync sample instead. Only other
// tracks (i.e. audio) will be rendered until the time of the first sync sample.
// See https://github.com/google/ExoPlayer/issues/1659.
startIndices[i]++;
}
editedSampleCount += endIndices[i] - startIndices[i];
copyMetadata |= nextSampleIndex != startIndices[i];
nextSampleIndex = endIndices[i];
} }
} }
copyMetadata |= editedSampleCount != sampleCount; copyMetadata |= editedSampleCount != sampleCount;
...@@ -409,37 +419,26 @@ import java.util.List; ...@@ -409,37 +419,26 @@ import java.util.List;
int sampleIndex = 0; int sampleIndex = 0;
for (int i = 0; i < track.editListDurations.length; i++) { for (int i = 0; i < track.editListDurations.length; i++) {
long editMediaTime = track.editListMediaTimes[i]; long editMediaTime = track.editListMediaTimes[i];
long editDuration = track.editListDurations[i]; int startIndex = startIndices[i];
if (editMediaTime != -1) { int endIndex = endIndices[i];
long endMediaTime = if (copyMetadata) {
editMediaTime int count = endIndex - startIndex;
+ Util.scaleLargeTimestamp(editDuration, track.timescale, track.movieTimescale); System.arraycopy(offsets, startIndex, editedOffsets, sampleIndex, count);
int startIndex = Util.binarySearchCeil(timestamps, editMediaTime, true, true); System.arraycopy(sizes, startIndex, editedSizes, sampleIndex, count);
int endIndex = Util.binarySearchCeil(timestamps, endMediaTime, omitClippedSample, false); System.arraycopy(flags, startIndex, editedFlags, sampleIndex, count);
if (copyMetadata) { }
int count = endIndex - startIndex; for (int j = startIndex; j < endIndex; j++) {
System.arraycopy(offsets, startIndex, editedOffsets, sampleIndex, count); long ptsUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.movieTimescale);
System.arraycopy(sizes, startIndex, editedSizes, sampleIndex, count); long timeInSegmentUs =
System.arraycopy(flags, startIndex, editedFlags, sampleIndex, count); Util.scaleLargeTimestamp(
} timestamps[j] - editMediaTime, C.MICROS_PER_SECOND, track.timescale);
if (startIndex < endIndex && (editedFlags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) == 0) { editedTimestamps[sampleIndex] = ptsUs + timeInSegmentUs;
// Applying the edit list would require prerolling from a sync sample. if (copyMetadata && editedSizes[sampleIndex] > editedMaximumSize) {
Log.w(TAG, "Ignoring edit list: edit does not start with a sync sample."); editedMaximumSize = sizes[j];
throw new UnhandledEditListException();
}
for (int j = startIndex; j < endIndex; j++) {
long ptsUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.movieTimescale);
long timeInSegmentUs =
Util.scaleLargeTimestamp(
timestamps[j] - editMediaTime, C.MICROS_PER_SECOND, track.timescale);
editedTimestamps[sampleIndex] = ptsUs + timeInSegmentUs;
if (copyMetadata && editedSizes[sampleIndex] > editedMaximumSize) {
editedMaximumSize = sizes[j];
}
sampleIndex++;
} }
sampleIndex++;
} }
pts += editDuration; pts += track.editListDurations[i];
} }
long editedDurationUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.timescale); long editedDurationUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.timescale);
return new TrackSampleTable( return new TrackSampleTable(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment