Don't use ParsableBitArray to parse TS packet headers

Really low hanging fruit optimization for TS extraction.

ParsableBitArray is quite expensive. In particular readBits
contains at least 2 if blocks and a for loop, and was being
called 5 times per 188 byte packet (4 times via readBit). A
separate change will follow that optimizes readBit, but for
this particular case there's no real value to using a
ParsableBitArray anyway; use of ParsableBitArray IMO only
really becomes useful when you need to parse a bitstream more
than 4 bytes long, or where parsing the bitstream requires
some control flow (if/for) to parse.

There are probably other places where we're using
ParsableBitArray over-zealously. I'll roll that into a
tracking bug for looking in more detail at all extractors.

Issue: #3040

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161650940
This commit is contained in:
olly 2017-07-12 04:47:31 -07:00 committed by Oliver Woodman
parent ecc8f6c4fa
commit 2b1614cc7b

View File

@ -111,7 +111,6 @@ public final class TsExtractor implements Extractor {
@Mode private final int mode;
private final List<TimestampAdjuster> timestampAdjusters;
private final ParsableByteArray tsPacketBuffer;
private final ParsableBitArray tsScratch;
private final SparseIntArray continuityCounters;
private final TsPayloadReader.Factory payloadReaderFactory;
private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
@ -164,7 +163,6 @@ public final class TsExtractor implements Extractor {
timestampAdjusters.add(timestampAdjuster);
}
tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE);
tsScratch = new ParsableBitArray(new byte[3]);
trackIds = new SparseBooleanArray();
tsPayloadReaders = new SparseArray<>();
continuityCounters = new SparseIntArray();
@ -250,24 +248,23 @@ public final class TsExtractor implements Extractor {
return RESULT_CONTINUE;
}
tsPacketBuffer.skipBytes(1);
tsPacketBuffer.readBytes(tsScratch, 3);
if (tsScratch.readBit()) { // transport_error_indicator
int tsPacketHeader = tsPacketBuffer.readInt();
if ((tsPacketHeader & 0x800000) != 0) { // transport_error_indicator
// There are uncorrectable errors in this packet.
tsPacketBuffer.setPosition(endOfPacket);
return RESULT_CONTINUE;
}
boolean payloadUnitStartIndicator = tsScratch.readBit();
tsScratch.skipBits(1); // transport_priority
int pid = tsScratch.readBits(13);
tsScratch.skipBits(2); // transport_scrambling_control
boolean adaptationFieldExists = tsScratch.readBit();
boolean payloadExists = tsScratch.readBit();
boolean payloadUnitStartIndicator = (tsPacketHeader & 0x400000) != 0;
// Ignoring transport_priority (tsPacketHeader & 0x200000)
int pid = (tsPacketHeader & 0x1FFF00) >> 8;
// Ignoring transport_scrambling_control (tsPacketHeader & 0xC0)
boolean adaptationFieldExists = (tsPacketHeader & 0x20) != 0;
boolean payloadExists = (tsPacketHeader & 0x10) != 0;
// Discontinuity check.
boolean discontinuityFound = false;
int continuityCounter = tsScratch.readBits(4);
if (mode != MODE_HLS) {
int continuityCounter = tsPacketHeader & 0xF;
int previousCounter = continuityCounters.get(pid, continuityCounter - 1);
continuityCounters.put(pid, continuityCounter);
if (previousCounter == continuityCounter) {
@ -276,7 +273,7 @@ public final class TsExtractor implements Extractor {
tsPacketBuffer.setPosition(endOfPacket);
return RESULT_CONTINUE;
}
} else if (continuityCounter != (previousCounter + 1) % 16) {
} else if (continuityCounter != ((previousCounter + 1) & 0xF)) {
discontinuityFound = true;
}
}
@ -296,7 +293,6 @@ public final class TsExtractor implements Extractor {
}
tsPacketBuffer.setLimit(endOfPacket);
payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator);
Assertions.checkState(tsPacketBuffer.getPosition() <= endOfPacket);
tsPacketBuffer.setLimit(limit);
}
}