Rabbit-R1/android (non root)/java/sources/androidx/media3/extractor/ts/AdtsReader.java
2024-05-21 17:08:36 -04:00

376 lines
14 KiB
Java

package androidx.media3.extractor.ts;
import androidx.media3.common.Format;
import androidx.media3.common.ParserException;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.ParsableBitArray;
import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.Util;
import androidx.media3.extractor.AacUtil;
import androidx.media3.extractor.DummyTrackOutput;
import androidx.media3.extractor.ExtractorOutput;
import androidx.media3.extractor.TrackOutput;
import androidx.media3.extractor.ts.TsPayloadReader;
import java.util.Arrays;
import java.util.Collections;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/* loaded from: classes2.dex */
public final class AdtsReader implements ElementaryStreamReader {
private static final int CRC_SIZE = 2;
private static final int HEADER_SIZE = 5;
private static final int ID3_HEADER_SIZE = 10;
private static final byte[] ID3_IDENTIFIER = {73, 68, 51};
private static final int ID3_SIZE_OFFSET = 6;
private static final int MATCH_STATE_FF = 512;
private static final int MATCH_STATE_I = 768;
private static final int MATCH_STATE_ID = 1024;
private static final int MATCH_STATE_START = 256;
private static final int MATCH_STATE_VALUE_SHIFT = 8;
private static final int STATE_CHECKING_ADTS_HEADER = 1;
private static final int STATE_FINDING_SAMPLE = 0;
private static final int STATE_READING_ADTS_HEADER = 3;
private static final int STATE_READING_ID3_HEADER = 2;
private static final int STATE_READING_SAMPLE = 4;
private static final String TAG = "AdtsReader";
private static final int VERSION_UNSET = -1;
private final ParsableBitArray adtsScratch;
private int bytesRead;
private int currentFrameVersion;
private TrackOutput currentOutput;
private long currentSampleDuration;
private final boolean exposeId3;
private int firstFrameSampleRateIndex;
private int firstFrameVersion;
private String formatId;
private boolean foundFirstFrame;
private boolean hasCrc;
private boolean hasOutputFormat;
private final ParsableByteArray id3HeaderBuffer;
private TrackOutput id3Output;
private final String language;
private int matchState;
private TrackOutput output;
private long sampleDurationUs;
private int sampleSize;
private int state;
private long timeUs;
public static boolean isAdtsSyncWord(int i) {
return (i & 65526) == 65520;
}
private void setCheckingAdtsHeaderState() {
this.state = 1;
this.bytesRead = 0;
}
private void setFindingSampleState() {
this.state = 0;
this.bytesRead = 0;
this.matchState = 256;
}
private void setReadingAdtsHeaderState() {
this.state = 3;
this.bytesRead = 0;
}
private void setReadingSampleState(TrackOutput trackOutput, long j, int i, int i2) {
this.state = 4;
this.bytesRead = i;
this.currentOutput = trackOutput;
this.currentSampleDuration = j;
this.sampleSize = i2;
}
public long getSampleDurationUs() {
return this.sampleDurationUs;
}
@Override // androidx.media3.extractor.ts.ElementaryStreamReader
public void packetFinished() {
}
@Override // androidx.media3.extractor.ts.ElementaryStreamReader
public void packetStarted(long j, int i) {
if (j != -9223372036854775807L) {
this.timeUs = j;
}
}
public AdtsReader(boolean z) {
this(z, null);
}
public AdtsReader(boolean z, String str) {
this.adtsScratch = new ParsableBitArray(new byte[7]);
this.id3HeaderBuffer = new ParsableByteArray(Arrays.copyOf(ID3_IDENTIFIER, 10));
setFindingSampleState();
this.firstFrameVersion = -1;
this.firstFrameSampleRateIndex = -1;
this.sampleDurationUs = -9223372036854775807L;
this.timeUs = -9223372036854775807L;
this.exposeId3 = z;
this.language = str;
}
@Override // androidx.media3.extractor.ts.ElementaryStreamReader
public void seek() {
this.timeUs = -9223372036854775807L;
resetSync();
}
@Override // androidx.media3.extractor.ts.ElementaryStreamReader
public void createTracks(ExtractorOutput extractorOutput, TsPayloadReader.TrackIdGenerator trackIdGenerator) {
trackIdGenerator.generateNewId();
this.formatId = trackIdGenerator.getFormatId();
TrackOutput track = extractorOutput.track(trackIdGenerator.getTrackId(), 1);
this.output = track;
this.currentOutput = track;
if (this.exposeId3) {
trackIdGenerator.generateNewId();
TrackOutput track2 = extractorOutput.track(trackIdGenerator.getTrackId(), 5);
this.id3Output = track2;
track2.format(new Format.Builder().setId(trackIdGenerator.getFormatId()).setSampleMimeType("application/id3").build());
return;
}
this.id3Output = new DummyTrackOutput();
}
@Override // androidx.media3.extractor.ts.ElementaryStreamReader
public void consume(ParsableByteArray parsableByteArray) throws ParserException {
assertTracksCreated();
while (parsableByteArray.bytesLeft() > 0) {
int i = this.state;
if (i == 0) {
findNextSample(parsableByteArray);
} else if (i == 1) {
checkAdtsHeader(parsableByteArray);
} else if (i != 2) {
if (i == 3) {
if (continueRead(parsableByteArray, this.adtsScratch.data, this.hasCrc ? 7 : 5)) {
parseAdtsHeader();
}
} else if (i == 4) {
readSample(parsableByteArray);
} else {
throw new IllegalStateException();
}
} else if (continueRead(parsableByteArray, this.id3HeaderBuffer.getData(), 10)) {
parseId3Header();
}
}
}
private void resetSync() {
this.foundFirstFrame = false;
setFindingSampleState();
}
private boolean continueRead(ParsableByteArray parsableByteArray, byte[] bArr, int i) {
int min = Math.min(parsableByteArray.bytesLeft(), i - this.bytesRead);
parsableByteArray.readBytes(bArr, this.bytesRead, min);
int i2 = this.bytesRead + min;
this.bytesRead = i2;
return i2 == i;
}
private void setReadingId3HeaderState() {
this.state = 2;
this.bytesRead = ID3_IDENTIFIER.length;
this.sampleSize = 0;
this.id3HeaderBuffer.setPosition(0);
}
private void findNextSample(ParsableByteArray parsableByteArray) {
byte[] data = parsableByteArray.getData();
int position = parsableByteArray.getPosition();
int limit = parsableByteArray.limit();
while (position < limit) {
int i = position + 1;
byte b = data[position];
int i2 = b & 255;
if (this.matchState == 512 && isAdtsSyncBytes((byte) -1, (byte) i2) && (this.foundFirstFrame || checkSyncPositionValid(parsableByteArray, position - 1))) {
this.currentFrameVersion = (b & 8) >> 3;
this.hasCrc = (b & 1) == 0;
if (!this.foundFirstFrame) {
setCheckingAdtsHeaderState();
} else {
setReadingAdtsHeaderState();
}
parsableByteArray.setPosition(i);
return;
}
int i3 = this.matchState;
int i4 = i2 | i3;
if (i4 == 329) {
this.matchState = 768;
} else if (i4 == 511) {
this.matchState = 512;
} else if (i4 == 836) {
this.matchState = 1024;
} else if (i4 == 1075) {
setReadingId3HeaderState();
parsableByteArray.setPosition(i);
return;
} else if (i3 != 256) {
this.matchState = 256;
}
position = i;
}
parsableByteArray.setPosition(position);
}
private void checkAdtsHeader(ParsableByteArray parsableByteArray) {
if (parsableByteArray.bytesLeft() == 0) {
return;
}
this.adtsScratch.data[0] = parsableByteArray.getData()[parsableByteArray.getPosition()];
this.adtsScratch.setPosition(2);
int readBits = this.adtsScratch.readBits(4);
int i = this.firstFrameSampleRateIndex;
if (i != -1 && readBits != i) {
resetSync();
return;
}
if (!this.foundFirstFrame) {
this.foundFirstFrame = true;
this.firstFrameVersion = this.currentFrameVersion;
this.firstFrameSampleRateIndex = readBits;
}
setReadingAdtsHeaderState();
}
private boolean checkSyncPositionValid(ParsableByteArray parsableByteArray, int i) {
parsableByteArray.setPosition(i + 1);
if (!tryRead(parsableByteArray, this.adtsScratch.data, 1)) {
return false;
}
this.adtsScratch.setPosition(4);
int readBits = this.adtsScratch.readBits(1);
int i2 = this.firstFrameVersion;
if (i2 != -1 && readBits != i2) {
return false;
}
if (this.firstFrameSampleRateIndex != -1) {
if (!tryRead(parsableByteArray, this.adtsScratch.data, 1)) {
return true;
}
this.adtsScratch.setPosition(2);
if (this.adtsScratch.readBits(4) != this.firstFrameSampleRateIndex) {
return false;
}
parsableByteArray.setPosition(i + 2);
}
if (!tryRead(parsableByteArray, this.adtsScratch.data, 4)) {
return true;
}
this.adtsScratch.setPosition(14);
int readBits2 = this.adtsScratch.readBits(13);
if (readBits2 < 7) {
return false;
}
byte[] data = parsableByteArray.getData();
int limit = parsableByteArray.limit();
int i3 = i + readBits2;
if (i3 >= limit) {
return true;
}
byte b = data[i3];
if (b == -1) {
int i4 = i3 + 1;
if (i4 == limit) {
return true;
}
return isAdtsSyncBytes((byte) -1, data[i4]) && ((data[i4] & 8) >> 3) == readBits;
}
if (b != 73) {
return false;
}
int i5 = i3 + 1;
if (i5 == limit) {
return true;
}
if (data[i5] != 68) {
return false;
}
int i6 = i3 + 2;
return i6 == limit || data[i6] == 51;
}
private boolean isAdtsSyncBytes(byte b, byte b2) {
return isAdtsSyncWord(((b & 255) << 8) | (b2 & 255));
}
private boolean tryRead(ParsableByteArray parsableByteArray, byte[] bArr, int i) {
if (parsableByteArray.bytesLeft() < i) {
return false;
}
parsableByteArray.readBytes(bArr, 0, i);
return true;
}
@RequiresNonNull({"id3Output"})
private void parseId3Header() {
this.id3Output.sampleData(this.id3HeaderBuffer, 10);
this.id3HeaderBuffer.setPosition(6);
setReadingSampleState(this.id3Output, 0L, 10, this.id3HeaderBuffer.readSynchSafeInt() + 10);
}
@RequiresNonNull({"output"})
private void parseAdtsHeader() throws ParserException {
this.adtsScratch.setPosition(0);
if (!this.hasOutputFormat) {
int i = 2;
int readBits = this.adtsScratch.readBits(2) + 1;
if (readBits != 2) {
Log.w(TAG, "Detected audio object type: " + readBits + ", but assuming AAC LC.");
} else {
i = readBits;
}
this.adtsScratch.skipBits(5);
byte[] buildAudioSpecificConfig = AacUtil.buildAudioSpecificConfig(i, this.firstFrameSampleRateIndex, this.adtsScratch.readBits(3));
AacUtil.Config parseAudioSpecificConfig = AacUtil.parseAudioSpecificConfig(buildAudioSpecificConfig);
Format build = new Format.Builder().setId(this.formatId).setSampleMimeType("audio/mp4a-latm").setCodecs(parseAudioSpecificConfig.codecs).setChannelCount(parseAudioSpecificConfig.channelCount).setSampleRate(parseAudioSpecificConfig.sampleRateHz).setInitializationData(Collections.singletonList(buildAudioSpecificConfig)).setLanguage(this.language).build();
this.sampleDurationUs = 1024000000 / build.sampleRate;
this.output.format(build);
this.hasOutputFormat = true;
} else {
this.adtsScratch.skipBits(10);
}
this.adtsScratch.skipBits(4);
int readBits2 = this.adtsScratch.readBits(13);
int i2 = readBits2 - 7;
if (this.hasCrc) {
i2 = readBits2 - 9;
}
setReadingSampleState(this.output, this.sampleDurationUs, 0, i2);
}
@RequiresNonNull({"currentOutput"})
private void readSample(ParsableByteArray parsableByteArray) {
int min = Math.min(parsableByteArray.bytesLeft(), this.sampleSize - this.bytesRead);
this.currentOutput.sampleData(parsableByteArray, min);
int i = this.bytesRead + min;
this.bytesRead = i;
int i2 = this.sampleSize;
if (i == i2) {
long j = this.timeUs;
if (j != -9223372036854775807L) {
this.currentOutput.sampleMetadata(j, 1, i2, 0, null);
this.timeUs += this.currentSampleDuration;
}
setFindingSampleState();
}
}
@EnsuresNonNull({"output", "currentOutput", "id3Output"})
private void assertTracksCreated() {
Assertions.checkNotNull(this.output);
Util.castNonNull(this.currentOutput);
Util.castNonNull(this.id3Output);
}
}