From 98de7c460b103799acdfd80b87c41a9169a8f921 Mon Sep 17 00:00:00 2001 From: Pierre-Hugues Husson Date: Tue, 18 Feb 2020 15:00:26 +0100 Subject: [PATCH] [AitDecoder] Move to ParsableBitArray --- .../exoplayer2/metadata/dvbsi/AitDecoder.java | 101 ++++++++++-------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/dvbsi/AitDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/dvbsi/AitDecoder.java index 33fe6bf865..e911349e1f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/dvbsi/AitDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/dvbsi/AitDecoder.java @@ -3,16 +3,20 @@ package com.google.android.exoplayer2.metadata.dvbsi; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataDecoder; import com.google.android.exoplayer2.metadata.MetadataInputBuffer; +import com.google.android.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.TimestampAdjuster; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +// Unless mentioned explicitly, every references here are to +// https://www.etsi.org/deliver/etsi_ts/102800_102899/102809/01.01.01_60/ts_102809v010101p.pdf public class AitDecoder implements MetadataDecoder { // Specification of AIT can be found in 5.3.4 of TS 102 809 v1.1.1 - // https://www.etsi.org/deliver/etsi_ts/102800_102899/102809/01.01.01_60/ts_102809v010101p.pdf + private final static int DESCRIPTOR_TRANSPORT_PROTOCOL = 0x02; private final static int DESCRIPTOR_SIMPLE_APPLICATION_LOCATION = 0x15; @@ -21,10 +25,10 @@ public class AitDecoder implements MetadataDecoder { private TimestampAdjuster timestampAdjuster; - private final ParsableByteArray sectionData; + private final ParsableBitArray sectionData; public AitDecoder() { - sectionData = new ParsableByteArray(); + sectionData = new ParsableBitArray(); } @Override @@ -40,8 +44,7 @@ public class AitDecoder implements MetadataDecoder { int size = buffer.limit(); sectionData.reset(data, size); - int tableId = sectionData.peekUnsignedByte(); - + int tableId = sectionData.data[0]; //Only this table is allowed in AIT streams if (tableId == 0x74) { return parseAit(sectionData); @@ -50,80 +53,92 @@ public class AitDecoder implements MetadataDecoder { return new Metadata(); } - private Metadata parseAit(ParsableByteArray sectionData) { - int tmp; + private Metadata parseAit(ParsableBitArray sectionData) { + //tableId + sectionData.skipBits(8); - int tableId = sectionData.readUnsignedByte(); + //section_syntax_indication | reserved_future_use | reserved + sectionData.skipBits(4); + int sectionLength = sectionData.readBits(12); + int endOfSection = sectionData.getBytePosition() + sectionLength - 4 /* Ignore leading CRC */; - tmp = sectionData.readUnsignedShort(); - int endOfSection = sectionData.getPosition() + (tmp & 4095) - 4 /* Ignore leading CRC */; + // test_application_flag | application_type + sectionData.skipBits(16); - tmp = sectionData.readUnsignedShort(); - int applicationType = tmp & 0x7fff; + // reserved | version_number | current_next_indicator + sectionData.skipBits(8); - tmp = sectionData.readUnsignedByte(); - int versionNumber = (tmp & 0x3e) >> 1; - boolean current = (tmp & 1) == 1; + // section_number + sectionData.skipBits(8); + // last_section_number + sectionData.skipBits(8); - int section_number = sectionData.readUnsignedByte(); - int last_section_number = sectionData.readUnsignedByte(); - - tmp = sectionData.readUnsignedShort(); - int commonDescriptorsLength = tmp & 4095; + // reserved_future_use + sectionData.skipBits(4); + int commonDescriptorsLength = sectionData.readBits(12); //Since we currently only keep url and control code, which are unique per application, //there is no useful information in common descriptor. sectionData.skipBytes(commonDescriptorsLength); - tmp = sectionData.readUnsignedShort(); - int appLoopLength = tmp & 4095; + // reserved_future_use | application_loop_length + sectionData.skipBits(16); ArrayList aits = new ArrayList<>(); - while(sectionData.getPosition() < endOfSection) { + while(sectionData.getBytePosition() < endOfSection) { // Values that will be stored in Ait() String aitUrlBase = null; String aitUrlExtension = null; int aitControlCode = -1; - long application_identifier = sectionData.readUnsignedInt24() << 24L; - application_identifier |= sectionData.readUnsignedInt24(); - int controlCode = sectionData.readUnsignedByte(); + // application_identifier + sectionData.skipBits(48); + int controlCode = sectionData.readBits(8); aitControlCode = controlCode; - tmp = sectionData.readUnsignedShort(); - int sectionLength = tmp & 4095; - int positionOfNextSection = sectionData.getPosition() + sectionLength; - while(sectionData.getPosition() < positionOfNextSection) { - int type = sectionData.readUnsignedByte(); - int l = sectionData.readUnsignedByte(); - int positionOfNextSection2 = sectionData.getPosition() + l; + // reserved_future_use + sectionData.skipBits(4); + + int applicationDescriptorsLoopLength = sectionData.readBits(12); + int positionOfNextSection = sectionData.getBytePosition() + applicationDescriptorsLoopLength; + while(sectionData.getBytePosition() < positionOfNextSection) { + int type = sectionData.readBits(8); + int l = sectionData.readBits(8); + int positionOfNextSection2 = sectionData.getBytePosition() + l; if(type == DESCRIPTOR_TRANSPORT_PROTOCOL) { - int protocolId = sectionData.readUnsignedShort(); - int label = sectionData.readUnsignedByte(); + // See section 5.3.6 + int protocolId = sectionData.readBits(16); + // label + sectionData.skipBits(8); if(protocolId == TRANSPORT_PROTOCOL_HTTP) { - while (sectionData.getPosition() < positionOfNextSection2) { - int urlBaseLength = sectionData.readUnsignedByte(); - String urlBase = sectionData.readString(urlBaseLength); - int extensionCount = sectionData.readUnsignedByte(); + while (sectionData.getBytePosition() < positionOfNextSection2) { + int urlBaseLength = sectionData.readBits(8); + byte[] urlBaseByteArray = new byte[urlBaseLength]; + sectionData.readBytes(urlBaseByteArray, 0, urlBaseLength); + String urlBase = new String(urlBaseByteArray, Charset.forName("ASCII")); + + int extensionCount = sectionData.readBits(8); aitUrlBase = urlBase; for (int i = 0; i < extensionCount; i++) { - int len = sectionData.readUnsignedByte(); + int len = sectionData.readBits(8); sectionData.skipBytes(len); } } } } else if(type == DESCRIPTOR_SIMPLE_APPLICATION_LOCATION) { - String url = sectionData.readString(l); + byte[] urlByteArray = new byte[l]; + sectionData.readBytes(urlByteArray, 0, l); + String url = new String(urlByteArray, Charset.forName("ASCII")); aitUrlExtension = url; } - sectionData.setPosition(positionOfNextSection2); + sectionData.setPosition(positionOfNextSection2*8); } - sectionData.setPosition(positionOfNextSection); + sectionData.setPosition(positionOfNextSection*8); if(aitControlCode != -1 && aitUrlBase != null && aitUrlExtension != null) { aits.add(new Ait(aitControlCode, aitUrlBase + aitUrlExtension));