From b1e4283058e1ec47fe9555dacbdb23b6e0f60063 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 17 Nov 2015 15:55:57 +0000 Subject: [PATCH] Some cleanup to TS H264/H265 readers. --- .../exoplayer/extractor/ts/H264Reader.java | 114 +++++++++--------- .../exoplayer/extractor/ts/H265Reader.java | 60 ++++----- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java index 2490803b87..0465e6f573 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java @@ -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 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); } /** diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java index 7756bd13ac..2ce1e3ec39 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java @@ -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]