Skip to content

Commit b771091

Browse files
committed
Workaround for TS seeking
- Increase the search window size to fix TS seeking for problematic media we've had provided to us. - As per my comments on the issue, we should look at doing more here to better fix the problem. This will solve the worst of the immediate problem, however. - The memory usage is non-trivial, particularly with the increased search window size. I've made the allocations only live whilst determining duration and seeking to address this. I've done the same for PS just for consistency. Issue: #5097 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=221449988
1 parent 5e6174f commit b771091

File tree

9 files changed

+72
-34
lines changed

9 files changed

+72
-34
lines changed

RELEASENOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
* DASH: Fix detecting the end of live events
66
([#4780](https://github.com/google/ExoPlayer/issues/4780)).
7+
* Support seeking for a wider range of MPEG-TS streams
8+
([#5097](https://github.com/google/ExoPlayer/issues/5097)).
79
* Support for playing spherical videos on Daydream.
810
* Improve decoder re-use between playbacks. TODO: Write and link a blog post
911
here ([#2826](https://github.com/google/ExoPlayer/issues/2826)).

library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ protected interface TimestampSeeker {
5858
TimestampSearchResult searchForTimestamp(
5959
ExtractorInput input, long targetTimestamp, OutputFrameHolder outputFrameHolder)
6060
throws IOException, InterruptedException;
61+
62+
/** Called when a seek operation finishes. */
63+
default void onSeekFinished() {}
6164
}
6265

6366
/**
@@ -256,6 +259,7 @@ protected SeekOperationParams createSeekParamsForTargetTimeUs(long timeUs) {
256259

257260
protected final void markSeekOperationFinished(boolean foundTargetFrame, long resultPosition) {
258261
seekOperationParams = null;
262+
timestampSeeker.onSeekFinished();
259263
onSeekOperationFinished(foundTargetFrame, resultPosition);
260264
}
261265

library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.android.exoplayer2.extractor.ExtractorInput;
2121
import com.google.android.exoplayer2.util.ParsableByteArray;
2222
import com.google.android.exoplayer2.util.TimestampAdjuster;
23+
import com.google.android.exoplayer2.util.Util;
2324
import java.io.IOException;
2425

2526
/**
@@ -64,7 +65,7 @@ private static final class PsScrSeeker implements TimestampSeeker {
6465

6566
private PsScrSeeker(TimestampAdjuster scrTimestampAdjuster) {
6667
this.scrTimestampAdjuster = scrTimestampAdjuster;
67-
packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES);
68+
packetBuffer = new ParsableByteArray();
6869
}
6970

7071
@Override
@@ -74,12 +75,17 @@ public TimestampSearchResult searchForTimestamp(
7475
long inputPosition = input.getPosition();
7576
int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - inputPosition);
7677

77-
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
7878
packetBuffer.reset(bytesToSearch);
79+
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
7980

8081
return searchForScrValueInBuffer(packetBuffer, targetTimestamp, inputPosition);
8182
}
8283

84+
@Override
85+
public void onSeekFinished() {
86+
packetBuffer.reset(Util.EMPTY_BYTE_ARRAY);
87+
}
88+
8389
private TimestampSearchResult searchForScrValueInBuffer(
8490
ParsableByteArray packetBuffer, long targetScrTimeUs, long bufferStartOffset) {
8591
int startOfLastPacketPosition = C.POSITION_UNSET;

library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.android.exoplayer2.extractor.PositionHolder;
2222
import com.google.android.exoplayer2.util.ParsableByteArray;
2323
import com.google.android.exoplayer2.util.TimestampAdjuster;
24+
import com.google.android.exoplayer2.util.Util;
2425
import java.io.IOException;
2526

2627
/**
@@ -56,7 +57,7 @@
5657
firstScrValue = C.TIME_UNSET;
5758
lastScrValue = C.TIME_UNSET;
5859
durationUs = C.TIME_UNSET;
59-
packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES);
60+
packetBuffer = new ParsableByteArray();
6061
}
6162

6263
/** Returns true if a PS duration has been read. */
@@ -129,6 +130,7 @@ public static long readScrValueFromPack(ParsableByteArray packetBuffer) {
129130
}
130131

131132
private int finishReadDuration(ExtractorInput input) {
133+
packetBuffer.reset(Util.EMPTY_BYTE_ARRAY);
132134
isDurationRead = true;
133135
input.resetPeekPosition();
134136
return Extractor.RESULT_CONTINUE;
@@ -143,9 +145,9 @@ private int readFirstScrValue(ExtractorInput input, PositionHolder seekPositionH
143145
return Extractor.RESULT_SEEK;
144146
}
145147

148+
packetBuffer.reset(bytesToSearch);
146149
input.resetPeekPosition();
147150
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
148-
packetBuffer.reset(bytesToSearch);
149151

150152
firstScrValue = readFirstScrValueFromBuffer(packetBuffer);
151153
isFirstScrValueRead = true;
@@ -180,9 +182,9 @@ private int readLastScrValue(ExtractorInput input, PositionHolder seekPositionHo
180182
return Extractor.RESULT_SEEK;
181183
}
182184

185+
packetBuffer.reset(bytesToSearch);
183186
input.resetPeekPosition();
184187
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
185-
packetBuffer.reset(bytesToSearch);
186188

187189
lastScrValue = readLastScrValueFromBuffer(packetBuffer);
188190
isLastScrValueRead = true;

library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.android.exoplayer2.extractor.ExtractorInput;
2121
import com.google.android.exoplayer2.util.ParsableByteArray;
2222
import com.google.android.exoplayer2.util.TimestampAdjuster;
23+
import com.google.android.exoplayer2.util.Util;
2324
import java.io.IOException;
2425

2526
/**
@@ -34,7 +35,7 @@
3435

3536
private static final long SEEK_TOLERANCE_US = 100_000;
3637
private static final int MINIMUM_SEARCH_RANGE_BYTES = 5 * TsExtractor.TS_PACKET_SIZE;
37-
private static final int TIMESTAMP_SEARCH_BYTES = 200 * TsExtractor.TS_PACKET_SIZE;
38+
private static final int TIMESTAMP_SEARCH_BYTES = 600 * TsExtractor.TS_PACKET_SIZE;
3839

3940
public TsBinarySearchSeeker(
4041
TimestampAdjuster pcrTimestampAdjuster, long streamDurationUs, long inputLength, int pcrPid) {
@@ -68,7 +69,7 @@ private static final class TsPcrSeeker implements TimestampSeeker {
6869
public TsPcrSeeker(int pcrPid, TimestampAdjuster pcrTimestampAdjuster) {
6970
this.pcrPid = pcrPid;
7071
this.pcrTimestampAdjuster = pcrTimestampAdjuster;
71-
packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES);
72+
packetBuffer = new ParsableByteArray();
7273
}
7374

7475
@Override
@@ -78,8 +79,8 @@ public TimestampSearchResult searchForTimestamp(
7879
long inputPosition = input.getPosition();
7980
int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - inputPosition);
8081

81-
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
8282
packetBuffer.reset(bytesToSearch);
83+
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
8384

8485
return searchForPcrValueInBuffer(packetBuffer, targetTimestamp, inputPosition);
8586
}
@@ -131,5 +132,10 @@ private TimestampSearchResult searchForPcrValueInBuffer(
131132
return TimestampSearchResult.NO_TIMESTAMP_IN_RANGE_RESULT;
132133
}
133134
}
135+
136+
@Override
137+
public void onSeekFinished() {
138+
packetBuffer.reset(Util.EMPTY_BYTE_ARRAY);
139+
}
134140
}
135141
}

library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.android.exoplayer2.extractor.PositionHolder;
2222
import com.google.android.exoplayer2.util.ParsableByteArray;
2323
import com.google.android.exoplayer2.util.TimestampAdjuster;
24+
import com.google.android.exoplayer2.util.Util;
2425
import java.io.IOException;
2526

2627
/**
@@ -35,7 +36,7 @@
3536
*/
3637
/* package */ final class TsDurationReader {
3738

38-
private static final int TIMESTAMP_SEARCH_BYTES = 200 * TsExtractor.TS_PACKET_SIZE;
39+
private static final int TIMESTAMP_SEARCH_BYTES = 600 * TsExtractor.TS_PACKET_SIZE;
3940

4041
private final TimestampAdjuster pcrTimestampAdjuster;
4142
private final ParsableByteArray packetBuffer;
@@ -53,7 +54,7 @@
5354
firstPcrValue = C.TIME_UNSET;
5455
lastPcrValue = C.TIME_UNSET;
5556
durationUs = C.TIME_UNSET;
56-
packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES);
57+
packetBuffer = new ParsableByteArray();
5758
}
5859

5960
/** Returns true if a TS duration has been read. */
@@ -116,6 +117,7 @@ public TimestampAdjuster getPcrTimestampAdjuster() {
116117
}
117118

118119
private int finishReadDuration(ExtractorInput input) {
120+
packetBuffer.reset(Util.EMPTY_BYTE_ARRAY);
119121
isDurationRead = true;
120122
input.resetPeekPosition();
121123
return Extractor.RESULT_CONTINUE;
@@ -130,9 +132,9 @@ private int readFirstPcrValue(ExtractorInput input, PositionHolder seekPositionH
130132
return Extractor.RESULT_SEEK;
131133
}
132134

135+
packetBuffer.reset(bytesToSearch);
133136
input.resetPeekPosition();
134137
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
135-
packetBuffer.reset(bytesToSearch);
136138

137139
firstPcrValue = readFirstPcrValueFromBuffer(packetBuffer, pcrPid);
138140
isFirstPcrValueRead = true;
@@ -166,9 +168,9 @@ private int readLastPcrValue(ExtractorInput input, PositionHolder seekPositionHo
166168
return Extractor.RESULT_SEEK;
167169
}
168170

171+
packetBuffer.reset(bytesToSearch);
169172
input.resetPeekPosition();
170173
input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch);
171-
packetBuffer.reset(bytesToSearch);
172174

173175
lastPcrValue = readLastPcrValueFromBuffer(packetBuffer, pcrPid);
174176
isLastPcrValueRead = true;

library/core/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ public ParsableByteArray(byte[] data, int limit) {
6767
this.limit = limit;
6868
}
6969

70+
/** Sets the position and limit to zero. */
71+
public void reset() {
72+
position = 0;
73+
limit = 0;
74+
}
75+
7076
/**
7177
* Resets the position to zero and the limit to the specified value. If the limit exceeds the
7278
* capacity, {@code data} is replaced with a new array of sufficient size.
@@ -77,6 +83,16 @@ public void reset(int limit) {
7783
reset(capacity() < limit ? new byte[limit] : data, limit);
7884
}
7985

86+
/**
87+
* Updates the instance to wrap {@code data}, and resets the position to zero and the limit to
88+
* {@code data.length}.
89+
*
90+
* @param data The array to wrap.
91+
*/
92+
public void reset(byte[] data) {
93+
reset(data, data.length);
94+
}
95+
8096
/**
8197
* Updates the instance to wrap {@code data}, and resets the position to zero.
8298
*
@@ -89,14 +105,6 @@ public void reset(byte[] data, int limit) {
89105
position = 0;
90106
}
91107

92-
/**
93-
* Sets the position and limit to zero.
94-
*/
95-
public void reset() {
96-
position = 0;
97-
limit = 0;
98-
}
99-
100108
/**
101109
* Returns the number of bytes yet to be read.
102110
*/

library/core/src/test/assets/ts/sample.ts.1.dump

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ track 256:
2626
drmInitData = -
2727
initializationData:
2828
data = length 22, hash CE183139
29-
total output bytes = 24315
30-
sample count = 1
29+
total output bytes = 45026
30+
sample count = 2
3131
sample 0:
32-
time = 55611
32+
time = 55610
33+
flags = 1
34+
data = length 20711, hash 34341E8
35+
sample 1:
36+
time = 88977
3337
flags = 0
3438
data = length 18112, hash EC44B35B
3539
track 257:
@@ -57,19 +61,19 @@ track 257:
5761
total output bytes = 5015
5862
sample count = 4
5963
sample 0:
60-
time = 11333
64+
time = 44699
6165
flags = 1
6266
data = length 1253, hash 727FD1C6
6367
sample 1:
64-
time = 37455
68+
time = 70821
6569
flags = 1
6670
data = length 1254, hash 73FB07B8
6771
sample 2:
68-
time = 63578
72+
time = 96944
6973
flags = 1
7074
data = length 1254, hash 73FB07B8
7175
sample 3:
72-
time = 89700
76+
time = 123066
7377
flags = 1
7478
data = length 1254, hash 73FB07B8
7579
track 8448:

library/core/src/test/assets/ts/sample.ts.2.dump

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ track 256:
2626
drmInitData = -
2727
initializationData:
2828
data = length 22, hash CE183139
29-
total output bytes = 24315
30-
sample count = 1
29+
total output bytes = 45026
30+
sample count = 2
3131
sample 0:
32-
time = 77855
32+
time = 77854
33+
flags = 1
34+
data = length 20711, hash 34341E8
35+
sample 1:
36+
time = 111221
3337
flags = 0
3438
data = length 18112, hash EC44B35B
3539
track 257:
@@ -57,19 +61,19 @@ track 257:
5761
total output bytes = 5015
5862
sample count = 4
5963
sample 0:
60-
time = 33577
64+
time = 66943
6165
flags = 1
6266
data = length 1253, hash 727FD1C6
6367
sample 1:
64-
time = 59699
68+
time = 93065
6569
flags = 1
6670
data = length 1254, hash 73FB07B8
6771
sample 2:
68-
time = 85822
72+
time = 119188
6973
flags = 1
7074
data = length 1254, hash 73FB07B8
7175
sample 3:
72-
time = 111944
76+
time = 145310
7377
flags = 1
7478
data = length 1254, hash 73FB07B8
7579
track 8448:

0 commit comments

Comments
 (0)