TsExtractor: handle packets without PTS
#minor-release Issue: #9294 PiperOrigin-RevId: 392844983
This commit is contained in:
parent
654a320792
commit
97466ab779
@ -11,6 +11,9 @@
|
||||
* Deprecate `SimpleExoPlayer.Builder`. Use `ExoPlayer.Builder` instead.
|
||||
* Fix track selection in `StyledPlayerControlView` when using
|
||||
`ForwardingPlayer`.
|
||||
* Extractors:
|
||||
* Support TS packets without PTS flag
|
||||
([#9294](https://github.com/google/ExoPlayer/issues/9294)).
|
||||
* Android 12 compatibility:
|
||||
* Disable platform transcoding when playing content URIs on Android 12.
|
||||
* Add `ExoPlayer.setVideoChangeFrameRateStrategy` to allow disabling of
|
||||
|
@ -102,12 +102,14 @@ public final class CeaUtil {
|
||||
for (TrackOutput output : outputs) {
|
||||
ccDataBuffer.setPosition(sampleStartPosition);
|
||||
output.sampleData(ccDataBuffer, sampleLength);
|
||||
if (presentationTimeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(
|
||||
presentationTimeUs,
|
||||
C.BUFFER_FLAG_KEY_FRAME,
|
||||
sampleLength,
|
||||
/* offset= */ 0,
|
||||
/* encryptionData= */ null);
|
||||
/* cryptoData= */ null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
||||
headerScratchBits = new ParsableBitArray(new byte[HEADER_SIZE]);
|
||||
headerScratchBytes = new ParsableByteArray(headerScratchBits.data);
|
||||
state = STATE_FINDING_SYNC;
|
||||
timeUs = C.TIME_UNSET;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
@ -93,6 +94,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
||||
state = STATE_FINDING_SYNC;
|
||||
bytesRead = 0;
|
||||
lastByteWas0B = false;
|
||||
timeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,8 +106,10 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -133,8 +137,10 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
||||
output.sampleData(data, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
if (bytesRead == sampleSize) {
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
timeUs += sampleDurationUs;
|
||||
}
|
||||
state = STATE_FINDING_SYNC;
|
||||
}
|
||||
break;
|
||||
|
@ -87,6 +87,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
||||
bytesRead = 0;
|
||||
lastByteWasAC = false;
|
||||
hasCRC = false;
|
||||
timeUs = C.TIME_UNSET;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
@ -96,6 +97,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
||||
bytesRead = 0;
|
||||
lastByteWasAC = false;
|
||||
hasCRC = false;
|
||||
timeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -107,8 +109,10 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -136,8 +140,10 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
||||
output.sampleData(data, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
if (bytesRead == sampleSize) {
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
timeUs += sampleDurationUs;
|
||||
}
|
||||
state = STATE_FINDING_SYNC;
|
||||
}
|
||||
break;
|
||||
|
@ -114,6 +114,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
||||
firstFrameVersion = VERSION_UNSET;
|
||||
firstFrameSampleRateIndex = C.INDEX_UNSET;
|
||||
sampleDurationUs = C.TIME_UNSET;
|
||||
timeUs = C.TIME_UNSET;
|
||||
this.exposeId3 = exposeId3;
|
||||
this.language = language;
|
||||
}
|
||||
@ -125,6 +126,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
timeUs = C.TIME_UNSET;
|
||||
resetSync();
|
||||
}
|
||||
|
||||
@ -149,8 +151,10 @@ public final class AdtsReader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) throws ParserException {
|
||||
@ -529,8 +533,10 @@ public final class AdtsReader implements ElementaryStreamReader {
|
||||
currentOutput.sampleData(data, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
if (bytesRead == sampleSize) {
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
currentOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
timeUs += currentSampleDuration;
|
||||
}
|
||||
setFindingSampleState();
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ public final class DtsReader implements ElementaryStreamReader {
|
||||
public DtsReader(@Nullable String language) {
|
||||
headerScratchBytes = new ParsableByteArray(new byte[HEADER_SIZE]);
|
||||
state = STATE_FINDING_SYNC;
|
||||
timeUs = C.TIME_UNSET;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
@ -74,6 +75,7 @@ public final class DtsReader implements ElementaryStreamReader {
|
||||
state = STATE_FINDING_SYNC;
|
||||
bytesRead = 0;
|
||||
syncBytes = 0;
|
||||
timeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,8 +87,10 @@ public final class DtsReader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -111,8 +115,10 @@ public final class DtsReader implements ElementaryStreamReader {
|
||||
output.sampleData(data, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
if (bytesRead == sampleSize) {
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
timeUs += sampleDurationUs;
|
||||
}
|
||||
state = STATE_FINDING_SYNC;
|
||||
}
|
||||
break;
|
||||
|
@ -43,11 +43,13 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
|
||||
public DvbSubtitleReader(List<DvbSubtitleInfo> subtitleInfos) {
|
||||
this.subtitleInfos = subtitleInfos;
|
||||
outputs = new TrackOutput[subtitleInfos.size()];
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
writingSample = false;
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,7 +75,9 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
|
||||
return;
|
||||
}
|
||||
writingSample = true;
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
sampleTimeUs = pesTimeUs;
|
||||
}
|
||||
sampleBytesWritten = 0;
|
||||
bytesToCheck = 2;
|
||||
}
|
||||
@ -81,9 +85,11 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
|
||||
@Override
|
||||
public void packetFinished() {
|
||||
if (writingSample) {
|
||||
if (sampleTimeUs != C.TIME_UNSET) {
|
||||
for (TrackOutput output : outputs) {
|
||||
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
|
||||
}
|
||||
}
|
||||
writingSample = false;
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +87,8 @@ public final class H262Reader implements ElementaryStreamReader {
|
||||
userData = null;
|
||||
userDataParsable = null;
|
||||
}
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -98,6 +100,8 @@ public final class H262Reader implements ElementaryStreamReader {
|
||||
}
|
||||
totalBytesWritten = 0;
|
||||
startedFirstSample = false;
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -182,7 +186,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
||||
}
|
||||
if (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER) {
|
||||
int bytesWrittenPastStartCode = limit - startCodeOffset;
|
||||
if (startedFirstSample && sampleHasPicture && hasOutputFormat) {
|
||||
if (sampleHasPicture && hasOutputFormat && sampleTimeUs != C.TIME_UNSET) {
|
||||
// Output the sample.
|
||||
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode;
|
||||
@ -194,7 +198,9 @@ public final class H262Reader implements ElementaryStreamReader {
|
||||
sampleTimeUs =
|
||||
pesTimeUs != C.TIME_UNSET
|
||||
? pesTimeUs
|
||||
: (startedFirstSample ? (sampleTimeUs + frameDurationUs) : 0);
|
||||
: (sampleTimeUs != C.TIME_UNSET
|
||||
? (sampleTimeUs + frameDurationUs)
|
||||
: C.TIME_UNSET);
|
||||
sampleIsKeyframe = false;
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
startedFirstSample = true;
|
||||
|
@ -87,6 +87,7 @@ public final class H263Reader implements ElementaryStreamReader {
|
||||
this.userDataReader = userDataReader;
|
||||
prefixFlags = new boolean[4];
|
||||
csdBuffer = new CsdBuffer(128);
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
if (userDataReader != null) {
|
||||
userData = new NalUnitTargetBuffer(START_CODE_VALUE_USER_DATA, 128);
|
||||
userDataParsable = new ParsableByteArray();
|
||||
@ -107,6 +108,7 @@ public final class H263Reader implements ElementaryStreamReader {
|
||||
userData.reset();
|
||||
}
|
||||
totalBytesWritten = 0;
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -123,8 +125,10 @@ public final class H263Reader implements ElementaryStreamReader {
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
// TODO (Internal b/32267012): Consider using random access indicator.
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
this.pesTimeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -462,7 +466,10 @@ public final class H263Reader implements ElementaryStreamReader {
|
||||
}
|
||||
|
||||
public void onDataEnd(long position, int bytesWrittenPastPosition, boolean hasOutputFormat) {
|
||||
if (startCodeValue == START_CODE_VALUE_VOP && hasOutputFormat && readingSample) {
|
||||
if (startCodeValue == START_CODE_VALUE_VOP
|
||||
&& hasOutputFormat
|
||||
&& readingSample
|
||||
&& sampleTimeUs != C.TIME_UNSET) {
|
||||
int size = (int) (position - samplePosition);
|
||||
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
output.sampleMetadata(
|
||||
|
@ -86,6 +86,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
||||
sps = new NalUnitTargetBuffer(NAL_UNIT_TYPE_SPS, 128);
|
||||
pps = new NalUnitTargetBuffer(NAL_UNIT_TYPE_PPS, 128);
|
||||
sei = new NalUnitTargetBuffer(NAL_UNIT_TYPE_SEI, 128);
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
seiWrapper = new ParsableByteArray();
|
||||
}
|
||||
|
||||
@ -93,6 +94,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
||||
public void seek() {
|
||||
totalBytesWritten = 0;
|
||||
randomAccessIndicator = false;
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
NalUnitUtil.clearPrefixFlags(prefixFlags);
|
||||
sps.reset();
|
||||
pps.reset();
|
||||
@ -113,7 +115,9 @@ public final class H264Reader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
this.pesTimeUs = pesTimeUs;
|
||||
}
|
||||
randomAccessIndicator |= (flags & FLAG_RANDOM_ACCESS_INDICATOR) != 0;
|
||||
}
|
||||
|
||||
@ -495,6 +499,9 @@ public final class H264Reader implements ElementaryStreamReader {
|
||||
}
|
||||
|
||||
private void outputSample(int offset) {
|
||||
if (sampleTimeUs == C.TIME_UNSET) {
|
||||
return;
|
||||
}
|
||||
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
int size = (int) (nalUnitStartPosition - samplePosition);
|
||||
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
||||
|
@ -85,12 +85,14 @@ public final class H265Reader implements ElementaryStreamReader {
|
||||
pps = new NalUnitTargetBuffer(PPS_NUT, 128);
|
||||
prefixSei = new NalUnitTargetBuffer(PREFIX_SEI_NUT, 128);
|
||||
suffixSei = new NalUnitTargetBuffer(SUFFIX_SEI_NUT, 128);
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
seiWrapper = new ParsableByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
totalBytesWritten = 0;
|
||||
pesTimeUs = C.TIME_UNSET;
|
||||
NalUnitUtil.clearPrefixFlags(prefixFlags);
|
||||
vps.reset();
|
||||
sps.reset();
|
||||
@ -114,8 +116,10 @@ public final class H265Reader implements ElementaryStreamReader {
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
// TODO (Internal b/32267012): Consider using random access indicator.
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
this.pesTimeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -536,6 +540,9 @@ public final class H265Reader implements ElementaryStreamReader {
|
||||
}
|
||||
|
||||
private void outputSample(int offset) {
|
||||
if (sampleTimeUs == C.TIME_UNSET) {
|
||||
return;
|
||||
}
|
||||
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
int size = (int) (nalUnitPosition - samplePosition);
|
||||
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
||||
|
@ -49,11 +49,13 @@ public final class Id3Reader implements ElementaryStreamReader {
|
||||
|
||||
public Id3Reader() {
|
||||
id3Header = new ParsableByteArray(ID3_HEADER_LENGTH);
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
writingSample = false;
|
||||
sampleTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,7 +75,9 @@ public final class Id3Reader implements ElementaryStreamReader {
|
||||
return;
|
||||
}
|
||||
writingSample = true;
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
sampleTimeUs = pesTimeUs;
|
||||
}
|
||||
sampleSize = 0;
|
||||
sampleBytesRead = 0;
|
||||
}
|
||||
@ -120,7 +124,9 @@ public final class Id3Reader implements ElementaryStreamReader {
|
||||
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
|
||||
return;
|
||||
}
|
||||
if (sampleTimeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||
}
|
||||
writingSample = false;
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +78,13 @@ public final class LatmReader implements ElementaryStreamReader {
|
||||
this.language = language;
|
||||
sampleDataBuffer = new ParsableByteArray(INITIAL_BUFFER_SIZE);
|
||||
sampleBitArray = new ParsableBitArray(sampleDataBuffer.getData());
|
||||
timeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
state = STATE_FINDING_SYNC_1;
|
||||
timeUs = C.TIME_UNSET;
|
||||
streamMuxRead = false;
|
||||
}
|
||||
|
||||
@ -95,8 +97,10 @@ public final class LatmReader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) throws ParserException {
|
||||
@ -306,9 +310,11 @@ public final class LatmReader implements ElementaryStreamReader {
|
||||
sampleDataBuffer.setPosition(0);
|
||||
}
|
||||
output.sampleData(sampleDataBuffer, muxLengthBytes);
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, muxLengthBytes, 0, null);
|
||||
timeUs += sampleDurationUs;
|
||||
}
|
||||
}
|
||||
|
||||
private void resetBufferForSize(int newSize) {
|
||||
sampleDataBuffer.reset(newSize);
|
||||
|
@ -69,6 +69,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
||||
headerScratch = new ParsableByteArray(4);
|
||||
headerScratch.getData()[0] = (byte) 0xFF;
|
||||
header = new MpegAudioUtil.Header();
|
||||
timeUs = C.TIME_UNSET;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
@ -77,6 +78,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
||||
state = STATE_FINDING_HEADER;
|
||||
frameBytesRead = 0;
|
||||
lastByteWasFF = false;
|
||||
timeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,8 +90,10 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
||||
|
||||
@Override
|
||||
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
|
||||
if (pesTimeUs != C.TIME_UNSET) {
|
||||
timeUs = pesTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
@ -227,8 +231,10 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeUs != C.TIME_UNSET) {
|
||||
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, frameSize, 0, null);
|
||||
timeUs += frameDurationUs;
|
||||
}
|
||||
frameBytesRead = 0;
|
||||
state = STATE_FINDING_HEADER;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user