mirror of
https://github.com/samsonjs/media.git
synced 2026-04-04 11:05:47 +00:00
Add package level NonNull to extractor.ts
Also remove most classes from the nullness blacklist PiperOrigin-RevId: 288494712
This commit is contained in:
parent
fb42f818ec
commit
63f90adef0
23 changed files with 307 additions and 139 deletions
|
|
@ -81,7 +81,10 @@ public final class DtsUtil {
|
|||
* @return The DTS format parsed from data in the header.
|
||||
*/
|
||||
public static Format parseDtsFormat(
|
||||
byte[] frame, String trackId, @Nullable String language, @Nullable DrmInitData drmInitData) {
|
||||
byte[] frame,
|
||||
@Nullable String trackId,
|
||||
@Nullable String language,
|
||||
@Nullable DrmInitData drmInitData) {
|
||||
ParsableBitArray frameBits = getNormalizedFrameHeader(frame);
|
||||
frameBits.skipBits(32 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE
|
||||
int amode = frameBits.readBits(6);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.Ac3Util;
|
||||
|
|
@ -23,11 +24,15 @@ import com.google.android.exoplayer2.audio.Ac3Util.SyncFrameInfo;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous (E-)AC-3 byte stream and extracts individual samples.
|
||||
|
|
@ -47,10 +52,10 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
|
||||
private final ParsableBitArray headerScratchBits;
|
||||
private final ParsableByteArray headerScratchBytes;
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
|
||||
private String trackFormatId;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
|
||||
@State private int state;
|
||||
private int bytesRead;
|
||||
|
|
@ -60,7 +65,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
|
||||
// Used when parsing the header.
|
||||
private long sampleDurationUs;
|
||||
private Format format;
|
||||
@MonotonicNonNull private Format format;
|
||||
private int sampleSize;
|
||||
|
||||
// Used when reading the samples.
|
||||
|
|
@ -78,7 +83,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
*
|
||||
* @param language Track language.
|
||||
*/
|
||||
public Ac3Reader(String language) {
|
||||
public Ac3Reader(@Nullable String language) {
|
||||
headerScratchBits = new ParsableBitArray(new byte[HEADER_SIZE]);
|
||||
headerScratchBytes = new ParsableByteArray(headerScratchBits.data);
|
||||
state = STATE_FINDING_SYNC;
|
||||
|
|
@ -95,7 +100,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
@Override
|
||||
public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator generator) {
|
||||
generator.generateNewId();
|
||||
trackFormatId = generator.getFormatId();
|
||||
formatId = generator.getFormatId();
|
||||
output = extractorOutput.track(generator.getTrackId(), C.TRACK_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +111,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_SYNC:
|
||||
|
|
@ -185,19 +191,28 @@ public final class Ac3Reader implements ElementaryStreamReader {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the sample header.
|
||||
*/
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
/** Parses the sample header. */
|
||||
@RequiresNonNull("output")
|
||||
private void parseHeader() {
|
||||
headerScratchBits.setPosition(0);
|
||||
SyncFrameInfo frameInfo = Ac3Util.parseAc3SyncframeInfo(headerScratchBits);
|
||||
if (format == null || frameInfo.channelCount != format.channelCount
|
||||
if (format == null
|
||||
|| frameInfo.channelCount != format.channelCount
|
||||
|| frameInfo.sampleRate != format.sampleRate
|
||||
|| frameInfo.mimeType != format.sampleMimeType) {
|
||||
format = Format.createAudioSampleFormat(trackFormatId, frameInfo.mimeType, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, frameInfo.channelCount, frameInfo.sampleRate, null,
|
||||
null, 0, language);
|
||||
|| Util.areEqual(frameInfo.mimeType, format.sampleMimeType)) {
|
||||
format =
|
||||
Format.createAudioSampleFormat(
|
||||
formatId,
|
||||
frameInfo.mimeType,
|
||||
null,
|
||||
Format.NO_VALUE,
|
||||
Format.NO_VALUE,
|
||||
frameInfo.channelCount,
|
||||
frameInfo.sampleRate,
|
||||
null,
|
||||
null,
|
||||
0,
|
||||
language);
|
||||
output.format(format);
|
||||
}
|
||||
sampleSize = frameInfo.frameSize;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.Ac4Util;
|
||||
|
|
@ -23,12 +24,15 @@ import com.google.android.exoplayer2.audio.Ac4Util.SyncFrameInfo;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/** Parses a continuous AC-4 byte stream and extracts individual samples. */
|
||||
public final class Ac4Reader implements ElementaryStreamReader {
|
||||
|
|
@ -44,10 +48,10 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
|
||||
private final ParsableBitArray headerScratchBits;
|
||||
private final ParsableByteArray headerScratchBytes;
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
|
||||
private String trackFormatId;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
|
||||
@State private int state;
|
||||
private int bytesRead;
|
||||
|
|
@ -58,7 +62,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
|
||||
// Used when parsing the header.
|
||||
private long sampleDurationUs;
|
||||
private Format format;
|
||||
@MonotonicNonNull private Format format;
|
||||
private int sampleSize;
|
||||
|
||||
// Used when reading the samples.
|
||||
|
|
@ -74,7 +78,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
*
|
||||
* @param language Track language.
|
||||
*/
|
||||
public Ac4Reader(String language) {
|
||||
public Ac4Reader(@Nullable String language) {
|
||||
headerScratchBits = new ParsableBitArray(new byte[Ac4Util.HEADER_SIZE_FOR_PARSER]);
|
||||
headerScratchBytes = new ParsableByteArray(headerScratchBits.data);
|
||||
state = STATE_FINDING_SYNC;
|
||||
|
|
@ -95,7 +99,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
@Override
|
||||
public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator generator) {
|
||||
generator.generateNewId();
|
||||
trackFormatId = generator.getFormatId();
|
||||
formatId = generator.getFormatId();
|
||||
output = extractorOutput.track(generator.getTrackId(), C.TRACK_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +110,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_SYNC:
|
||||
|
|
@ -185,7 +190,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
}
|
||||
|
||||
/** Parses the sample header. */
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
@RequiresNonNull("output")
|
||||
private void parseHeader() {
|
||||
headerScratchBits.setPosition(0);
|
||||
SyncFrameInfo frameInfo = Ac4Util.parseAc4SyncframeInfo(headerScratchBits);
|
||||
|
|
@ -195,7 +200,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
|
|||
|| !MimeTypes.AUDIO_AC4.equals(format.sampleMimeType)) {
|
||||
format =
|
||||
Format.createAudioSampleFormat(
|
||||
trackFormatId,
|
||||
formatId,
|
||||
MimeTypes.AUDIO_AC4,
|
||||
/* codecs= */ null,
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
|
|
@ -23,13 +24,18 @@ import com.google.android.exoplayer2.extractor.DummyTrackOutput;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous ADTS byte stream and extracts individual frames.
|
||||
|
|
@ -62,11 +68,11 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
private final boolean exposeId3;
|
||||
private final ParsableBitArray adtsScratch;
|
||||
private final ParsableByteArray id3HeaderBuffer;
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
private TrackOutput id3Output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
@MonotonicNonNull private TrackOutput id3Output;
|
||||
|
||||
private int state;
|
||||
private int bytesRead;
|
||||
|
|
@ -90,7 +96,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
// Used when reading the samples.
|
||||
private long timeUs;
|
||||
|
||||
private TrackOutput currentOutput;
|
||||
@MonotonicNonNull private TrackOutput currentOutput;
|
||||
private long currentSampleDuration;
|
||||
|
||||
/**
|
||||
|
|
@ -104,7 +110,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
* @param exposeId3 True if the reader should expose ID3 information.
|
||||
* @param language Track language.
|
||||
*/
|
||||
public AdtsReader(boolean exposeId3, String language) {
|
||||
public AdtsReader(boolean exposeId3, @Nullable String language) {
|
||||
adtsScratch = new ParsableBitArray(new byte[HEADER_SIZE + CRC_SIZE]);
|
||||
id3HeaderBuffer = new ParsableByteArray(Arrays.copyOf(ID3_IDENTIFIER, ID3_HEADER_SIZE));
|
||||
setFindingSampleState();
|
||||
|
|
@ -130,6 +136,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
idGenerator.generateNewId();
|
||||
formatId = idGenerator.getFormatId();
|
||||
output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_AUDIO);
|
||||
currentOutput = output;
|
||||
if (exposeId3) {
|
||||
idGenerator.generateNewId();
|
||||
id3Output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_METADATA);
|
||||
|
|
@ -147,6 +154,7 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) throws ParserException {
|
||||
assertTracksCreated();
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_SAMPLE:
|
||||
|
|
@ -425,9 +433,8 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Id3 header.
|
||||
*/
|
||||
/** Parses the Id3 header. */
|
||||
@RequiresNonNull("id3Output")
|
||||
private void parseId3Header() {
|
||||
id3Output.sampleData(id3HeaderBuffer, ID3_HEADER_SIZE);
|
||||
id3HeaderBuffer.setPosition(ID3_SIZE_OFFSET);
|
||||
|
|
@ -435,9 +442,8 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
id3HeaderBuffer.readSynchSafeInt() + ID3_HEADER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the sample header.
|
||||
*/
|
||||
/** Parses the sample header. */
|
||||
@RequiresNonNull("output")
|
||||
private void parseAdtsHeader() throws ParserException {
|
||||
adtsScratch.setPosition(0);
|
||||
|
||||
|
|
@ -487,9 +493,8 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
setReadingSampleState(output, sampleDurationUs, 0, sampleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the rest of the sample
|
||||
*/
|
||||
/** Reads the rest of the sample */
|
||||
@RequiresNonNull("currentOutput")
|
||||
private void readSample(ParsableByteArray data) {
|
||||
int bytesToRead = Math.min(data.bytesLeft(), sampleSize - bytesRead);
|
||||
currentOutput.sampleData(data, bytesToRead);
|
||||
|
|
@ -501,4 +506,10 @@ public final class AdtsReader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"output", "currentOutput", "id3Output"})
|
||||
private void assertTracksCreated() {
|
||||
Assertions.checkNotNull(output);
|
||||
Util.castNonNull(currentOutput);
|
||||
Util.castNonNull(id3Output);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.ts;
|
|||
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo;
|
||||
import com.google.android.exoplayer2.text.cea.Cea708InitializationData;
|
||||
|
|
@ -134,6 +135,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact
|
|||
return new SparseArray<>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
|
||||
switch (streamType) {
|
||||
|
|
@ -247,7 +249,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact
|
|||
// Skip reserved (8).
|
||||
scratchDescriptorData.skipBytes(1);
|
||||
|
||||
List<byte[]> initializationData = null;
|
||||
@Nullable List<byte[]> initializationData = null;
|
||||
// The wide_aspect_ratio flag only has meaning for CEA-708.
|
||||
if (isDigital) {
|
||||
boolean isWideAspectRatio = (flags & 0x40) != 0;
|
||||
|
|
|
|||
|
|
@ -15,13 +15,17 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.DtsUtil;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous DTS byte stream and extracts individual samples.
|
||||
|
|
@ -35,10 +39,10 @@ public final class DtsReader implements ElementaryStreamReader {
|
|||
private static final int HEADER_SIZE = 18;
|
||||
|
||||
private final ParsableByteArray headerScratchBytes;
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
|
||||
private int state;
|
||||
private int bytesRead;
|
||||
|
|
@ -48,7 +52,7 @@ public final class DtsReader implements ElementaryStreamReader {
|
|||
|
||||
// Used when parsing the header.
|
||||
private long sampleDurationUs;
|
||||
private Format format;
|
||||
@MonotonicNonNull private Format format;
|
||||
private int sampleSize;
|
||||
|
||||
// Used when reading the samples.
|
||||
|
|
@ -59,7 +63,7 @@ public final class DtsReader implements ElementaryStreamReader {
|
|||
*
|
||||
* @param language Track language.
|
||||
*/
|
||||
public DtsReader(String language) {
|
||||
public DtsReader(@Nullable String language) {
|
||||
headerScratchBytes = new ParsableByteArray(new byte[HEADER_SIZE]);
|
||||
state = STATE_FINDING_SYNC;
|
||||
this.language = language;
|
||||
|
|
@ -86,6 +90,7 @@ public final class DtsReader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_SYNC:
|
||||
|
|
@ -162,9 +167,8 @@ public final class DtsReader implements ElementaryStreamReader {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the sample header.
|
||||
*/
|
||||
/** Parses the sample header. */
|
||||
@RequiresNonNull("output")
|
||||
private void parseHeader() {
|
||||
byte[] frameData = headerScratchBytes.data;
|
||||
if (format == null) {
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
|
|||
Format.createImageSampleFormat(
|
||||
idGenerator.getFormatId(),
|
||||
MimeTypes.APPLICATION_DVBSUBS,
|
||||
null,
|
||||
/* codecs= */ null,
|
||||
Format.NO_VALUE,
|
||||
0,
|
||||
/* selectionFlags= */ 0,
|
||||
Collections.singletonList(subtitleInfo.initializationData),
|
||||
subtitleInfo.language,
|
||||
null));
|
||||
/* drmInitData= */ null));
|
||||
outputs[i] = output;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,20 @@
|
|||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.NalUnitUtil;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous H262 byte stream and extracts individual frames.
|
||||
|
|
@ -38,27 +42,27 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
private static final int START_GROUP = 0xB8;
|
||||
private static final int START_USER_DATA = 0xB2;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
|
||||
// Maps (frame_rate_code - 1) indices to values, as defined in ITU-T H.262 Table 6-4.
|
||||
private static final double[] FRAME_RATE_VALUES = new double[] {
|
||||
24000d / 1001, 24, 25, 30000d / 1001, 30, 50, 60000d / 1001, 60};
|
||||
|
||||
@Nullable private final UserDataReader userDataReader;
|
||||
@Nullable private final ParsableByteArray userDataParsable;
|
||||
|
||||
// State that should be reset on seek.
|
||||
@Nullable private final NalUnitTargetBuffer userData;
|
||||
private final boolean[] prefixFlags;
|
||||
private final CsdBuffer csdBuffer;
|
||||
private long totalBytesWritten;
|
||||
private boolean startedFirstSample;
|
||||
|
||||
// State that should not be reset on seek.
|
||||
private boolean hasOutputFormat;
|
||||
private long frameDurationUs;
|
||||
|
||||
private final UserDataReader userDataReader;
|
||||
private final ParsableByteArray userDataParsable;
|
||||
|
||||
// State that should be reset on seek.
|
||||
private final boolean[] prefixFlags;
|
||||
private final CsdBuffer csdBuffer;
|
||||
private final NalUnitTargetBuffer userData;
|
||||
private long totalBytesWritten;
|
||||
private boolean startedFirstSample;
|
||||
|
||||
// Per packet state that gets reset at the start of each packet.
|
||||
private long pesTimeUs;
|
||||
|
||||
|
|
@ -72,7 +76,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
this(null);
|
||||
}
|
||||
|
||||
/* package */ H262Reader(UserDataReader userDataReader) {
|
||||
/* package */ H262Reader(@Nullable UserDataReader userDataReader) {
|
||||
this.userDataReader = userDataReader;
|
||||
prefixFlags = new boolean[4];
|
||||
csdBuffer = new CsdBuffer(128);
|
||||
|
|
@ -89,7 +93,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
public void seek() {
|
||||
NalUnitUtil.clearPrefixFlags(prefixFlags);
|
||||
csdBuffer.reset();
|
||||
if (userDataReader != null) {
|
||||
if (userData != null) {
|
||||
userData.reset();
|
||||
}
|
||||
totalBytesWritten = 0;
|
||||
|
|
@ -114,6 +118,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
int offset = data.getPosition();
|
||||
int limit = data.limit();
|
||||
byte[] dataArray = data.data;
|
||||
|
|
@ -130,7 +135,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
if (!hasOutputFormat) {
|
||||
csdBuffer.onData(dataArray, offset, limit);
|
||||
}
|
||||
if (userDataReader != null) {
|
||||
if (userData != null) {
|
||||
userData.appendToNalUnit(dataArray, offset, limit);
|
||||
}
|
||||
return;
|
||||
|
|
@ -157,7 +162,7 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
hasOutputFormat = true;
|
||||
}
|
||||
}
|
||||
if (userDataReader != null) {
|
||||
if (userData != null) {
|
||||
int bytesAlreadyPassed = 0;
|
||||
if (lengthToStartCode > 0) {
|
||||
userData.appendToNalUnit(dataArray, offset, startCodeOffset);
|
||||
|
|
@ -167,8 +172,8 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
|
||||
if (userData.endNalUnit(bytesAlreadyPassed)) {
|
||||
int unescapedLength = NalUnitUtil.unescapeStream(userData.nalData, userData.nalLength);
|
||||
userDataParsable.reset(userData.nalData, unescapedLength);
|
||||
userDataReader.consume(sampleTimeUs, userDataParsable);
|
||||
Util.castNonNull(userDataParsable).reset(userData.nalData, unescapedLength);
|
||||
Util.castNonNull(userDataReader).consume(sampleTimeUs, userDataParsable);
|
||||
}
|
||||
|
||||
if (startCodeValue == START_USER_DATA && data.data[startCodeOffset + 2] == 0x1) {
|
||||
|
|
@ -211,10 +216,10 @@ public final class H262Reader implements ElementaryStreamReader {
|
|||
*
|
||||
* @param csdBuffer The csd buffer.
|
||||
* @param formatId The id for the generated format. May be null.
|
||||
* @return A pair consisting of the {@link Format} and the frame duration in microseconds, or
|
||||
* 0 if the duration could not be determined.
|
||||
* @return A pair consisting of the {@link Format} and the frame duration in microseconds, or 0 if
|
||||
* the duration could not be determined.
|
||||
*/
|
||||
private static Pair<Format, Long> parseCsdBuffer(CsdBuffer csdBuffer, String formatId) {
|
||||
private static Pair<Format, Long> parseCsdBuffer(CsdBuffer csdBuffer, @Nullable String formatId) {
|
||||
byte[] csdData = Arrays.copyOf(csdBuffer.data, csdBuffer.length);
|
||||
|
||||
int firstByte = csdData[4] & 0xFF;
|
||||
|
|
|
|||
|
|
@ -23,15 +23,21 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.NalUnitUtil;
|
||||
import com.google.android.exoplayer2.util.NalUnitUtil.SpsData;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.ParsableNalUnitBitArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous H264 byte stream and extracts individual frames.
|
||||
|
|
@ -51,9 +57,9 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
private long totalBytesWritten;
|
||||
private final boolean[] prefixFlags;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
private SampleReader sampleReader;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
@MonotonicNonNull private SampleReader sampleReader;
|
||||
|
||||
// State that should not be reset on seek.
|
||||
private boolean hasOutputFormat;
|
||||
|
|
@ -87,13 +93,15 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void seek() {
|
||||
totalBytesWritten = 0;
|
||||
randomAccessIndicator = false;
|
||||
NalUnitUtil.clearPrefixFlags(prefixFlags);
|
||||
sps.reset();
|
||||
pps.reset();
|
||||
sei.reset();
|
||||
sampleReader.reset();
|
||||
totalBytesWritten = 0;
|
||||
randomAccessIndicator = false;
|
||||
if (sampleReader != null) {
|
||||
sampleReader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -113,6 +121,8 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
assertTracksCreated();
|
||||
|
||||
int offset = data.getPosition();
|
||||
int limit = data.limit();
|
||||
byte[] dataArray = data.data;
|
||||
|
|
@ -159,6 +169,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
@RequiresNonNull("sampleReader")
|
||||
private void startNalUnit(long position, int nalUnitType, long pesTimeUs) {
|
||||
if (!hasOutputFormat || sampleReader.needsSpsPps()) {
|
||||
sps.startNalUnit(nalUnitType);
|
||||
|
|
@ -168,6 +179,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
sampleReader.startNalUnit(position, nalUnitType, pesTimeUs);
|
||||
}
|
||||
|
||||
@RequiresNonNull("sampleReader")
|
||||
private void nalUnitData(byte[] dataArray, int offset, int limit) {
|
||||
if (!hasOutputFormat || sampleReader.needsSpsPps()) {
|
||||
sps.appendToNalUnit(dataArray, offset, limit);
|
||||
|
|
@ -177,6 +189,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
sampleReader.appendToNalUnit(dataArray, offset, limit);
|
||||
}
|
||||
|
||||
@RequiresNonNull({"output", "sampleReader"})
|
||||
private void endNalUnit(long position, int offset, int discardPadding, long pesTimeUs) {
|
||||
if (!hasOutputFormat || sampleReader.needsSpsPps()) {
|
||||
sps.endNalUnit(discardPadding);
|
||||
|
|
@ -237,6 +250,12 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"output", "sampleReader"})
|
||||
private void assertTracksCreated() {
|
||||
Assertions.checkStateNotNull(output);
|
||||
Util.castNonNull(sampleReader);
|
||||
}
|
||||
|
||||
/** Consumes a stream of NAL units and outputs samples. */
|
||||
private static final class SampleReader {
|
||||
|
||||
|
|
@ -478,7 +497,7 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
private boolean isComplete;
|
||||
private boolean hasSliceType;
|
||||
|
||||
private SpsData spsData;
|
||||
@Nullable private SpsData spsData;
|
||||
private int nalRefIdc;
|
||||
private int sliceType;
|
||||
private int frameNum;
|
||||
|
|
@ -542,6 +561,8 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
|
||||
private boolean isFirstVclNalUnitOfPicture(SliceHeaderData other) {
|
||||
// See ISO 14496-10 subsection 7.4.1.2.4.
|
||||
SpsData spsData = Assertions.checkStateNotNull(this.spsData);
|
||||
SpsData otherSpsData = Assertions.checkStateNotNull(other.spsData);
|
||||
return isComplete
|
||||
&& (!other.isComplete
|
||||
|| frameNum != other.frameNum
|
||||
|
|
@ -552,15 +573,15 @@ public final class H264Reader implements ElementaryStreamReader {
|
|||
&& bottomFieldFlag != other.bottomFieldFlag)
|
||||
|| (nalRefIdc != other.nalRefIdc && (nalRefIdc == 0 || other.nalRefIdc == 0))
|
||||
|| (spsData.picOrderCountType == 0
|
||||
&& other.spsData.picOrderCountType == 0
|
||||
&& otherSpsData.picOrderCountType == 0
|
||||
&& (picOrderCntLsb != other.picOrderCntLsb
|
||||
|| deltaPicOrderCntBottom != other.deltaPicOrderCntBottom))
|
||||
|| (spsData.picOrderCountType == 1
|
||||
&& other.spsData.picOrderCountType == 1
|
||||
&& otherSpsData.picOrderCountType == 1
|
||||
&& (deltaPicOrderCnt0 != other.deltaPicOrderCnt0
|
||||
|| deltaPicOrderCnt1 != other.deltaPicOrderCnt1))
|
||||
|| idrPicFlag != other.idrPicFlag
|
||||
|| (idrPicFlag && other.idrPicFlag && idrPicId != other.idrPicId));
|
||||
|| (idrPicFlag && idrPicId != other.idrPicId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,18 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.NalUnitUtil;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.ParsableNalUnitBitArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Collections;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous H.265 byte stream and extracts individual frames.
|
||||
|
|
@ -46,9 +52,9 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
|
||||
private final SeiReader seiReader;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
private SampleReader sampleReader;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
@MonotonicNonNull private SampleReader sampleReader;
|
||||
|
||||
// State that should not be reset on seek.
|
||||
private boolean hasOutputFormat;
|
||||
|
|
@ -84,14 +90,16 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void seek() {
|
||||
totalBytesWritten = 0;
|
||||
NalUnitUtil.clearPrefixFlags(prefixFlags);
|
||||
vps.reset();
|
||||
sps.reset();
|
||||
pps.reset();
|
||||
prefixSei.reset();
|
||||
suffixSei.reset();
|
||||
sampleReader.reset();
|
||||
totalBytesWritten = 0;
|
||||
if (sampleReader != null) {
|
||||
sampleReader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -111,6 +119,8 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
assertTracksCreated();
|
||||
|
||||
while (data.bytesLeft() > 0) {
|
||||
int offset = data.getPosition();
|
||||
int limit = data.limit();
|
||||
|
|
@ -160,6 +170,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
@RequiresNonNull("sampleReader")
|
||||
private void startNalUnit(long position, int offset, int nalUnitType, long pesTimeUs) {
|
||||
if (hasOutputFormat) {
|
||||
sampleReader.startNalUnit(position, offset, nalUnitType, pesTimeUs);
|
||||
|
|
@ -172,6 +183,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
suffixSei.startNalUnit(nalUnitType);
|
||||
}
|
||||
|
||||
@RequiresNonNull("sampleReader")
|
||||
private void nalUnitData(byte[] dataArray, int offset, int limit) {
|
||||
if (hasOutputFormat) {
|
||||
sampleReader.readNalUnitData(dataArray, offset, limit);
|
||||
|
|
@ -184,6 +196,7 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
suffixSei.appendToNalUnit(dataArray, offset, limit);
|
||||
}
|
||||
|
||||
@RequiresNonNull({"output", "sampleReader"})
|
||||
private void endNalUnit(long position, int offset, int discardPadding, long pesTimeUs) {
|
||||
if (hasOutputFormat) {
|
||||
sampleReader.endNalUnit(position, offset);
|
||||
|
|
@ -214,8 +227,11 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
private static Format parseMediaFormat(String formatId, NalUnitTargetBuffer vps,
|
||||
NalUnitTargetBuffer sps, NalUnitTargetBuffer pps) {
|
||||
private static Format parseMediaFormat(
|
||||
@Nullable String formatId,
|
||||
NalUnitTargetBuffer vps,
|
||||
NalUnitTargetBuffer sps,
|
||||
NalUnitTargetBuffer pps) {
|
||||
// Build codec-specific data.
|
||||
byte[] csd = new byte[vps.nalLength + sps.nalLength + pps.nalLength];
|
||||
System.arraycopy(vps.nalData, 0, csd, 0, vps.nalLength);
|
||||
|
|
@ -389,6 +405,12 @@ public final class H265Reader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"output", "sampleReader"})
|
||||
private void assertTracksCreated() {
|
||||
Assertions.checkStateNotNull(output);
|
||||
Util.castNonNull(sampleReader);
|
||||
}
|
||||
|
||||
private static final class SampleReader {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Parses ID3 data and extracts individual text information frames.
|
||||
|
|
@ -36,7 +38,7 @@ public final class Id3Reader implements ElementaryStreamReader {
|
|||
|
||||
private final ParsableByteArray id3Header;
|
||||
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
|
||||
// State that should be reset on seek.
|
||||
private boolean writingSample;
|
||||
|
|
@ -76,6 +78,7 @@ public final class Id3Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
if (!writingSample) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -106,6 +109,7 @@ public final class Id3Reader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void packetFinished() {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,14 @@ import com.google.android.exoplayer2.ParserException;
|
|||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.CodecSpecificDataUtil;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.util.Collections;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses and extracts samples from an AAC/LATM elementary stream.
|
||||
|
|
@ -43,14 +46,14 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
private static final int SYNC_BYTE_FIRST = 0x56;
|
||||
private static final int SYNC_BYTE_SECOND = 0xE0;
|
||||
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
private final ParsableByteArray sampleDataBuffer;
|
||||
private final ParsableBitArray sampleBitArray;
|
||||
|
||||
// Track output info.
|
||||
private TrackOutput output;
|
||||
private Format format;
|
||||
private String formatId;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
@MonotonicNonNull private Format format;
|
||||
|
||||
// Parser state info.
|
||||
private int state;
|
||||
|
|
@ -99,6 +102,7 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) throws ParserException {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
int bytesToRead;
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
|
|
@ -150,6 +154,7 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
*
|
||||
* @param data A {@link ParsableBitArray} containing the AudioMuxElement's bytes.
|
||||
*/
|
||||
@RequiresNonNull("output")
|
||||
private void parseAudioMuxElement(ParsableBitArray data) throws ParserException {
|
||||
boolean useSameStreamMux = data.readBit();
|
||||
if (!useSameStreamMux) {
|
||||
|
|
@ -173,9 +178,8 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a StreamMuxConfig as defined in ISO/IEC 14496-3:2009 Section 1.7.3.1, Table 1.42.
|
||||
*/
|
||||
/** Parses a StreamMuxConfig as defined in ISO/IEC 14496-3:2009 Section 1.7.3.1, Table 1.42. */
|
||||
@RequiresNonNull("output")
|
||||
private void parseStreamMuxConfig(ParsableBitArray data) throws ParserException {
|
||||
int audioMuxVersion = data.readBits(1);
|
||||
audioMuxVersionA = audioMuxVersion == 1 ? data.readBits(1) : 0;
|
||||
|
|
@ -198,9 +202,19 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
data.setPosition(startPosition);
|
||||
byte[] initData = new byte[(readBits + 7) / 8];
|
||||
data.readBits(initData, 0, readBits);
|
||||
Format format = Format.createAudioSampleFormat(formatId, MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRateHz,
|
||||
Collections.singletonList(initData), null, 0, language);
|
||||
Format format =
|
||||
Format.createAudioSampleFormat(
|
||||
formatId,
|
||||
MimeTypes.AUDIO_AAC,
|
||||
/* codecs= */ null,
|
||||
Format.NO_VALUE,
|
||||
Format.NO_VALUE,
|
||||
channelCount,
|
||||
sampleRateHz,
|
||||
Collections.singletonList(initData),
|
||||
/* drmInitData= */ null,
|
||||
/* selectionFlags= */ 0,
|
||||
language);
|
||||
if (!format.equals(this.format)) {
|
||||
this.format = format;
|
||||
sampleDurationUs = (C.MICROS_PER_SECOND * 1024) / format.sampleRate;
|
||||
|
|
@ -280,6 +294,7 @@ public final class LatmReader implements ElementaryStreamReader {
|
|||
}
|
||||
}
|
||||
|
||||
@RequiresNonNull("output")
|
||||
private void parsePayloadMux(ParsableBitArray data, int muxLengthBytes) {
|
||||
// The start of sample data in
|
||||
int bitPosition = data.getPosition();
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
|||
import com.google.android.exoplayer2.extractor.MpegAudioHeader;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses a continuous MPEG Audio byte stream and extracts individual frames.
|
||||
|
|
@ -36,10 +40,10 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
|
||||
private final ParsableByteArray headerScratch;
|
||||
private final MpegAudioHeader header;
|
||||
private final String language;
|
||||
@Nullable private final String language;
|
||||
|
||||
private String formatId;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
@MonotonicNonNull private String formatId;
|
||||
|
||||
private int state;
|
||||
private int frameBytesRead;
|
||||
|
|
@ -59,7 +63,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
this(null);
|
||||
}
|
||||
|
||||
public MpegAudioReader(String language) {
|
||||
public MpegAudioReader(@Nullable String language) {
|
||||
state = STATE_FINDING_HEADER;
|
||||
// The first byte of an MPEG Audio frame header is always 0xFF.
|
||||
headerScratch = new ParsableByteArray(4);
|
||||
|
|
@ -89,6 +93,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data) {
|
||||
Assertions.checkStateNotNull(output); // Asserts that createTracks has been called.
|
||||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_HEADER:
|
||||
|
|
@ -146,20 +151,21 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
|
||||
/**
|
||||
* Attempts to read the remaining two bytes of the frame header.
|
||||
* <p>
|
||||
* If a frame header is read in full then the state is changed to {@link #STATE_READING_FRAME},
|
||||
*
|
||||
* <p>If a frame header is read in full then the state is changed to {@link #STATE_READING_FRAME},
|
||||
* the media format is output if this has not previously occurred, the four header bytes are
|
||||
* output as sample data, and the position of the source is advanced to the byte that immediately
|
||||
* follows the header.
|
||||
* <p>
|
||||
* If a frame header is read in full but cannot be parsed then the state is changed to
|
||||
* {@link #STATE_READING_HEADER}.
|
||||
* <p>
|
||||
* If a frame header is not read in full then the position of the source is advanced to the limit,
|
||||
* and the method should be called again with the next source to continue the read.
|
||||
*
|
||||
* <p>If a frame header is read in full but cannot be parsed then the state is changed to {@link
|
||||
* #STATE_READING_HEADER}.
|
||||
*
|
||||
* <p>If a frame header is not read in full then the position of the source is advanced to the
|
||||
* limit, and the method should be called again with the next source to continue the read.
|
||||
*
|
||||
* @param source The source from which to read.
|
||||
*/
|
||||
@RequiresNonNull("output")
|
||||
private void readHeaderRemainder(ParsableByteArray source) {
|
||||
int bytesToRead = Math.min(source.bytesLeft(), HEADER_SIZE - frameBytesRead);
|
||||
source.readBytes(headerScratch.data, frameBytesRead, bytesToRead);
|
||||
|
|
@ -195,16 +201,17 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
|
||||
/**
|
||||
* Attempts to read the remainder of the frame.
|
||||
* <p>
|
||||
* If a frame is read in full then true is returned. The frame will have been output, and the
|
||||
*
|
||||
* <p>If a frame is read in full then true is returned. The frame will have been output, and the
|
||||
* position of the source will have been advanced to the byte that immediately follows the end of
|
||||
* the frame.
|
||||
* <p>
|
||||
* If a frame is not read in full then the position of the source will have been advanced to the
|
||||
* limit, and the method should be called again with the next source to continue the read.
|
||||
*
|
||||
* <p>If a frame is not read in full then the position of the source will have been advanced to
|
||||
* the limit, and the method should be called again with the next source to continue the read.
|
||||
*
|
||||
* @param source The source from which to read.
|
||||
*/
|
||||
@RequiresNonNull("output")
|
||||
private void readFrameRemainder(ParsableByteArray source) {
|
||||
int bytesToRead = Math.min(source.bytesLeft(), frameSize - frameBytesRead);
|
||||
output.sampleData(source, bytesToRead);
|
||||
|
|
@ -219,5 +226,4 @@ public final class MpegAudioReader implements ElementaryStreamReader {
|
|||
frameBytesRead = 0;
|
||||
state = STATE_FINDING_HEADER;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,17 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Parses PES packet data and extracts samples.
|
||||
|
|
@ -45,7 +49,7 @@ public final class PesReader implements TsPayloadReader {
|
|||
private int state;
|
||||
private int bytesRead;
|
||||
|
||||
private TimestampAdjuster timestampAdjuster;
|
||||
@MonotonicNonNull private TimestampAdjuster timestampAdjuster;
|
||||
private boolean ptsFlag;
|
||||
private boolean dtsFlag;
|
||||
private boolean seenFirstDts;
|
||||
|
|
@ -79,6 +83,8 @@ public final class PesReader implements TsPayloadReader {
|
|||
|
||||
@Override
|
||||
public final void consume(ParsableByteArray data, @Flags int flags) throws ParserException {
|
||||
Assertions.checkStateNotNull(timestampAdjuster); // Asserts init has been called.
|
||||
|
||||
if ((flags & FLAG_PAYLOAD_UNIT_START_INDICATOR) != 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_HEADER:
|
||||
|
|
@ -119,7 +125,7 @@ public final class PesReader implements TsPayloadReader {
|
|||
int readLength = Math.min(MAX_HEADER_EXTENSION_SIZE, extendedHeaderLength);
|
||||
// Read as much of the extended header as we're interested in, and skip the rest.
|
||||
if (continueRead(data, pesScratch.data, readLength)
|
||||
&& continueRead(data, null, extendedHeaderLength)) {
|
||||
&& continueRead(data, /* target= */ null, extendedHeaderLength)) {
|
||||
parseHeaderExtension();
|
||||
flags |= dataAlignmentIndicator ? FLAG_DATA_ALIGNMENT_INDICATOR : 0;
|
||||
reader.packetStarted(timeUs, flags);
|
||||
|
|
@ -162,7 +168,8 @@ public final class PesReader implements TsPayloadReader {
|
|||
* @param targetLength The target length of the read.
|
||||
* @return Whether the target length has been reached.
|
||||
*/
|
||||
private boolean continueRead(ParsableByteArray source, byte[] target, int targetLength) {
|
||||
private boolean continueRead(
|
||||
ParsableByteArray source, @Nullable byte[] target, int targetLength) {
|
||||
int bytesToRead = Math.min(source.bytesLeft(), targetLength - bytesRead);
|
||||
if (bytesToRead <= 0) {
|
||||
return true;
|
||||
|
|
@ -207,6 +214,7 @@ public final class PesReader implements TsPayloadReader {
|
|||
return true;
|
||||
}
|
||||
|
||||
@RequiresNonNull("timestampAdjuster")
|
||||
private void parseHeaderExtension() {
|
||||
pesScratch.setPosition(0);
|
||||
timeUs = C.TIME_UNSET;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
|
|
@ -25,10 +26,13 @@ import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
|||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||
import java.io.IOException;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* Extracts data from the MPEG-2 PS container format.
|
||||
|
|
@ -67,8 +71,8 @@ public final class PsExtractor implements Extractor {
|
|||
private long lastTrackPosition;
|
||||
|
||||
// Accessed only by the loading thread.
|
||||
private PsBinarySearchSeeker psBinarySearchSeeker;
|
||||
private ExtractorOutput output;
|
||||
@Nullable private PsBinarySearchSeeker psBinarySearchSeeker;
|
||||
@MonotonicNonNull private ExtractorOutput output;
|
||||
private boolean hasOutputSeekMap;
|
||||
|
||||
public PsExtractor() {
|
||||
|
|
@ -160,6 +164,7 @@ public final class PsExtractor implements Extractor {
|
|||
@Override
|
||||
public int read(ExtractorInput input, PositionHolder seekPosition)
|
||||
throws IOException, InterruptedException {
|
||||
Assertions.checkStateNotNull(output); // Asserts init has been called.
|
||||
|
||||
long inputLength = input.getLength();
|
||||
boolean canReadDuration = inputLength != C.LENGTH_UNSET;
|
||||
|
|
@ -221,7 +226,7 @@ public final class PsExtractor implements Extractor {
|
|||
PesReader payloadReader = psPayloadReaders.get(streamId);
|
||||
if (!foundAllTracks) {
|
||||
if (payloadReader == null) {
|
||||
ElementaryStreamReader elementaryStreamReader = null;
|
||||
@Nullable ElementaryStreamReader elementaryStreamReader = null;
|
||||
if (streamId == PRIVATE_STREAM_1) {
|
||||
// Private stream, used for AC3 audio.
|
||||
// NOTE: This may need further parsing to determine if its DTS, but that's likely only
|
||||
|
|
@ -278,6 +283,7 @@ public final class PsExtractor implements Extractor {
|
|||
|
||||
// Internals.
|
||||
|
||||
@RequiresNonNull("output")
|
||||
private void maybeOutputSeekMap(long inputLength) {
|
||||
if (!hasOutputSeekMap) {
|
||||
hasOutputSeekMap = true;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
|
|
@ -45,7 +46,7 @@ public final class SeiReader {
|
|||
idGenerator.generateNewId();
|
||||
TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT);
|
||||
Format channelFormat = closedCaptionFormats.get(i);
|
||||
String channelMimeType = channelFormat.sampleMimeType;
|
||||
@Nullable String channelMimeType = channelFormat.sampleMimeType;
|
||||
Assertions.checkArgument(MimeTypes.APPLICATION_CEA608.equals(channelMimeType)
|
||||
|| MimeTypes.APPLICATION_CEA708.equals(channelMimeType),
|
||||
"Invalid closed caption mime type provided: " + channelMimeType);
|
||||
|
|
@ -69,5 +70,4 @@ public final class SeiReader {
|
|||
public void consume(long pesTimeUs, ParsableByteArray seiBuffer) {
|
||||
CeaUtil.consume(pesTimeUs, seiBuffer, outputs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,17 +19,21 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Parses splice info sections as defined by SCTE35.
|
||||
*/
|
||||
public final class SpliceInfoSectionReader implements SectionPayloadReader {
|
||||
|
||||
private TimestampAdjuster timestampAdjuster;
|
||||
private TrackOutput output;
|
||||
@MonotonicNonNull private TimestampAdjuster timestampAdjuster;
|
||||
@MonotonicNonNull private TrackOutput output;
|
||||
private boolean formatDeclared;
|
||||
|
||||
@Override
|
||||
|
|
@ -44,6 +48,7 @@ public final class SpliceInfoSectionReader implements SectionPayloadReader {
|
|||
|
||||
@Override
|
||||
public void consume(ParsableByteArray sectionData) {
|
||||
assertInitialized();
|
||||
if (!formatDeclared) {
|
||||
if (timestampAdjuster.getTimestampOffsetUs() == C.TIME_UNSET) {
|
||||
// There is not enough information to initialize the timestamp adjuster.
|
||||
|
|
@ -59,4 +64,9 @@ public final class SpliceInfoSectionReader implements SectionPayloadReader {
|
|||
sampleSize, 0, null);
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"timestampAdjuster", "output"})
|
||||
private void assertInitialized() {
|
||||
Assertions.checkStateNotNull(timestampAdjuster);
|
||||
Util.castNonNull(output);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import android.util.SparseArray;
|
|||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
|
|
@ -587,8 +588,11 @@ public final class TsExtractor implements Extractor {
|
|||
continue;
|
||||
}
|
||||
|
||||
TsPayloadReader reader = mode == MODE_HLS && streamType == TS_STREAM_TYPE_ID3 ? id3Reader
|
||||
: payloadReaderFactory.createPayloadReader(streamType, esInfo);
|
||||
@Nullable
|
||||
TsPayloadReader reader =
|
||||
mode == MODE_HLS && streamType == TS_STREAM_TYPE_ID3
|
||||
? id3Reader
|
||||
: payloadReaderFactory.createPayloadReader(streamType, esInfo);
|
||||
if (mode != MODE_HLS
|
||||
|| elementaryPid < trackIdToPidScratch.get(trackId, MAX_PID_PLUS_ONE)) {
|
||||
trackIdToPidScratch.put(trackId, elementaryPid);
|
||||
|
|
@ -602,7 +606,7 @@ public final class TsExtractor implements Extractor {
|
|||
int trackPid = trackIdToPidScratch.valueAt(i);
|
||||
trackIds.put(trackId, true);
|
||||
trackPids.put(trackPid, true);
|
||||
TsPayloadReader reader = trackIdToReaderScratch.valueAt(i);
|
||||
@Nullable TsPayloadReader reader = trackIdToReaderScratch.valueAt(i);
|
||||
if (reader != null) {
|
||||
if (reader != id3Reader) {
|
||||
reader.init(timestampAdjuster, output,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.ts;
|
|||
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
|
|
@ -53,11 +54,11 @@ public interface TsPayloadReader {
|
|||
*
|
||||
* @param streamType Stream type value as defined in the PMT entry or associated descriptors.
|
||||
* @param esInfo Information associated to the elementary stream provided in the PMT.
|
||||
* @return A {@link TsPayloadReader} for the packet stream carried by the provided pid.
|
||||
* @return A {@link TsPayloadReader} for the packet stream carried by the provided pid, or
|
||||
* {@code null} if the stream is not supported.
|
||||
*/
|
||||
@Nullable
|
||||
TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -66,18 +67,21 @@ public interface TsPayloadReader {
|
|||
final class EsInfo {
|
||||
|
||||
public final int streamType;
|
||||
public final String language;
|
||||
@Nullable public final String language;
|
||||
public final List<DvbSubtitleInfo> dvbSubtitleInfos;
|
||||
public final byte[] descriptorBytes;
|
||||
|
||||
/**
|
||||
* @param streamType The type of the stream as defined by the
|
||||
* {@link TsExtractor}{@code .TS_STREAM_TYPE_*}.
|
||||
* @param streamType The type of the stream as defined by the {@link TsExtractor}{@code
|
||||
* .TS_STREAM_TYPE_*}.
|
||||
* @param language The language of the stream, as defined by ISO/IEC 13818-1, section 2.6.18.
|
||||
* @param dvbSubtitleInfos Information about DVB subtitles associated to the stream.
|
||||
* @param descriptorBytes The descriptor bytes associated to the stream.
|
||||
*/
|
||||
public EsInfo(int streamType, String language, List<DvbSubtitleInfo> dvbSubtitleInfos,
|
||||
public EsInfo(
|
||||
int streamType,
|
||||
@Nullable String language,
|
||||
@Nullable List<DvbSubtitleInfo> dvbSubtitleInfos,
|
||||
byte[] descriptorBytes) {
|
||||
this.streamType = streamType;
|
||||
this.language = language;
|
||||
|
|
@ -134,6 +138,7 @@ public interface TsPayloadReader {
|
|||
this.firstTrackId = firstTrackId;
|
||||
this.trackIdIncrement = trackIdIncrement;
|
||||
trackId = ID_UNSET;
|
||||
formatId = "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
|
|
@ -44,7 +45,7 @@ import java.util.List;
|
|||
idGenerator.generateNewId();
|
||||
TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT);
|
||||
Format channelFormat = closedCaptionFormats.get(i);
|
||||
String channelMimeType = channelFormat.sampleMimeType;
|
||||
@Nullable String channelMimeType = channelFormat.sampleMimeType;
|
||||
Assertions.checkArgument(
|
||||
MimeTypes.APPLICATION_CEA608.equals(channelMimeType)
|
||||
|| MimeTypes.APPLICATION_CEA708.equals(channelMimeType),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@NonNullApi
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import com.google.android.exoplayer2.util.NonNullApi;
|
||||
|
|
@ -773,7 +773,7 @@ public final class DownloadHelper {
|
|||
}
|
||||
|
||||
// Initialization of array of Lists.
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void onMediaPrepared() {
|
||||
Assertions.checkNotNull(mediaPreparer);
|
||||
Assertions.checkNotNull(mediaPreparer.mediaPeriods);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.extractor.ts;
|
|||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
|
|
@ -172,6 +173,7 @@ public final class TsExtractorTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
|
||||
if (provideCustomEsReader && streamType == 3) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue