mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 03:23:07 +00:00
Reuse a single AvByteBufferDescriptor when depacketizing H264 instead of allocating many of them per packet
This commit is contained in:
parent
fb8b6fd7f5
commit
7d39ac2a45
@ -19,6 +19,13 @@ public class AvByteBufferDescriptor {
|
|||||||
this.length = desc.length;
|
this.length = desc.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reinitialize(byte[] data, int offset, int length)
|
||||||
|
{
|
||||||
|
this.data = data;
|
||||||
|
this.offset = offset;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
public void print()
|
public void print()
|
||||||
{
|
{
|
||||||
print(offset, length);
|
print(offset, length);
|
||||||
|
@ -18,4 +18,11 @@ public class AvShortBufferDescriptor {
|
|||||||
this.offset = desc.offset;
|
this.offset = desc.offset;
|
||||||
this.length = desc.length;
|
this.length = desc.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reinitialize(short[] data, int offset, int length)
|
||||||
|
{
|
||||||
|
this.data = data;
|
||||||
|
this.offset = offset;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,10 @@ public class AvVideoDepacketizer {
|
|||||||
private int avcNalDataLength = 0;
|
private int avcNalDataLength = 0;
|
||||||
private int currentlyDecoding;
|
private int currentlyDecoding;
|
||||||
|
|
||||||
|
// Cached buffer descriptor to save on allocations
|
||||||
|
// Only safe to use in decode thread!!!!
|
||||||
|
private AvByteBufferDescriptor cachedDesc;
|
||||||
|
|
||||||
// Sequencing state
|
// Sequencing state
|
||||||
private short lastSequenceNumber;
|
private short lastSequenceNumber;
|
||||||
|
|
||||||
@ -28,6 +32,7 @@ public class AvVideoDepacketizer {
|
|||||||
public AvVideoDepacketizer(ConnectionStatusListener controlListener)
|
public AvVideoDepacketizer(ConnectionStatusListener controlListener)
|
||||||
{
|
{
|
||||||
this.controlListener = controlListener;
|
this.controlListener = controlListener;
|
||||||
|
this.cachedDesc = new AvByteBufferDescriptor(null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearAvcNalState()
|
private void clearAvcNalState()
|
||||||
@ -45,12 +50,11 @@ public class AvVideoDepacketizer {
|
|||||||
|
|
||||||
// Check if this is a special NAL unit
|
// Check if this is a special NAL unit
|
||||||
AvByteBufferDescriptor header = avcNalDataChain.getFirst();
|
AvByteBufferDescriptor header = avcNalDataChain.getFirst();
|
||||||
AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(header);
|
|
||||||
|
|
||||||
if (specialSeq != null)
|
if (NAL.getSpecialSequenceDescriptor(header, cachedDesc))
|
||||||
{
|
{
|
||||||
// The next byte after the special sequence is the NAL header
|
// The next byte after the special sequence is the NAL header
|
||||||
byte nalHeader = specialSeq.data[specialSeq.offset+specialSeq.length];
|
byte nalHeader = cachedDesc.data[cachedDesc.offset+cachedDesc.length];
|
||||||
|
|
||||||
switch (nalHeader)
|
switch (nalHeader)
|
||||||
{
|
{
|
||||||
@ -112,16 +116,15 @@ public class AvVideoDepacketizer {
|
|||||||
int start = location.offset;
|
int start = location.offset;
|
||||||
|
|
||||||
// Check for a special sequence
|
// Check for a special sequence
|
||||||
AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location);
|
if (NAL.getSpecialSequenceDescriptor(location, cachedDesc))
|
||||||
if (specialSeq != null)
|
|
||||||
{
|
{
|
||||||
if (NAL.isAvcStartSequence(specialSeq))
|
if (NAL.isAvcStartSequence(cachedDesc))
|
||||||
{
|
{
|
||||||
// We're decoding H264 now
|
// We're decoding H264 now
|
||||||
currentlyDecoding = AvDecodeUnit.TYPE_H264;
|
currentlyDecoding = AvDecodeUnit.TYPE_H264;
|
||||||
|
|
||||||
// Check if it's the end of the last frame
|
// Check if it's the end of the last frame
|
||||||
if (NAL.isAvcFrameStart(specialSeq))
|
if (NAL.isAvcFrameStart(cachedDesc))
|
||||||
{
|
{
|
||||||
// Reassemble any pending AVC NAL
|
// Reassemble any pending AVC NAL
|
||||||
reassembleAvcNal();
|
reassembleAvcNal();
|
||||||
@ -132,14 +135,14 @@ public class AvVideoDepacketizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip the start sequence
|
// Skip the start sequence
|
||||||
location.length -= specialSeq.length;
|
location.length -= cachedDesc.length;
|
||||||
location.offset += specialSeq.length;
|
location.offset += cachedDesc.length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check if this is padding after a full AVC frame
|
// Check if this is padding after a full AVC frame
|
||||||
if (currentlyDecoding == AvDecodeUnit.TYPE_H264 &&
|
if (currentlyDecoding == AvDecodeUnit.TYPE_H264 &&
|
||||||
NAL.isPadding(specialSeq)) {
|
NAL.isPadding(cachedDesc)) {
|
||||||
// The decode unit is complete
|
// The decode unit is complete
|
||||||
reassembleAvcNal();
|
reassembleAvcNal();
|
||||||
}
|
}
|
||||||
@ -159,15 +162,13 @@ public class AvVideoDepacketizer {
|
|||||||
// Catch the easy case first where byte 0 != 0x00
|
// Catch the easy case first where byte 0 != 0x00
|
||||||
if (location.data[location.offset] == 0x00)
|
if (location.data[location.offset] == 0x00)
|
||||||
{
|
{
|
||||||
specialSeq = NAL.getSpecialSequenceDescriptor(location);
|
|
||||||
|
|
||||||
// Check if this should end the current NAL
|
// Check if this should end the current NAL
|
||||||
if (specialSeq != null)
|
if (NAL.getSpecialSequenceDescriptor(location, cachedDesc))
|
||||||
{
|
{
|
||||||
// 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 (currentlyDecoding != AvDecodeUnit.TYPE_UNKNOWN ||
|
if (currentlyDecoding != AvDecodeUnit.TYPE_UNKNOWN ||
|
||||||
!NAL.isPadding(specialSeq))
|
!NAL.isPadding(cachedDesc))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -249,11 +250,11 @@ class NAL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a buffer descriptor describing the start sequence
|
// Returns a buffer descriptor describing the start sequence
|
||||||
public static AvByteBufferDescriptor getSpecialSequenceDescriptor(AvByteBufferDescriptor buffer)
|
public static boolean getSpecialSequenceDescriptor(AvByteBufferDescriptor buffer, AvByteBufferDescriptor outputDesc)
|
||||||
{
|
{
|
||||||
// NAL start sequence is 00 00 00 01 or 00 00 01
|
// NAL start sequence is 00 00 00 01 or 00 00 01
|
||||||
if (buffer.length < 3)
|
if (buffer.length < 3)
|
||||||
return null;
|
return false;
|
||||||
|
|
||||||
// 00 00 is magic
|
// 00 00 is magic
|
||||||
if (buffer.data[buffer.offset] == 0x00 &&
|
if (buffer.data[buffer.offset] == 0x00 &&
|
||||||
@ -267,19 +268,21 @@ class NAL {
|
|||||||
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 AVC start sequence 00 00 00 01
|
||||||
return new AvByteBufferDescriptor(buffer.data, buffer.offset, 4);
|
outputDesc.reinitialize(buffer.data, buffer.offset, 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// It's 00 00 00
|
// It's 00 00 00
|
||||||
return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
|
outputDesc.reinitialize(buffer.data, buffer.offset, 3);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (buffer.data[buffer.offset+2] == 0x01 ||
|
else if (buffer.data[buffer.offset+2] == 0x01 ||
|
||||||
buffer.data[buffer.offset+2] == 0x02)
|
buffer.data[buffer.offset+2] == 0x02)
|
||||||
{
|
{
|
||||||
// These are easy: 00 00 01 or 00 00 02
|
// These are easy: 00 00 01 or 00 00 02
|
||||||
return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
|
outputDesc.reinitialize(buffer.data, buffer.offset, 3);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (buffer.data[buffer.offset+2] == 0x03)
|
else if (buffer.data[buffer.offset+2] == 0x03)
|
||||||
{
|
{
|
||||||
@ -290,22 +293,23 @@ class NAL {
|
|||||||
// or whether it's something else
|
// or whether it's something else
|
||||||
|
|
||||||
if (buffer.length < 4)
|
if (buffer.length < 4)
|
||||||
return null;
|
return false;
|
||||||
|
|
||||||
if (buffer.data[buffer.offset+3] >= 0x00 &&
|
if (buffer.data[buffer.offset+3] >= 0x00 &&
|
||||||
buffer.data[buffer.offset+3] <= 0x03)
|
buffer.data[buffer.offset+3] <= 0x03)
|
||||||
{
|
{
|
||||||
// It's not really a special sequence after all
|
// It's not really a special sequence after all
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// It's not a standard replacement so it's a special sequence
|
// It's not a standard replacement so it's a special sequence
|
||||||
return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
|
outputDesc.reinitialize(buffer.data, buffer.offset, 3);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user