summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java')
-rw-r--r--mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java
new file mode 100644
index 0000000000..61b53cfa72
--- /dev/null
+++ b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/ts/SectionReader.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+package org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.ts;
+
+import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.ExtractorOutput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.ParsableByteArray;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.TimestampAdjuster;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.Util;
+
+/**
+ * Reads section data packets and feeds the whole sections to a given {@link SectionPayloadReader}.
+ * Useful information on PSI sections can be found in ISO/IEC 13818-1, section 2.4.4.
+ */
+public final class SectionReader implements TsPayloadReader {
+
+ private static final int SECTION_HEADER_LENGTH = 3;
+ private static final int DEFAULT_SECTION_BUFFER_LENGTH = 32;
+ private static final int MAX_SECTION_LENGTH = 4098;
+
+ private final SectionPayloadReader reader;
+ private final ParsableByteArray sectionData;
+
+ private int totalSectionLength;
+ private int bytesRead;
+ private boolean sectionSyntaxIndicator;
+ private boolean waitingForPayloadStart;
+
+ public SectionReader(SectionPayloadReader reader) {
+ this.reader = reader;
+ sectionData = new ParsableByteArray(DEFAULT_SECTION_BUFFER_LENGTH);
+ }
+
+ @Override
+ public void init(TimestampAdjuster timestampAdjuster, ExtractorOutput extractorOutput,
+ TrackIdGenerator idGenerator) {
+ reader.init(timestampAdjuster, extractorOutput, idGenerator);
+ waitingForPayloadStart = true;
+ }
+
+ @Override
+ public void seek() {
+ waitingForPayloadStart = true;
+ }
+
+ @Override
+ public void consume(ParsableByteArray data, @Flags int flags) {
+ boolean payloadUnitStartIndicator = (flags & FLAG_PAYLOAD_UNIT_START_INDICATOR) != 0;
+ int payloadStartPosition = C.POSITION_UNSET;
+ if (payloadUnitStartIndicator) {
+ int payloadStartOffset = data.readUnsignedByte();
+ payloadStartPosition = data.getPosition() + payloadStartOffset;
+ }
+
+ if (waitingForPayloadStart) {
+ if (!payloadUnitStartIndicator) {
+ return;
+ }
+ waitingForPayloadStart = false;
+ data.setPosition(payloadStartPosition);
+ bytesRead = 0;
+ }
+
+ while (data.bytesLeft() > 0) {
+ if (bytesRead < SECTION_HEADER_LENGTH) {
+ // Note: see ISO/IEC 13818-1, section 2.4.4.3 for detailed information on the format of
+ // the header.
+ if (bytesRead == 0) {
+ int tableId = data.readUnsignedByte();
+ data.setPosition(data.getPosition() - 1);
+ if (tableId == 0xFF /* forbidden value */) {
+ // No more sections in this ts packet.
+ waitingForPayloadStart = true;
+ return;
+ }
+ }
+ int headerBytesToRead = Math.min(data.bytesLeft(), SECTION_HEADER_LENGTH - bytesRead);
+ data.readBytes(sectionData.data, bytesRead, headerBytesToRead);
+ bytesRead += headerBytesToRead;
+ if (bytesRead == SECTION_HEADER_LENGTH) {
+ sectionData.reset(SECTION_HEADER_LENGTH);
+ sectionData.skipBytes(1); // Skip table id (8).
+ int secondHeaderByte = sectionData.readUnsignedByte();
+ int thirdHeaderByte = sectionData.readUnsignedByte();
+ sectionSyntaxIndicator = (secondHeaderByte & 0x80) != 0;
+ totalSectionLength =
+ (((secondHeaderByte & 0x0F) << 8) | thirdHeaderByte) + SECTION_HEADER_LENGTH;
+ if (sectionData.capacity() < totalSectionLength) {
+ // Ensure there is enough space to keep the whole section.
+ byte[] bytes = sectionData.data;
+ sectionData.reset(
+ Math.min(MAX_SECTION_LENGTH, Math.max(totalSectionLength, bytes.length * 2)));
+ System.arraycopy(bytes, 0, sectionData.data, 0, SECTION_HEADER_LENGTH);
+ }
+ }
+ } else {
+ // Reading the body.
+ int bodyBytesToRead = Math.min(data.bytesLeft(), totalSectionLength - bytesRead);
+ data.readBytes(sectionData.data, bytesRead, bodyBytesToRead);
+ bytesRead += bodyBytesToRead;
+ if (bytesRead == totalSectionLength) {
+ if (sectionSyntaxIndicator) {
+ // This section has common syntax as defined in ISO/IEC 13818-1, section 2.4.4.11.
+ if (Util.crc32(sectionData.data, 0, totalSectionLength, 0xFFFFFFFF) != 0) {
+ // The CRC is invalid so discard the section.
+ waitingForPayloadStart = true;
+ return;
+ }
+ sectionData.reset(totalSectionLength - 4); // Exclude the CRC_32 field.
+ } else {
+ // This is a private section with private defined syntax.
+ sectionData.reset(totalSectionLength);
+ }
+ reader.consume(sectionData);
+ bytesRead = 0;
+ }
+ }
+ }
+ }
+
+}