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