Some cleanup to TS H264/H265 readers.

This commit is contained in:
Oliver Woodman 2015-11-17 15:55:57 +00:00
parent d96fe37c05
commit b1e4283058
2 changed files with 87 additions and 87 deletions

View file

@ -102,56 +102,60 @@ import java.util.List;
output.sampleData(data, data.bytesLeft());
// Scan the appended data, processing NAL units as they are encountered
while (offset < limit) {
int nextNalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags);
if (nextNalUnitOffset < limit) {
// We've seen the start of a NAL unit.
while (true) {
int nalUnitOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags);
// This is the length to the start of the unit. It may be negative if the NAL unit
// actually started in previously consumed data.
int lengthToNalUnit = nextNalUnitOffset - offset;
if (lengthToNalUnit > 0) {
feedNalUnitTargetBuffersData(dataArray, offset, nextNalUnitOffset);
}
int nalUnitType = NalUnitUtil.getNalUnitType(dataArray, nextNalUnitOffset);
int bytesWrittenPastNalUnit = limit - nextNalUnitOffset;
switch (nalUnitType) {
case NAL_UNIT_TYPE_IDR:
isKeyframe = true;
break;
case NAL_UNIT_TYPE_AUD:
if (foundFirstSample) {
if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) {
int sliceType = ifrParserBuffer.getSliceType();
isKeyframe |= (sliceType == FRAME_TYPE_I || sliceType == FRAME_TYPE_ALL_I);
ifrParserBuffer.reset();
}
if (isKeyframe && !hasOutputFormat && sps.isCompleted() && pps.isCompleted()) {
parseMediaFormat(sps, pps);
}
int flags = isKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastNalUnit;
output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastNalUnit, null);
}
foundFirstSample = true;
samplePosition = totalBytesWritten - bytesWrittenPastNalUnit;
sampleTimeUs = pesTimeUs;
isKeyframe = false;
break;
}
// If the length to the start of the unit 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);
// Notify the start of the next NAL unit.
feedNalUnitTargetBuffersStart(nalUnitType);
// Continue scanning the data.
offset = nextNalUnitOffset + 3;
} else {
if (nalUnitOffset == limit) {
// We've scanned to the end of the data without finding the start of another NAL unit.
feedNalUnitTargetBuffersData(dataArray, offset, limit);
offset = limit;
return;
}
// 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) {
feedNalUnitTargetBuffersData(dataArray, offset, nalUnitOffset);
}
switch (nalUnitType) {
case NAL_UNIT_TYPE_IDR:
isKeyframe = true;
break;
case NAL_UNIT_TYPE_AUD:
int bytesWrittenPastNalUnit = limit - nalUnitOffset;
if (foundFirstSample) {
if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) {
int sliceType = ifrParserBuffer.getSliceType();
isKeyframe |= (sliceType == FRAME_TYPE_I || sliceType == FRAME_TYPE_ALL_I);
ifrParserBuffer.reset();
}
if (isKeyframe && !hasOutputFormat && sps.isCompleted() && pps.isCompleted()) {
output.format(parseMediaFormat(sps, pps));
hasOutputFormat = true;
}
int flags = isKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastNalUnit;
output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastNalUnit, null);
}
foundFirstSample = true;
samplePosition = totalBytesWritten - bytesWrittenPastNalUnit;
sampleTimeUs = pesTimeUs;
isKeyframe = false;
break;
}
// Indicate the end of the previous NAL unit. If the length to the start of the next unit
// 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);
// Indicate the start of the next NAL unit.
feedNalUnitTargetBuffersStart(nalUnitType);
// Continue scanning the data.
offset = nalUnitOffset + 3;
}
}
}
@ -194,14 +198,10 @@ import java.util.List;
}
}
private void 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);
private static MediaFormat parseMediaFormat(NalUnitTargetBuffer sps, NalUnitTargetBuffer pps) {
List<byte[]> initializationData = new ArrayList<>();
initializationData.add(spsData);
initializationData.add(ppsData);
initializationData.add(Arrays.copyOf(sps.nalData, sps.nalLength));
initializationData.add(Arrays.copyOf(pps.nalData, pps.nalLength));
// Unescape and parse the SPS unit.
NalUnitUtil.unescapeStream(sps.nalData, sps.nalLength);
@ -209,11 +209,9 @@ import java.util.List;
bitArray.skipBits(32); // NAL header
SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray);
// Construct and output the format.
output.format(MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
return MediaFormat.createVideoFormat(null, MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height,
initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio));
hasOutputFormat = true;
initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio);
}
/**

View file

@ -101,32 +101,34 @@ import java.util.Collections;
// Scan the appended data, processing NAL units as they are encountered
while (offset < limit) {
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
// actually started in previously consumed data.
int lengthToNalUnit = nalUnitOffset - offset;
if (lengthToNalUnit > 0) {
nalUnitData(dataArray, offset, nalUnitOffset);
}
int bytesWrittenPastPosition = limit - nalUnitOffset;
long absolutePosition = totalBytesWritten - bytesWrittenPastPosition;
// Indicate the end of the previous NAL unit. If the length to the start of the next unit
// is negative then we wrote too many bytes to the NAL buffers. Discard the excess bytes
// when notifying that the unit has ended.
nalUnitEnd(absolutePosition, bytesWrittenPastPosition,
lengthToNalUnit < 0 ? -lengthToNalUnit : 0, pesTimeUs);
// Indicate the start of the next NAL unit.
int nalUnitType = NalUnitUtil.getH265NalUnitType(dataArray, nalUnitOffset);
startNalUnit(absolutePosition, bytesWrittenPastPosition, nalUnitType, pesTimeUs);
// Continue scanning the data.
offset = nalUnitOffset + 3;
} else {
if (nalUnitOffset == limit) {
// We've scanned to the end of the data without finding the start of another NAL unit.
nalUnitData(dataArray, offset, limit);
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;
if (lengthToNalUnit > 0) {
nalUnitData(dataArray, offset, nalUnitOffset);
}
int bytesWrittenPastPosition = limit - nalUnitOffset;
long absolutePosition = totalBytesWritten - bytesWrittenPastPosition;
// Indicate the end of the previous NAL unit. If the length to the start of the next unit
// is negative then we wrote too many bytes to the NAL buffers. Discard the excess bytes
// when notifying that the unit has ended.
nalUnitEnd(absolutePosition, bytesWrittenPastPosition,
lengthToNalUnit < 0 ? -lengthToNalUnit : 0, pesTimeUs);
// Indicate the start of the next NAL unit.
startNalUnit(absolutePosition, bytesWrittenPastPosition, nalUnitType, pesTimeUs);
// Continue scanning the data.
offset = nalUnitOffset + 3;
}
}
}
@ -167,7 +169,8 @@ import java.util.Collections;
sps.endNalUnit(discardPadding);
pps.endNalUnit(discardPadding);
if (vps.isCompleted() && sps.isCompleted() && pps.isCompleted()) {
parseMediaFormat(vps, sps, pps);
output.format(parseMediaFormat(vps, sps, pps));
hasOutputFormat = true;
}
}
if (prefixSei.endNalUnit(discardPadding)) {
@ -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) {
// Build codec-specific data.
byte[] csd = new byte[vps.nalLength + sps.nalLength + pps.nalLength];
@ -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,
Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio));
hasOutputFormat = true;
Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio);
}
/** 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 matrixId = 0; matrixId < 6; matrixId += sizeId == 3 ? 3 : 1) {
if (!bitArray.readBit()) { // scaling_list_pred_mode_flag[sizeId][matrixId]