Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix missing last frame of MPEG-TS content #419

Merged
merged 7 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
* Parse EXIF rotation data for image inputs.
* Track Selection:
* Extractors:
* MPEG-TS: Ensure the last frame is rendered by passing the last access
unit of a stream to the sample queue
([#7909](https://github.com/google/ExoPlayer/issues/7909)).
* Audio:
* Audio Offload:
* Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public void consume(ParsableByteArray data) throws ParserException {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
if (writingSample) {
if (sampleTimeUs != C.TIME_UNSET) {
for (TrackOutput output : outputs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ public interface ElementaryStreamReader {
void consume(ParsableByteArray data) throws ParserException;

/** Called when a packet ends. */
void packetFinished();
void packetFinished(boolean isEndOfInput);
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,13 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
// Do nothing.
public void packetFinished(boolean isEndOfInput) {
checkStateNotNull(output); // Asserts that createTracks has been called.
if (isEndOfInput) {
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
int size = (int) (totalBytesWritten - samplePosition);
output.sampleMetadata(sampleTimeUs, flags, size, /* offset= */ 0, /* cryptoData= */ null);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,13 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
// Do nothing.
public void packetFinished(boolean isEndOfInput) {
// Assert that createTracks has been called.
checkStateNotNull(sampleReader);
if (isEndOfInput) {
sampleReader.onDataEnd(totalBytesWritten, /* bytesWrittenPastPosition= */ 0, hasOutputFormat);
sampleReader.reset();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
// Do nothing.
public void packetFinished(boolean isEndOfInput) {
assertTracksCreated();
if (isEndOfInput) {
icbaker marked this conversation as resolved.
Show resolved Hide resolved
sampleReader.end(totalBytesWritten);
}
}

@RequiresNonNull("sampleReader")
Expand Down Expand Up @@ -500,6 +503,13 @@ private void outputSample(int offset) {
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
}

public void end(long position) {
// Output a final sample with the NAL units currently held
nalUnitStartPosition = position;
outputSample(/* offset= */ 0);
readingSample = false;
}

private static final class SliceHeaderData {

private static final int SLICE_TYPE_I = 2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,11 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
// Do nothing.
public void packetFinished(boolean isEndOfInput) {
assertTracksCreated();
if (isEndOfInput) {
sampleReader.end(totalBytesWritten);
}
}

@RequiresNonNull("sampleReader")
Expand Down Expand Up @@ -376,6 +379,13 @@ private void outputSample(int offset) {
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
}

public void end(long position) {
// Output a final sample with the NAL units currently held
nalUnitPosition = position;
outputSample(/* offset= */ 0);
readingSample = false;
}

/** Returns whether a NAL unit type is one that occurs before any VCL NAL units in a sample. */
private static boolean isPrefixNalUnit(int nalUnitType) {
return (VPS_NUT <= nalUnitType && nalUnitType <= AUD_NUT) || nalUnitType == PREFIX_SEI_NUT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public void consume(ParsableByteArray data) throws ParserException {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void consume(ParsableByteArray data) {
}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
// Do nothing.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ public final void consume(ParsableByteArray data, @Flags int flags) throws Parse
Log.w(TAG, "Unexpected start indicator: expected " + payloadSize + " more bytes");
}
// Either way, notify the reader that it has now finished.
reader.packetFinished();
boolean isEndOfInput = (data.limit() == 0);
reader.packetFinished(isEndOfInput);
break;
default:
throw new IllegalStateException();
Expand Down Expand Up @@ -147,7 +148,8 @@ && continueRead(data, /* target= */ null, extendedHeaderLength)) {
if (payloadSize != C.LENGTH_UNSET) {
payloadSize -= readLength;
if (payloadSize == 0) {
reader.packetFinished();
// There are bytes left in data, see above, so this is not the end of input
reader.packetFinished(/* isEndOfInput= */ false);
setState(STATE_READING_HEADER);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public void consume(ParsableByteArray data) throws ParserException {
pesPayloadReader.packetStarted(timeUs, TsPayloadReader.FLAG_DATA_ALIGNMENT_INDICATOR);
pesPayloadReader.consume(data);
// We always have complete PES packets with program stream.
pesPayloadReader.packetFinished();
pesPayloadReader.packetFinished(/* isEndOfInput= */ false);
}

private void parseHeader() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ public void release() {
}

if (!fillBufferWithAtLeastOnePacket(input)) {
// Send a synthesised empty pusi to allow for packetFinished to be triggered on the last unit.
for (int i = 0; i < tsPayloadReaders.size(); i++) {
TsPayloadReader payloadReader = tsPayloadReaders.valueAt(i);
if (payloadReader instanceof PesReader) {
payloadReader.consume(new ParsableByteArray(), FLAG_PAYLOAD_UNIT_START_INDICATOR);
}
}
return RESULT_END_OF_INPUT;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {}
public void consume(ParsableByteArray data) {}

@Override
public void packetFinished() {
public void packetFinished(boolean isEndOfInput) {
packetsRead++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 1
track 256:
total output bytes = 39002
sample count = 24
sample count = 25
format 0:
id = 1/256
sampleMimeType = video/mp4v-es
Expand Down Expand Up @@ -112,4 +112,8 @@ track 256:
time = 920000
flags = 0
data = length 222, hash 7E77BF79
sample 24:
time = 960000
flags = 1
data = length 11769, hash D94C80C0
tracksEnded = true
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 1
track 256:
total output bytes = 27354
sample count = 18
sample count = 19
format 0:
id = 1/256
sampleMimeType = video/mp4v-es
Expand Down Expand Up @@ -88,4 +88,8 @@ track 256:
time = 920000
flags = 0
data = length 222, hash 7E77BF79
sample 18:
time = 960000
flags = 1
data = length 11769, hash D94C80C0
tracksEnded = true
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 1
track 256:
total output bytes = 13592
sample count = 8
sample count = 9
format 0:
id = 1/256
sampleMimeType = video/mp4v-es
Expand Down Expand Up @@ -48,4 +48,8 @@ track 256:
time = 920000
flags = 0
data = length 222, hash 7E77BF79
sample 8:
time = 960000
flags = 1
data = length 11769, hash D94C80C0
tracksEnded = true
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ seekMap:
numberOfTracks = 1
track 256:
total output bytes = 39002
sample count = 24
sample count = 25
format 0:
id = 1/256
sampleMimeType = video/mp4v-es
Expand Down Expand Up @@ -109,4 +109,8 @@ track 256:
time = 920000
flags = 0
data = length 222, hash 7E77BF79
sample 24:
time = 960000
flags = 1
data = length 11769, hash D94C80C0
tracksEnded = true
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 2
track 256:
total output bytes = 13650
sample count = 2
sample count = 3
format 0:
id = 1/256
sampleMimeType = video/avc
Expand All @@ -26,6 +26,10 @@ track 256:
time = 100100
flags = 0
data = length 813, hash 99F7B4FA
sample 2:
time = 133466
flags = 0
data = length 442, hash A7367ECF
track 257:
total output bytes = 18432
sample count = 9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ seekMap:
numberOfTracks = 2
track 256:
total output bytes = 13650
sample count = 2
sample count = 3
format 0:
id = 1/256
sampleMimeType = video/avc
Expand All @@ -23,6 +23,10 @@ track 256:
time = 100100
flags = 0
data = length 813, hash 99F7B4FA
sample 2:
time = 133466
flags = 0
data = length 442, hash A7367ECF
track 257:
total output bytes = 18432
sample count = 9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 2
track 256:
total output bytes = 13650
sample count = 2
sample count = 3
format 0:
id = 1/256
sampleMimeType = video/avc
Expand All @@ -26,6 +26,10 @@ track 256:
time = 100100
flags = 0
data = length 813, hash 99F7B4FA
sample 2:
time = 133466
flags = 0
data = length 442, hash A7367ECF
track 257:
total output bytes = 5015
sample count = 4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ seekMap:
numberOfTracks = 2
track 256:
total output bytes = 13650
sample count = 2
sample count = 3
format 0:
id = 1/256
sampleMimeType = video/avc
Expand All @@ -26,6 +26,10 @@ track 256:
time = 100100
flags = 0
data = length 813, hash 99F7B4FA
sample 2:
time = 133466
flags = 0
data = length 442, hash A7367ECF
track 257:
total output bytes = 5015
sample count = 4
Expand Down