mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Some cleanup to TS H264/H265 readers.
This commit is contained in:
parent
d96fe37c05
commit
b1e4283058
2 changed files with 87 additions and 87 deletions
|
|
@ -102,56 +102,60 @@ 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.
|
|
||||||
|
|
||||||
// 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.
|
||||||
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 {
|
|
||||||
feedNalUnitTargetBuffersData(dataArray, offset, limit);
|
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) {
|
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;
|
||||||
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,32 +101,34 @@ 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.
|
||||||
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 {
|
|
||||||
nalUnitData(dataArray, offset, limit);
|
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);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue