diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/CeaUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/CeaUtil.java index 8421d44605..58b7c45d52 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/CeaUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/CeaUtil.java @@ -15,6 +15,8 @@ */ package androidx.media3.extractor; +import static androidx.media3.common.util.Assertions.checkState; + import androidx.media3.common.C; import androidx.media3.common.util.Log; import androidx.media3.common.util.ParsableByteArray; @@ -104,14 +106,13 @@ 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, - /* cryptoData= */ null); - } + checkState(presentationTimeUs != C.TIME_UNSET); + output.sampleMetadata( + presentationTimeUs, + C.BUFFER_FLAG_KEY_FRAME, + sampleLength, + /* offset= */ 0, + /* cryptoData= */ null); } } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac3Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac3Reader.java index e5ce22e44d..fe69bff1f0 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac3Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac3Reader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import static java.lang.annotation.ElementType.TYPE_USE; @@ -112,9 +113,7 @@ public final class Ac3Reader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -143,10 +142,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; - } + // packetStarted method must be called before reading samples. + checkState(timeUs != C.TIME_UNSET); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); + timeUs += sampleDurationUs; state = STATE_FINDING_SYNC; } break; diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac4Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac4Reader.java index 5947a29132..5c967d724f 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac4Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Ac4Reader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import static java.lang.annotation.ElementType.TYPE_USE; @@ -114,9 +115,7 @@ public final class Ac4Reader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -145,10 +144,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; - } + // packetStarted method must be called before reading samples. + checkState(timeUs != C.TIME_UNSET); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); + timeUs += sampleDurationUs; state = STATE_FINDING_SYNC; } break; diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/AdtsReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/AdtsReader.java index de80f047d6..836c46d5f9 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/AdtsReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/AdtsReader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import androidx.annotation.Nullable; @@ -155,9 +156,7 @@ public final class AdtsReader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -537,10 +536,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; - } + // packetStarted method must be called before reading samples. + checkState(timeUs != C.TIME_UNSET); + currentOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); + timeUs += currentSampleDuration; setFindingSampleState(); } } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DtsReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DtsReader.java index c28faf501d..7dd515ce66 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DtsReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DtsReader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import androidx.annotation.Nullable; @@ -89,9 +90,7 @@ public final class DtsReader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -117,10 +116,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; - } + // packetStarted method must be called before consuming samples. + checkState(timeUs != C.TIME_UNSET); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); + timeUs += sampleDurationUs; state = STATE_FINDING_SYNC; } break; diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DvbSubtitleReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DvbSubtitleReader.java index 5de21926f7..02d111c855 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DvbSubtitleReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/DvbSubtitleReader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.extractor.ts.TsPayloadReader.FLAG_DATA_ALIGNMENT_INDICATOR; import androidx.media3.common.C; @@ -79,9 +80,7 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { return; } writingSample = true; - if (pesTimeUs != C.TIME_UNSET) { - sampleTimeUs = pesTimeUs; - } + sampleTimeUs = pesTimeUs; sampleBytesWritten = 0; bytesToCheck = 2; } @@ -89,10 +88,10 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { @Override public void packetFinished(boolean isEndOfInput) { if (writingSample) { - if (sampleTimeUs != C.TIME_UNSET) { - for (TrackOutput output : outputs) { - output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null); - } + // packetStarted method must be called before reading sample. + checkState(sampleTimeUs != C.TIME_UNSET); + for (TrackOutput output : outputs) { + output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null); } writingSample = false; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/ElementaryStreamReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/ElementaryStreamReader.java index 3d60db839c..a6decc12a2 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/ElementaryStreamReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/ElementaryStreamReader.java @@ -21,7 +21,20 @@ import androidx.media3.common.util.UnstableApi; import androidx.media3.extractor.ExtractorOutput; import androidx.media3.extractor.TrackOutput; -/** Extracts individual samples from an elementary media stream, preserving original order. */ +/** + * Extracts individual samples from an elementary media stream, preserving original order. + * + *

