Add H265 support to depacketizer

This commit is contained in:
Cameron Gutman 2015-12-12 01:32:07 -08:00
parent adcffa62d8
commit d8c7d10ed6
2 changed files with 28 additions and 22 deletions

View File

@ -3,14 +3,9 @@ package com.limelight.nvstream.av;
import com.limelight.nvstream.av.video.VideoPacket; import com.limelight.nvstream.av.video.VideoPacket;
public class DecodeUnit { public class DecodeUnit {
public static final int TYPE_UNKNOWN = 0;
public static final int TYPE_H264 = 1;
public static final int TYPE_OPUS = 2;
public static final int DU_FLAG_CODEC_CONFIG = 0x1; public static final int DU_FLAG_CODEC_CONFIG = 0x1;
public static final int DU_FLAG_SYNC_FRAME = 0x2; public static final int DU_FLAG_SYNC_FRAME = 0x2;
private int type;
private ByteBufferDescriptor bufferHead; private ByteBufferDescriptor bufferHead;
private int dataLength; private int dataLength;
private int frameNumber; private int frameNumber;
@ -21,10 +16,9 @@ public class DecodeUnit {
public DecodeUnit() { public DecodeUnit() {
} }
public void initialize(int type, ByteBufferDescriptor bufferHead, int dataLength, public void initialize(ByteBufferDescriptor bufferHead, int dataLength,
int frameNumber, long receiveTimestamp, int flags, VideoPacket backingPacketHead) int frameNumber, long receiveTimestamp, int flags, VideoPacket backingPacketHead)
{ {
this.type = type;
this.bufferHead = bufferHead; this.bufferHead = bufferHead;
this.dataLength = dataLength; this.dataLength = dataLength;
this.frameNumber = frameNumber; this.frameNumber = frameNumber;
@ -33,11 +27,6 @@ public class DecodeUnit {
this.backingPacketHead = backingPacketHead; this.backingPacketHead = backingPacketHead;
} }
public int getType()
{
return type;
}
public long getReceiveTimestamp() public long getReceiveTimestamp()
{ {
return receiveTimestamp; return receiveTimestamp;

View File

@ -130,11 +130,23 @@ public class VideoDepacketizer {
int flags = 0; int flags = 0;
if (NAL.getSpecialSequenceDescriptor(firstBuffer, cachedSpecialDesc) && NAL.isAnnexBFrameStart(cachedSpecialDesc)) { if (NAL.getSpecialSequenceDescriptor(firstBuffer, cachedSpecialDesc) && NAL.isAnnexBFrameStart(cachedSpecialDesc)) {
switch (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length]) { switch (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length]) {
case 0x67:
case 0x68: // H265
case 0x40: // VPS
case 0x42: // SPS
case 0x44: // PPS
flags |= DecodeUnit.DU_FLAG_CODEC_CONFIG; flags |= DecodeUnit.DU_FLAG_CODEC_CONFIG;
break; break;
case 0x65: case 0x26: // I-frame
flags |= DecodeUnit.DU_FLAG_SYNC_FRAME;
break;
// H264
case 0x67: // SPS
case 0x68: // PPS
flags |= DecodeUnit.DU_FLAG_CODEC_CONFIG;
break;
case 0x65: // I-frame
flags |= DecodeUnit.DU_FLAG_SYNC_FRAME; flags |= DecodeUnit.DU_FLAG_SYNC_FRAME;
break; break;
} }
@ -159,8 +171,8 @@ public class VideoDepacketizer {
} }
// Initialize the free DU // Initialize the free DU
du.initialize(DecodeUnit.TYPE_H264, frameDataChainHead, du.initialize(frameDataChainHead, frameDataLength, frameNumber,
frameDataLength, frameNumber, frameStartTime, flags, backingPacketHead); frameStartTime, flags, backingPacketHead);
// Packets now owned by the DU // Packets now owned by the DU
backingPacketTail = backingPacketHead = null; backingPacketTail = backingPacketHead = null;
@ -233,7 +245,8 @@ public class VideoDepacketizer {
// Reassemble any pending NAL // Reassemble any pending NAL
reassembleFrame(packet.getFrameIndex()); reassembleFrame(packet.getFrameIndex());
if (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x65) { if (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x65 || // H264 I-Frame
cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x26) { // H265 I-Frame
// This is the NALU code for I-frame data // This is the NALU code for I-frame data
waitingForIdrFrame = false; waitingForIdrFrame = false;
} }
@ -433,10 +446,7 @@ public class VideoDepacketizer {
} }
lastPacketInStream = streamPacketIndex; lastPacketInStream = streamPacketIndex;
if (firstPacket if (firstPacket && isIdrFrameStart(cachedReassemblyDesc))
&& NAL.getSpecialSequenceDescriptor(cachedReassemblyDesc, cachedSpecialDesc)
&& NAL.isAnnexBFrameStart(cachedSpecialDesc)
&& cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x67)
{ {
// The slow path doesn't update the frame start time by itself // The slow path doesn't update the frame start time by itself
frameStartTime = TimeHelper.getMonotonicMillis(); frameStartTime = TimeHelper.getMonotonicMillis();
@ -477,6 +487,13 @@ public class VideoDepacketizer {
} }
} }
private boolean isIdrFrameStart(ByteBufferDescriptor desc) {
return NAL.getSpecialSequenceDescriptor(desc, cachedSpecialDesc) &&
NAL.isAnnexBFrameStart(cachedSpecialDesc) &&
(cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x67 || // H264 SPS
cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x40); // H265 VPS
}
public DecodeUnit takeNextDecodeUnit() throws InterruptedException public DecodeUnit takeNextDecodeUnit() throws InterruptedException
{ {
return decodedUnits.takePopulatedObject(); return decodedUnits.takePopulatedObject();