Reuse a single AvByteBufferDescriptor when depacketizing H264 instead of allocating many of them per packet

This commit is contained in:
Cameron Gutman 2013-11-24 21:51:09 -05:00
parent fb8b6fd7f5
commit 7d39ac2a45
3 changed files with 41 additions and 23 deletions

View File

@ -19,6 +19,13 @@ public class AvByteBufferDescriptor {
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()
{
print(offset, length);

View File

@ -18,4 +18,11 @@ public class AvShortBufferDescriptor {
this.offset = desc.offset;
this.length = desc.length;
}
public void reinitialize(short[] data, int offset, int length)
{
this.data = data;
this.offset = offset;
this.length = length;
}
}

View File

@ -17,6 +17,10 @@ public class AvVideoDepacketizer {
private int avcNalDataLength = 0;
private int currentlyDecoding;
// Cached buffer descriptor to save on allocations
// Only safe to use in decode thread!!!!
private AvByteBufferDescriptor cachedDesc;
// Sequencing state
private short lastSequenceNumber;
@ -28,6 +32,7 @@ public class AvVideoDepacketizer {
public AvVideoDepacketizer(ConnectionStatusListener controlListener)
{
this.controlListener = controlListener;
this.cachedDesc = new AvByteBufferDescriptor(null, 0, 0);
}
private void clearAvcNalState()
@ -45,12 +50,11 @@ public class AvVideoDepacketizer {
// Check if this is a special NAL unit
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
byte nalHeader = specialSeq.data[specialSeq.offset+specialSeq.length];
byte nalHeader = cachedDesc.data[cachedDesc.offset+cachedDesc.length];
switch (nalHeader)
{
@ -112,16 +116,15 @@ public class AvVideoDepacketizer {
int start = location.offset;
// Check for a special sequence
AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location);
if (specialSeq != null)
if (NAL.getSpecialSequenceDescriptor(location, cachedDesc))
{
if (NAL.isAvcStartSequence(specialSeq))
if (NAL.isAvcStartSequence(cachedDesc))
{
// We're decoding H264 now
currentlyDecoding = AvDecodeUnit.TYPE_H264;
// Check if it's the end of the last frame
if (NAL.isAvcFrameStart(specialSeq))
if (NAL.isAvcFrameStart(cachedDesc))
{
// Reassemble any pending AVC NAL
reassembleAvcNal();
@ -132,14 +135,14 @@ public class AvVideoDepacketizer {
}
// Skip the start sequence
location.length -= specialSeq.length;
location.offset += specialSeq.length;
location.length -= cachedDesc.length;
location.offset += cachedDesc.length;
}
else
{
// Check if this is padding after a full AVC frame
if (currentlyDecoding == AvDecodeUnit.TYPE_H264 &&
NAL.isPadding(specialSeq)) {
NAL.isPadding(cachedDesc)) {
// The decode unit is complete
reassembleAvcNal();
}
@ -159,15 +162,13 @@ public class AvVideoDepacketizer {
// Catch the easy case first where byte 0 != 0x00
if (location.data[location.offset] == 0x00)
{
specialSeq = NAL.getSpecialSequenceDescriptor(location);
// 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
// isn't padding
if (currentlyDecoding != AvDecodeUnit.TYPE_UNKNOWN ||
!NAL.isPadding(specialSeq))
!NAL.isPadding(cachedDesc))
{
break;
}
@ -249,11 +250,11 @@ class NAL {
}
// 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
if (buffer.length < 3)
return null;
return false;
// 00 00 is magic
if (buffer.data[buffer.offset] == 0x00 &&
@ -267,19 +268,21 @@ class NAL {
buffer.data[buffer.offset+3] == 0x01)
{
// 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
{
// 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 ||
buffer.data[buffer.offset+2] == 0x02)
{
// 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)
{
@ -290,22 +293,23 @@ class NAL {
// or whether it's something else
if (buffer.length < 4)
return null;
return false;
if (buffer.data[buffer.offset+3] >= 0x00 &&
buffer.data[buffer.offset+3] <= 0x03)
{
// It's not really a special sequence after all
return null;
return false;
}
else
{
// 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;
}
}