mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-21 12:03:02 +00:00
Refactor depacketizer to avoid H264 and AVC references -- no behavior changes
This commit is contained in:
parent
260d716eb8
commit
adcffa62d8
@ -14,7 +14,7 @@ import com.limelight.utils.TimeHelper;
|
|||||||
public class VideoDepacketizer {
|
public class VideoDepacketizer {
|
||||||
|
|
||||||
// Current frame state
|
// Current frame state
|
||||||
private int avcFrameDataLength = 0;
|
private int frameDataLength = 0;
|
||||||
private ByteBufferDescriptor frameDataChainHead;
|
private ByteBufferDescriptor frameDataChainHead;
|
||||||
private ByteBufferDescriptor frameDataChainTail;
|
private ByteBufferDescriptor frameDataChainTail;
|
||||||
private VideoPacket backingPacketHead;
|
private VideoPacket backingPacketHead;
|
||||||
@ -84,7 +84,7 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dropAvcFrameState()
|
private void dropFrameState()
|
||||||
{
|
{
|
||||||
// We'll need an IDR frame now if we're in strict mode
|
// We'll need an IDR frame now if we're in strict mode
|
||||||
if (strictIdrFrameWait) {
|
if (strictIdrFrameWait) {
|
||||||
@ -106,10 +106,10 @@ public class VideoDepacketizer {
|
|||||||
controlListener.connectionDetectedFrameLoss(0, 0);
|
controlListener.connectionDetectedFrameLoss(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupAvcFrameState();
|
cleanupFrameState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupAvcFrameState()
|
private void cleanupFrameState()
|
||||||
{
|
{
|
||||||
backingPacketTail = null;
|
backingPacketTail = null;
|
||||||
while (backingPacketHead != null) {
|
while (backingPacketHead != null) {
|
||||||
@ -118,17 +118,17 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
frameDataChainHead = frameDataChainTail = null;
|
frameDataChainHead = frameDataChainTail = null;
|
||||||
avcFrameDataLength = 0;
|
frameDataLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reassembleAvcFrame(int frameNumber)
|
private void reassembleFrame(int frameNumber)
|
||||||
{
|
{
|
||||||
// This is the start of a new frame
|
// This is the start of a new frame
|
||||||
if (frameDataChainHead != null) {
|
if (frameDataChainHead != null) {
|
||||||
ByteBufferDescriptor firstBuffer = frameDataChainHead;
|
ByteBufferDescriptor firstBuffer = frameDataChainHead;
|
||||||
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (NAL.getSpecialSequenceDescriptor(firstBuffer, cachedSpecialDesc) && NAL.isAvcFrameStart(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 0x67:
|
||||||
case 0x68:
|
case 0x68:
|
||||||
@ -140,7 +140,7 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the H264 decode unit
|
// Construct the video decode unit
|
||||||
DecodeUnit du = decodedUnits.pollFreeObject();
|
DecodeUnit du = decodedUnits.pollFreeObject();
|
||||||
if (du == null) {
|
if (du == null) {
|
||||||
LimeLog.warning("Video decoder is too slow! Forced to drop decode units");
|
LimeLog.warning("Video decoder is too slow! Forced to drop decode units");
|
||||||
@ -154,13 +154,13 @@ public class VideoDepacketizer {
|
|||||||
decodedUnits.clearPopulatedObjects();
|
decodedUnits.clearPopulatedObjects();
|
||||||
|
|
||||||
// Clear frame state and wait for an IDR
|
// Clear frame state and wait for an IDR
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the free DU
|
// Initialize the free DU
|
||||||
du.initialize(DecodeUnit.TYPE_H264, frameDataChainHead,
|
du.initialize(DecodeUnit.TYPE_H264, frameDataChainHead,
|
||||||
avcFrameDataLength, frameNumber, frameStartTime, flags, backingPacketHead);
|
frameDataLength, frameNumber, frameStartTime, flags, backingPacketHead);
|
||||||
|
|
||||||
// Packets now owned by the DU
|
// Packets now owned by the DU
|
||||||
backingPacketTail = backingPacketHead = null;
|
backingPacketTail = backingPacketHead = null;
|
||||||
@ -171,7 +171,7 @@ public class VideoDepacketizer {
|
|||||||
decodedUnits.addPopulatedObject(du);
|
decodedUnits.addPopulatedObject(du);
|
||||||
|
|
||||||
// Clear old state
|
// Clear old state
|
||||||
cleanupAvcFrameState();
|
cleanupFrameState();
|
||||||
|
|
||||||
// Clear frame drops
|
// Clear frame drops
|
||||||
consecutiveFrameDrops = 0;
|
consecutiveFrameDrops = 0;
|
||||||
@ -190,7 +190,7 @@ public class VideoDepacketizer {
|
|||||||
frameDataChainHead = frameDataChainTail = desc;
|
frameDataChainHead = frameDataChainTail = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
avcFrameDataLength += desc.length;
|
frameDataLength += desc.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chainPacketToCurrentFrame(VideoPacket packet) {
|
private void chainPacketToCurrentFrame(VideoPacket packet) {
|
||||||
@ -209,7 +209,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
private void addInputDataSlow(VideoPacket packet, ByteBufferDescriptor location)
|
private void addInputDataSlow(VideoPacket packet, ByteBufferDescriptor location)
|
||||||
{
|
{
|
||||||
boolean isDecodingH264 = false;
|
boolean isDecodingVideoData = false;
|
||||||
|
|
||||||
while (location.length != 0)
|
while (location.length != 0)
|
||||||
{
|
{
|
||||||
@ -219,19 +219,19 @@ public class VideoDepacketizer {
|
|||||||
// Check for a special sequence
|
// Check for a special sequence
|
||||||
if (NAL.getSpecialSequenceDescriptor(location, cachedSpecialDesc))
|
if (NAL.getSpecialSequenceDescriptor(location, cachedSpecialDesc))
|
||||||
{
|
{
|
||||||
if (NAL.isAvcStartSequence(cachedSpecialDesc))
|
if (NAL.isAnnexBStartSequence(cachedSpecialDesc))
|
||||||
{
|
{
|
||||||
// We're decoding H264 now
|
// We're decoding video data now
|
||||||
isDecodingH264 = true;
|
isDecodingVideoData = true;
|
||||||
|
|
||||||
// Check if it's the end of the last frame
|
// Check if it's the end of the last frame
|
||||||
if (NAL.isAvcFrameStart(cachedSpecialDesc))
|
if (NAL.isAnnexBFrameStart(cachedSpecialDesc))
|
||||||
{
|
{
|
||||||
// Update the global state that we're decoding a new frame
|
// Update the global state that we're decoding a new frame
|
||||||
this.decodingFrame = true;
|
this.decodingFrame = true;
|
||||||
|
|
||||||
// Reassemble any pending AVC NAL
|
// Reassemble any pending NAL
|
||||||
reassembleAvcFrame(packet.getFrameIndex());
|
reassembleFrame(packet.getFrameIndex());
|
||||||
|
|
||||||
if (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x65) {
|
if (cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x65) {
|
||||||
// This is the NALU code for I-frame data
|
// This is the NALU code for I-frame data
|
||||||
@ -245,14 +245,14 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check if this is padding after a full AVC frame
|
// Check if this is padding after a full video frame
|
||||||
if (isDecodingH264 && NAL.isPadding(cachedSpecialDesc)) {
|
if (isDecodingVideoData && NAL.isPadding(cachedSpecialDesc)) {
|
||||||
// The decode unit is complete
|
// The decode unit is complete
|
||||||
reassembleAvcFrame(packet.getFrameIndex());
|
reassembleFrame(packet.getFrameIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not decoding AVC
|
// Not decoding video
|
||||||
isDecodingH264 = false;
|
isDecodingVideoData = false;
|
||||||
|
|
||||||
// Just skip this byte
|
// Just skip this byte
|
||||||
location.length--;
|
location.length--;
|
||||||
@ -271,7 +271,7 @@ public class VideoDepacketizer {
|
|||||||
{
|
{
|
||||||
// Only stop if we're decoding something or this
|
// Only stop if we're decoding something or this
|
||||||
// isn't padding
|
// isn't padding
|
||||||
if (isDecodingH264 || !NAL.isPadding(cachedSpecialDesc))
|
if (isDecodingVideoData || !NAL.isPadding(cachedSpecialDesc))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -283,7 +283,7 @@ public class VideoDepacketizer {
|
|||||||
location.length--;
|
location.length--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDecodingH264 && decodingFrame)
|
if (isDecodingVideoData && decodingFrame)
|
||||||
{
|
{
|
||||||
// The slow path may result in multiple decode units per packet.
|
// The slow path may result in multiple decode units per packet.
|
||||||
// The VideoPacket objects only support being in 1 DU list, so we'll
|
// The VideoPacket objects only support being in 1 DU list, so we'll
|
||||||
@ -364,7 +364,7 @@ public class VideoDepacketizer {
|
|||||||
waitingForNextSuccessfulFrame = true;
|
waitingForNextSuccessfulFrame = true;
|
||||||
|
|
||||||
// Clear the old state and wait for an IDR
|
// Clear the old state and wait for an IDR
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
}
|
}
|
||||||
// Look for a non-frame start before a frame start
|
// Look for a non-frame start before a frame start
|
||||||
else if (!firstPacket && !decodingFrame) {
|
else if (!firstPacket && !decodingFrame) {
|
||||||
@ -378,7 +378,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
waitingForNextSuccessfulFrame = true;
|
waitingForNextSuccessfulFrame = true;
|
||||||
|
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
decodingFrame = false;
|
decodingFrame = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -397,7 +397,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
// Wait until an IDR frame comes
|
// Wait until an IDR frame comes
|
||||||
waitingForNextSuccessfulFrame = true;
|
waitingForNextSuccessfulFrame = true;
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
}
|
}
|
||||||
else if (nextFrameNumber != frameIndex) {
|
else if (nextFrameNumber != frameIndex) {
|
||||||
// Duplicate packet or FEC dup
|
// Duplicate packet or FEC dup
|
||||||
@ -419,7 +419,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
waitingForNextSuccessfulFrame = true;
|
waitingForNextSuccessfulFrame = true;
|
||||||
|
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
decodingFrame = false;
|
decodingFrame = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -435,7 +435,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
if (firstPacket
|
if (firstPacket
|
||||||
&& NAL.getSpecialSequenceDescriptor(cachedReassemblyDesc, cachedSpecialDesc)
|
&& NAL.getSpecialSequenceDescriptor(cachedReassemblyDesc, cachedSpecialDesc)
|
||||||
&& NAL.isAvcFrameStart(cachedSpecialDesc)
|
&& NAL.isAnnexBFrameStart(cachedSpecialDesc)
|
||||||
&& cachedSpecialDesc.data[cachedSpecialDesc.offset+cachedSpecialDesc.length] == 0x67)
|
&& 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
|
||||||
@ -467,11 +467,11 @@ public class VideoDepacketizer {
|
|||||||
if (waitingForIdrFrame) {
|
if (waitingForIdrFrame) {
|
||||||
LimeLog.warning("Waiting for IDR frame");
|
LimeLog.warning("Waiting for IDR frame");
|
||||||
|
|
||||||
dropAvcFrameState();
|
dropFrameState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reassembleAvcFrame(frameIndex);
|
reassembleFrame(frameIndex);
|
||||||
|
|
||||||
startFrameNumber = nextFrameNumber;
|
startFrameNumber = nextFrameNumber;
|
||||||
}
|
}
|
||||||
@ -496,14 +496,14 @@ public class VideoDepacketizer {
|
|||||||
class NAL {
|
class NAL {
|
||||||
|
|
||||||
// This assumes that the buffer passed in is already a special sequence
|
// This assumes that the buffer passed in is already a special sequence
|
||||||
public static boolean isAvcStartSequence(ByteBufferDescriptor specialSeq)
|
public static boolean isAnnexBStartSequence(ByteBufferDescriptor specialSeq)
|
||||||
{
|
{
|
||||||
// The start sequence is 00 00 01 or 00 00 00 01
|
// The start sequence is 00 00 01 or 00 00 00 01
|
||||||
return (specialSeq.data[specialSeq.offset+specialSeq.length-1] == 0x01);
|
return (specialSeq.data[specialSeq.offset+specialSeq.length-1] == 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This assumes that the buffer passed in is already a special sequence
|
// This assumes that the buffer passed in is already a special sequence
|
||||||
public static boolean isAvcFrameStart(ByteBufferDescriptor specialSeq)
|
public static boolean isAnnexBFrameStart(ByteBufferDescriptor specialSeq)
|
||||||
{
|
{
|
||||||
if (specialSeq.length != 4)
|
if (specialSeq.length != 4)
|
||||||
return false;
|
return false;
|
||||||
@ -537,7 +537,7 @@ class NAL {
|
|||||||
if (buffer.length >= 4 &&
|
if (buffer.length >= 4 &&
|
||||||
buffer.data[buffer.offset+3] == 0x01)
|
buffer.data[buffer.offset+3] == 0x01)
|
||||||
{
|
{
|
||||||
// It's the AVC start sequence 00 00 00 01
|
// It's the Annex B start sequence 00 00 00 01
|
||||||
outputDesc.reinitialize(buffer.data, buffer.offset, 4);
|
outputDesc.reinitialize(buffer.data, buffer.offset, 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user