Commit 5b186a2a by Andrew Lewis

Add support for reading H.265 in MPEG TS.

parent 02d5cb81
...@@ -77,7 +77,7 @@ import java.util.List; ...@@ -77,7 +77,7 @@ import java.util.List;
private final NalUnitTargetBuffer sps; private final NalUnitTargetBuffer sps;
private final NalUnitTargetBuffer pps; private final NalUnitTargetBuffer pps;
private final NalUnitTargetBuffer sei; private final NalUnitTargetBuffer sei;
private boolean writingSample; private boolean foundFirstSample;
private long totalBytesWritten; private long totalBytesWritten;
// Per sample state that gets reset at the start of each sample. // Per sample state that gets reset at the start of each sample.
...@@ -111,7 +111,7 @@ import java.util.List; ...@@ -111,7 +111,7 @@ import java.util.List;
if (ifrParserBuffer != null) { if (ifrParserBuffer != null) {
ifrParserBuffer.reset(); ifrParserBuffer.reset();
} }
writingSample = false; foundFirstSample = false;
totalBytesWritten = 0; totalBytesWritten = 0;
} }
...@@ -146,7 +146,7 @@ import java.util.List; ...@@ -146,7 +146,7 @@ import java.util.List;
isKeyframe = true; isKeyframe = true;
break; break;
case NAL_UNIT_TYPE_AUD: case NAL_UNIT_TYPE_AUD:
if (writingSample) { if (foundFirstSample) {
if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) { if (ifrParserBuffer != null && ifrParserBuffer.isCompleted()) {
int sliceType = ifrParserBuffer.getSliceType(); int sliceType = ifrParserBuffer.getSliceType();
isKeyframe |= (sliceType == FRAME_TYPE_I || sliceType == FRAME_TYPE_ALL_I); isKeyframe |= (sliceType == FRAME_TYPE_I || sliceType == FRAME_TYPE_ALL_I);
...@@ -158,9 +158,8 @@ import java.util.List; ...@@ -158,9 +158,8 @@ import java.util.List;
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;
output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastNalUnit, null); output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastNalUnit, null);
writingSample = false;
} }
writingSample = true; foundFirstSample = true;
samplePosition = totalBytesWritten - bytesWrittenPastNalUnit; samplePosition = totalBytesWritten - bytesWrittenPastNalUnit;
sampleTimeUs = pesTimeUs; sampleTimeUs = pesTimeUs;
isKeyframe = false; isKeyframe = false;
...@@ -215,6 +214,7 @@ import java.util.List; ...@@ -215,6 +214,7 @@ import java.util.List;
if (sei.endNalUnit(discardPadding)) { if (sei.endNalUnit(discardPadding)) {
int unescapedLength = unescapeStream(sei.nalData, sei.nalLength); int unescapedLength = unescapeStream(sei.nalData, sei.nalLength);
seiWrapper.reset(sei.nalData, unescapedLength); seiWrapper.reset(sei.nalData, unescapedLength);
seiWrapper.setPosition(4); // NAL prefix and nal_unit() header.
seiReader.consume(seiWrapper, pesTimeUs, true); seiReader.consume(seiWrapper, pesTimeUs, true);
} }
} }
...@@ -385,7 +385,7 @@ import java.util.List; ...@@ -385,7 +385,7 @@ import java.util.List;
return unescapedLength; return unescapedLength;
} }
private int findNextUnescapeIndex(byte[] bytes, int offset, int limit) { private static int findNextUnescapeIndex(byte[] bytes, int offset, int limit) {
for (int i = offset; i < limit - 2; i++) { for (int i = offset; i < limit - 2; i++) {
if (bytes[i] == 0x00 && bytes[i + 1] == 0x00 && bytes[i + 2] == 0x03) { if (bytes[i] == 0x00 && bytes[i + 1] == 0x00 && bytes[i + 2] == 0x03) {
return i; return i;
......
...@@ -41,9 +41,6 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -41,9 +41,6 @@ import com.google.android.exoplayer.util.ParsableByteArray;
@Override @Override
public void consume(ParsableByteArray seiBuffer, long pesTimeUs, boolean startOfPacket) { public void consume(ParsableByteArray seiBuffer, long pesTimeUs, boolean startOfPacket) {
// Skip the NAL prefix and type.
seiBuffer.skipBytes(4);
int b; int b;
while (seiBuffer.bytesLeft() > 1 /* last byte will be rbsp_trailing_bits */) { while (seiBuffer.bytesLeft() > 1 /* last byte will be rbsp_trailing_bits */) {
// Parse payload type. // Parse payload type.
......
...@@ -46,6 +46,7 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -46,6 +46,7 @@ public final class TsExtractor implements Extractor, SeekMap {
private static final int TS_STREAM_TYPE_ATSC_AC3 = 0x81; private static final int TS_STREAM_TYPE_ATSC_AC3 = 0x81;
private static final int TS_STREAM_TYPE_ATSC_E_AC3 = 0x87; private static final int TS_STREAM_TYPE_ATSC_E_AC3 = 0x87;
private static final int TS_STREAM_TYPE_H264 = 0x1B; private static final int TS_STREAM_TYPE_H264 = 0x1B;
private static final int TS_STREAM_TYPE_H265 = 0x24;
private static final int TS_STREAM_TYPE_ID3 = 0x15; private static final int TS_STREAM_TYPE_ID3 = 0x15;
private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1 private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1
...@@ -361,9 +362,12 @@ public final class TsExtractor implements Extractor, SeekMap { ...@@ -361,9 +362,12 @@ public final class TsExtractor implements Extractor, SeekMap {
pesPayloadReader = new Ac3Reader(output.track(streamType)); pesPayloadReader = new Ac3Reader(output.track(streamType));
break; break;
case TS_STREAM_TYPE_H264: case TS_STREAM_TYPE_H264:
SeiReader seiReader = new SeiReader(output.track(TS_STREAM_TYPE_EIA608)); pesPayloadReader = new H264Reader(output.track(TS_STREAM_TYPE_H264),
pesPayloadReader = new H264Reader(output.track(TS_STREAM_TYPE_H264), seiReader, new SeiReader(output.track(TS_STREAM_TYPE_EIA608)), idrKeyframesOnly);
idrKeyframesOnly); break;
case TS_STREAM_TYPE_H265:
pesPayloadReader = new H265Reader(output.track(TS_STREAM_TYPE_H265),
new SeiReader(output.track(TS_STREAM_TYPE_EIA608)));
break; break;
case TS_STREAM_TYPE_ID3: case TS_STREAM_TYPE_ID3:
pesPayloadReader = id3Reader; pesPayloadReader = id3Reader;
......
...@@ -65,6 +65,18 @@ public final class NalUnitUtil { ...@@ -65,6 +65,18 @@ public final class NalUnitUtil {
} }
/** /**
* Gets the type of the H.265 NAL unit in {@code data} that starts at {@code offset}.
*
* @param data The data to search.
* @param offset The start offset of a NAL unit. Must lie between {@code -3} (inclusive) and
* {@code data.length - 3} (exclusive).
* @return The type of the unit.
*/
public static int getH265NalUnitType(byte[] data, int offset) {
return (data[offset + 3] & 0x7E) >> 1;
}
/**
* Finds the first NAL unit in {@code data}. * Finds the first NAL unit in {@code data}.
* <p> * <p>
* If {@code prefixFlags} is null then the first four bytes of a NAL unit must be entirely * If {@code prefixFlags} is null then the first four bytes of a NAL unit must be entirely
......
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