TsExtractor: handle packets without PTS

#minor-release
Issue: #9294
PiperOrigin-RevId: 392844983
This commit is contained in:
kimvde 2021-08-25 09:44:27 +01:00 committed by kim-vde
parent 654a320792
commit 97466ab779
14 changed files with 115 additions and 35 deletions

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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(

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}