Commit b1e42830 by Oliver Woodman

Some cleanup to TS H264/H265 readers.

parent d96fe37c
...@@ -102,25 +102,31 @@ import java.util.List; ...@@ -102,25 +102,31 @@ import java.util.List;
output.sampleData(data, data.bytesLeft()); output.sampleData(data, data.bytesLeft());
// Scan the appended data, processing NAL units as they are encountered // Scan the appended data, processing NAL units as they are encountered
while (offset < limit) { while (true) {
int nextNalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags); int nalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags);
if (nextNalUnitOffset < limit) {
// We've seen the start of a NAL unit. if (nalUnitOffset == limit) {
// We've scanned to the end of the data without finding the start of another NAL unit.
// This is the length to the start of the unit. It may be negative if the NAL unit feedNalUnitTargetBuffersData(dataArray, offset, limit);
// actually started in previously consumed data. return;
int lengthToNalUnit = nextNalUnitOffset - offset; }
// We've seen the start of a NAL unit of the following type.
int nalUnitType = NalUnitUtil.getNalUnitType(dataArray, nalUnitOffset);
// This is the number of bytes from the current offset to the start of the next NAL unit.
// It may be negative if the NAL unit started in the previously consumed data.
int lengthToNalUnit = nalUnitOffset - offset;
if (lengthToNalUnit > 0) { if (lengthToNalUnit > 0) {
feedNalUnitTargetBuffersData(dataArray, offset, nextNalUnitOffset); feedNalUnitTargetBuffersData(dataArray, offset, nalUnitOffset);
} }
int nalUnitType = NalUnitUtil.getNalUnitType(dataArray, nextNalUnitOffset);
int bytesWrittenPastNalUnit = limit - nextNalUnitOffset;
switch (nalUnitType) { switch (nalUnitType) {
case NAL_UNIT_TYPE_IDR: case NAL_UNIT_TYPE_IDR:
isKeyframe = true; isKeyframe = true;
break; break;
case NAL_UNIT_TYPE_AUD: case NAL_UNIT_TYPE_AUD:
int bytesWrittenPastNalUnit = limit - nalUnitOffset;
if (foundFirstSample) { if (foundFirstSample) {
if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) { if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) {
int sliceType = ifrParserBuffer.getSliceType(); int sliceType = ifrParserBuffer.getSliceType();
...@@ -128,7 +134,8 @@ import java.util.List; ...@@ -128,7 +134,8 @@ import java.util.List;
ifrParserBuffer.reset(); ifrParserBuffer.reset();
} }
if (isKeyframe && !hasOutputFormat && sps.isCompleted() && pps.isCompleted()) { if (isKeyframe && !hasOutputFormat && sps.isCompleted() && pps.isCompleted()) {
parseMediaFormat(sps, pps); output.format(parseMediaFormat(sps, pps));
hasOutputFormat = true;
} }
int flags = isKeyframe ? C.SAMPLE_FLAG_SYNC : 0; int flags = isKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastNalUnit; int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastNalUnit;
...@@ -141,17 +148,14 @@ import java.util.List; ...@@ -141,17 +148,14 @@ import java.util.List;
break; break;
} }
// If the length to the start of the unit is negative then we wrote too many bytes to the // Indicate the end of the previous NAL unit. If the length to the start of the next unit
// NAL buffers. Discard the excess bytes when notifying that the unit has ended. // is negative then we wrote too many bytes to the NAL buffers. Discard the excess bytes
// when notifying that the unit has ended.
feedNalUnitTargetEnd(pesTimeUs, lengthToNalUnit < 0 ? -lengthToNalUnit : 0); feedNalUnitTargetEnd(pesTimeUs, lengthToNalUnit < 0 ? -lengthToNalUnit : 0);
// Notify the start of the next NAL unit. // Indicate the start of the next NAL unit.
feedNalUnitTargetBuffersStart(nalUnitType); feedNalUnitTargetBuffersStart(nalUnitType);
// Continue scanning the data. // Continue scanning the data.
offset = nextNalUnitOffset + 3; offset = nalUnitOffset + 3;
} else {
feedNalUnitTargetBuffersData(dataArray, offset, limit);
offset = limit;
}
} }
} }
} }
...@@ -194,14 +198,10 @@ import java.util.List; ...@@ -194,14 +198,10 @@ import java.util.List;
} }
} }
private void parseMediaFormat(NalUnitTargetBuffer sps, NalUnitTargetBuffer pps) { private static MediaFormat parseMediaFormat(NalUnitTargetBuffer sps, NalUnitTargetBuffer pps) {
byte[] spsData = new byte[sps.nalLength];
byte[] ppsData = new byte[pps.nalLength];
System.arraycopy(sps.nalData, 0, spsData, 0, sps.nalLength);
System.arraycopy(pps.nalData, 0, ppsData, 0, pps.nalLength);
List<byte[]> initializationData = new ArrayList<>(); List<byte[]> initializationData = new ArrayList<>();
initializationData.add(spsData); initializationData.add(Arrays.copyOf(sps.nalData, sps.nalLength));
initializationData.add(ppsData); initializationData.add(Arrays.copyOf(pps.nalData, pps.nalLength));
// Unescape and parse the SPS unit. // Unescape and parse the SPS unit.
NalUnitUtil.unescapeStream(sps.nalData, sps.nalLength); NalUnitUtil.unescapeStream(sps.nalData, sps.nalLength);
...@@ -209,11 +209,9 @@ import java.util.List; ...@@ -209,11 +209,9 @@ import java.util.List;
bitArray.skipBits(32); // NAL header bitArray.skipBits(32); // NAL header
SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray); SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray);
// Construct and output the format. return MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
output.format(MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height,
initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio)); initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio);
hasOutputFormat = true;
} }
/** /**
......
...@@ -101,15 +101,23 @@ import java.util.Collections; ...@@ -101,15 +101,23 @@ import java.util.Collections;
// Scan the appended data, processing NAL units as they are encountered // Scan the appended data, processing NAL units as they are encountered
while (offset < limit) { while (offset < limit) {
int nalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags); int nalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags);
if (nalUnitOffset < limit) {
// We've seen the start of a NAL unit.
// This is the length to the start of the unit. It may be negative if the NAL unit if (nalUnitOffset == limit) {
// actually started in previously consumed data. // We've scanned to the end of the data without finding the start of another NAL unit.
nalUnitData(dataArray, offset, limit);
return;
}
// We've seen the start of a NAL unit of the following type.
int nalUnitType = NalUnitUtil.getH265NalUnitType(dataArray, nalUnitOffset);
// This is the number of bytes from the current offset to the start of the next NAL unit.
// It may be negative if the NAL unit started in the previously consumed data.
int lengthToNalUnit = nalUnitOffset - offset; int lengthToNalUnit = nalUnitOffset - offset;
if (lengthToNalUnit > 0) { if (lengthToNalUnit > 0) {
nalUnitData(dataArray, offset, nalUnitOffset); nalUnitData(dataArray, offset, nalUnitOffset);
} }
int bytesWrittenPastPosition = limit - nalUnitOffset; int bytesWrittenPastPosition = limit - nalUnitOffset;
long absolutePosition = totalBytesWritten - bytesWrittenPastPosition; long absolutePosition = totalBytesWritten - bytesWrittenPastPosition;
// Indicate the end of the previous NAL unit. If the length to the start of the next unit // Indicate the end of the previous NAL unit. If the length to the start of the next unit
...@@ -117,16 +125,10 @@ import java.util.Collections; ...@@ -117,16 +125,10 @@ import java.util.Collections;
// when notifying that the unit has ended. // when notifying that the unit has ended.
nalUnitEnd(absolutePosition, bytesWrittenPastPosition, nalUnitEnd(absolutePosition, bytesWrittenPastPosition,
lengthToNalUnit < 0 ? -lengthToNalUnit : 0, pesTimeUs); lengthToNalUnit < 0 ? -lengthToNalUnit : 0, pesTimeUs);
// Indicate the start of the next NAL unit. // Indicate the start of the next NAL unit.
int nalUnitType = NalUnitUtil.getH265NalUnitType(dataArray, nalUnitOffset);
startNalUnit(absolutePosition, bytesWrittenPastPosition, nalUnitType, pesTimeUs); startNalUnit(absolutePosition, bytesWrittenPastPosition, nalUnitType, pesTimeUs);
// Continue scanning the data. // Continue scanning the data.
offset = nalUnitOffset + 3; offset = nalUnitOffset + 3;
} else {
nalUnitData(dataArray, offset, limit);
offset = limit;
}
} }
} }
} }
...@@ -167,7 +169,8 @@ import java.util.Collections; ...@@ -167,7 +169,8 @@ import java.util.Collections;
sps.endNalUnit(discardPadding); sps.endNalUnit(discardPadding);
pps.endNalUnit(discardPadding); pps.endNalUnit(discardPadding);
if (vps.isCompleted() && sps.isCompleted() && pps.isCompleted()) { if (vps.isCompleted() && sps.isCompleted() && pps.isCompleted()) {
parseMediaFormat(vps, sps, pps); output.format(parseMediaFormat(vps, sps, pps));
hasOutputFormat = true;
} }
} }
if (prefixSei.endNalUnit(discardPadding)) { if (prefixSei.endNalUnit(discardPadding)) {
...@@ -188,7 +191,7 @@ import java.util.Collections; ...@@ -188,7 +191,7 @@ import java.util.Collections;
} }
} }
private void parseMediaFormat(NalUnitTargetBuffer vps, NalUnitTargetBuffer sps, private static MediaFormat parseMediaFormat(NalUnitTargetBuffer vps, NalUnitTargetBuffer sps,
NalUnitTargetBuffer pps) { NalUnitTargetBuffer pps) {
// Build codec-specific data. // Build codec-specific data.
byte[] csd = new byte[vps.nalLength + sps.nalLength + pps.nalLength]; byte[] csd = new byte[vps.nalLength + sps.nalLength + pps.nalLength];
...@@ -294,14 +297,13 @@ import java.util.Collections; ...@@ -294,14 +297,13 @@ import java.util.Collections;
} }
} }
output.format(MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE, return MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples,
Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio)); Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio);
hasOutputFormat = true;
} }
/** Skips scaling_list_data(). See H.265/HEVC (2014) 7.3.4. */ /** Skips scaling_list_data(). See H.265/HEVC (2014) 7.3.4. */
private void skipScalingList(ParsableBitArray bitArray) { private static void skipScalingList(ParsableBitArray bitArray) {
for (int sizeId = 0; sizeId < 4; sizeId++) { for (int sizeId = 0; sizeId < 4; sizeId++) {
for (int matrixId = 0; matrixId < 6; matrixId += sizeId == 3 ? 3 : 1) { for (int matrixId = 0; matrixId < 6; matrixId += sizeId == 3 ? 3 : 1) {
if (!bitArray.readBit()) { // scaling_list_pred_mode_flag[sizeId][matrixId] if (!bitArray.readBit()) { // scaling_list_pred_mode_flag[sizeId][matrixId]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment