From d8c7d10ed682434c20230303c3882e4d1d009b26 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 12 Dec 2015 01:32:07 -0800 Subject: [PATCH] Add H265 support to depacketizer --- .../com/limelight/nvstream/av/DecodeUnit.java | 13 +------ .../nvstream/av/video/VideoDepacketizer.java | 37 ++++++++++++++----- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/moonlight-common/src/com/limelight/nvstream/av/DecodeUnit.java b/moonlight-common/src/com/limelight/nvstream/av/DecodeUnit.java index cdce37d7..9403e9bd 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/DecodeUnit.java +++ b/moonlight-common/src/com/limelight/nvstream/av/DecodeUnit.java @@ -3,14 +3,9 @@ package com.limelight.nvstream.av; import com.limelight.nvstream.av.video.VideoPacket; 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_SYNC_FRAME = 0x2; - private int type; private ByteBufferDescriptor bufferHead; private int dataLength; private int frameNumber; @@ -21,10 +16,9 @@ public class 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) { - this.type = type; this.bufferHead = bufferHead; this.dataLength = dataLength; this.frameNumber = frameNumber; @@ -33,11 +27,6 @@ public class DecodeUnit { this.backingPacketHead = backingPacketHead; } - public int getType() - { - return type; - } - public long getReceiveTimestamp() { return receiveTimestamp; diff --git a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java index 2b8db6df..6bbb3291 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java +++ b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java @@ -130,11 +130,23 @@ public class VideoDepacketizer { int flags = 0; if (NAL.getSpecialSequenceDescriptor(firstBuffer, cachedSpecialDesc) && NAL.isAnnexBFrameStart(cachedSpecialDesc)) { 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; 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; break; } @@ -159,8 +171,8 @@ public class VideoDepacketizer { } // Initialize the free DU - du.initialize(DecodeUnit.TYPE_H264, frameDataChainHead, - frameDataLength, frameNumber, frameStartTime, flags, backingPacketHead); + du.initialize(frameDataChainHead, frameDataLength, frameNumber, + frameStartTime, flags, backingPacketHead); // Packets now owned by the DU backingPacketTail = backingPacketHead = null; @@ -233,7 +245,8 @@ public class VideoDepacketizer { // Reassemble any pending NAL 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 waitingForIdrFrame = false; } @@ -433,10 +446,7 @@ public class VideoDepacketizer { } lastPacketInStream = streamPacketIndex; - if (firstPacket - && NAL.getSpecialSequenceDescriptor(cachedReassemblyDesc, cachedSpecialDesc) - && NAL.isAnnexBFrameStart(cachedSpecialDesc) - && cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x67) + if (firstPacket && isIdrFrameStart(cachedReassemblyDesc)) { // The slow path doesn't update the frame start time by itself 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 { return decodedUnits.takePopulatedObject();