The expected sequence of method calls is as follows: + * + *

    + *
  1. {@link #createTracks(ExtractorOutput, PesReader.TrackIdGenerator)} (once at initialization) + *
  2. {@link #seek()} (optional, to reset the state) + *
  3. {@link #packetStarted(long, int)} (to signal the start of a new packet) + *
  4. {@link #consume(ParsableByteArray)} (zero or more times, to provide packet data) + *
  5. {@link #packetFinished(boolean)} (to signal the end of the current packet) + *
  6. Repeat steps 3-5 for subsequent packets + *
+ */ @UnstableApi public interface ElementaryStreamReader { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H263Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H263Reader.java index 302dd500e8..5c9d03eab9 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H263Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H263Reader.java @@ -16,6 +16,7 @@ package androidx.media3.extractor.ts; import static androidx.media3.common.util.Assertions.checkNotNull; +import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Util.castNonNull; import static java.lang.annotation.ElementType.TYPE_USE; @@ -130,9 +131,7 @@ 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; - } + this.pesTimeUs = pesTimeUs; } @Override @@ -479,10 +478,9 @@ public final class H263Reader implements ElementaryStreamReader { } public void onDataEnd(long position, int bytesWrittenPastPosition, boolean hasOutputFormat) { - if (startCodeValue == START_CODE_VALUE_VOP - && hasOutputFormat - && readingSample - && sampleTimeUs != C.TIME_UNSET) { + // packetStarted method must be called before reading sample. + checkState(sampleTimeUs != C.TIME_UNSET); + if (startCodeValue == START_CODE_VALUE_VOP && hasOutputFormat && readingSample) { int size = (int) (position - samplePosition); @C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; output.sampleMetadata( diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java index 07786a4ba5..4445af067a 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H264Reader.java @@ -114,9 +114,7 @@ public final class H264Reader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - this.pesTimeUs = pesTimeUs; - } + this.pesTimeUs = pesTimeUs; randomAccessIndicator |= (flags & FLAG_RANDOM_ACCESS_INDICATOR) != 0; } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H265Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H265Reader.java index 040ed9fb9b..7d265852a6 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H265Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/H265Reader.java @@ -117,9 +117,7 @@ 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; - } + this.pesTimeUs = pesTimeUs; } @Override diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Id3Reader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Id3Reader.java index 3d903ffbba..002dd33657 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Id3Reader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/Id3Reader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.extractor.metadata.id3.Id3Decoder.ID3_HEADER_LENGTH; import static androidx.media3.extractor.ts.TsPayloadReader.FLAG_DATA_ALIGNMENT_INDICATOR; import static java.lang.Math.min; @@ -77,9 +78,7 @@ public final class Id3Reader implements ElementaryStreamReader { return; } writingSample = true; - if (pesTimeUs != C.TIME_UNSET) { - sampleTimeUs = pesTimeUs; - } + sampleTimeUs = pesTimeUs; sampleSize = 0; sampleBytesRead = 0; } @@ -126,9 +125,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); - } + // packetStarted method must be called before consuming samples. + checkState(sampleTimeUs != C.TIME_UNSET); + output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null); writingSample = false; } } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/LatmReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/LatmReader.java index d51c50dcca..59612473f0 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/LatmReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/LatmReader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import androidx.annotation.Nullable; @@ -101,9 +102,7 @@ public final class LatmReader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -314,10 +313,10 @@ 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; - } + // packetStarted method must be called before consuming samples. + checkState(timeUs != C.TIME_UNSET); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, muxLengthBytes, 0, null); + timeUs += sampleDurationUs; } private void resetBufferForSize(int newSize) { diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpegAudioReader.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpegAudioReader.java index 550eae2906..c17f7a942f 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpegAudioReader.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ts/MpegAudioReader.java @@ -15,6 +15,7 @@ */ package androidx.media3.extractor.ts; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.Math.min; import androidx.annotation.Nullable; @@ -92,9 +93,7 @@ public final class MpegAudioReader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) { - if (pesTimeUs != C.TIME_UNSET) { - timeUs = pesTimeUs; - } + timeUs = pesTimeUs; } @Override @@ -233,10 +232,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; - } + // packetStarted method must be called before consuming samples. + checkState(timeUs != C.TIME_UNSET); + output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, frameSize, 0, null); + timeUs += frameDurationUs; frameBytesRead = 0; state = STATE_FINDING_HEADER; }