Rename AvBufferX -> AvByteBufferX and create AvShortBufferX

This commit is contained in:
Cameron Gutman 2013-11-10 03:42:29 -05:00
parent 62a9040cb8
commit 34e87ca899
11 changed files with 115 additions and 68 deletions

View File

@ -3,29 +3,22 @@ package com.limelight.nvstream;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException; import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import jlibrtp.Participant; import jlibrtp.Participant;
import jlibrtp.RTPSession; import jlibrtp.RTPSession;
import com.limelight.nvstream.av.AvBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvBufferPool; import com.limelight.nvstream.av.AvByteBufferPool;
import com.limelight.nvstream.av.AvDecodeUnit;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
import com.limelight.nvstream.av.AvShortBufferDescriptor;
import com.limelight.nvstream.av.audio.AvAudioDepacketizer; import com.limelight.nvstream.av.audio.AvAudioDepacketizer;
import com.limelight.nvstream.av.audio.OpusDecoder; import com.limelight.nvstream.av.audio.OpusDecoder;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.net.rtp.AudioGroup;
import android.net.rtp.AudioStream;
import android.view.Surface;
public class NvAudioStream { public class NvAudioStream {
public static final int RTP_PORT = 48000; public static final int RTP_PORT = 48000;
@ -40,7 +33,7 @@ public class NvAudioStream {
private AvAudioDepacketizer depacketizer = new AvAudioDepacketizer(); private AvAudioDepacketizer depacketizer = new AvAudioDepacketizer();
private AvBufferPool pool = new AvBufferPool(1500); private AvByteBufferPool pool = new AvByteBufferPool(1500);
public void startAudioStream(final String host) public void startAudioStream(final String host)
{ {
@ -147,7 +140,8 @@ public class NvAudioStream {
public void run() { public void run() {
for (;;) for (;;)
{ {
short[] samples; AvShortBufferDescriptor samples;
try { try {
samples = depacketizer.getNextDecodedData(); samples = depacketizer.getNextDecodedData();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -155,7 +149,7 @@ public class NvAudioStream {
return; return;
} }
track.write(samples, 0, samples.length); track.write(samples.data, samples.offset, samples.length);
} }
} }
}).start(); }).start();
@ -168,7 +162,7 @@ public class NvAudioStream {
@Override @Override
public void run() { public void run() {
DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500);
AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0); AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0);
for (;;) for (;;)
{ {

View File

@ -10,8 +10,8 @@ import java.net.UnknownHostException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvBufferPool; import com.limelight.nvstream.av.AvByteBufferPool;
import com.limelight.nvstream.av.AvDecodeUnit; import com.limelight.nvstream.av.AvDecodeUnit;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
import com.limelight.nvstream.av.video.AvVideoDepacketizer; import com.limelight.nvstream.av.video.AvVideoDepacketizer;
@ -37,7 +37,7 @@ public class NvVideoStream {
private RTPSession session; private RTPSession session;
private DatagramSocket rtp; private DatagramSocket rtp;
private AvBufferPool pool = new AvBufferPool(1500); private AvByteBufferPool pool = new AvByteBufferPool(1500);
private AvVideoDepacketizer depacketizer = new AvVideoDepacketizer(); private AvVideoDepacketizer depacketizer = new AvVideoDepacketizer();
@ -176,7 +176,7 @@ public class NvVideoStream {
buf.clear(); buf.clear();
// Copy data from our buffer list into the input buffer // Copy data from our buffer list into the input buffer
for (AvBufferDescriptor desc : du.getBufferList()) for (AvByteBufferDescriptor desc : du.getBufferList())
{ {
buf.put(desc.data, desc.offset, desc.length); buf.put(desc.data, desc.offset, desc.length);
@ -234,7 +234,7 @@ public class NvVideoStream {
@Override @Override
public void run() { public void run() {
DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500);
AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0); AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0);
for (;;) for (;;)
{ {

View File

@ -1,18 +1,18 @@
package com.limelight.nvstream.av; package com.limelight.nvstream.av;
public class AvBufferDescriptor { public class AvByteBufferDescriptor {
public byte[] data; public byte[] data;
public int offset; public int offset;
public int length; public int length;
public AvBufferDescriptor(byte[] data, int offset, int length) public AvByteBufferDescriptor(byte[] data, int offset, int length)
{ {
this.data = data; this.data = data;
this.offset = offset; this.offset = offset;
this.length = length; this.length = length;
} }
public AvBufferDescriptor(AvBufferDescriptor desc) public AvByteBufferDescriptor(AvByteBufferDescriptor desc)
{ {
this.data = desc.data; this.data = desc.data;
this.offset = desc.offset; this.offset = desc.offset;

View File

@ -2,11 +2,11 @@ package com.limelight.nvstream.av;
import java.util.LinkedList; import java.util.LinkedList;
public class AvBufferPool { public class AvByteBufferPool {
private LinkedList<byte[]> bufferList = new LinkedList<byte[]>(); private LinkedList<byte[]> bufferList = new LinkedList<byte[]>();
private int bufferSize; private int bufferSize;
public AvBufferPool(int size) public AvByteBufferPool(int size)
{ {
this.bufferSize = size; this.bufferSize = size;
} }

View File

@ -8,11 +8,11 @@ public class AvDecodeUnit {
public static final int TYPE_OPUS = 2; public static final int TYPE_OPUS = 2;
private int type; private int type;
private List<AvBufferDescriptor> bufferList; private List<AvByteBufferDescriptor> bufferList;
private int dataLength; private int dataLength;
private int flags; private int flags;
public AvDecodeUnit(int type, List<AvBufferDescriptor> bufferList, int dataLength, int flags) public AvDecodeUnit(int type, List<AvByteBufferDescriptor> bufferList, int dataLength, int flags)
{ {
this.type = type; this.type = type;
this.bufferList = bufferList; this.bufferList = bufferList;
@ -30,7 +30,7 @@ public class AvDecodeUnit {
return flags; return flags;
} }
public List<AvBufferDescriptor> getBufferList() public List<AvByteBufferDescriptor> getBufferList()
{ {
return bufferList; return bufferList;
} }

View File

@ -6,11 +6,11 @@ public class AvRtpPacket {
private byte packetType; private byte packetType;
private short seqNum; private short seqNum;
private AvBufferDescriptor buffer; private AvByteBufferDescriptor buffer;
public AvRtpPacket(AvBufferDescriptor buffer) public AvRtpPacket(AvByteBufferDescriptor buffer)
{ {
this.buffer = new AvBufferDescriptor(buffer); this.buffer = new AvByteBufferDescriptor(buffer);
ByteBuffer bb = ByteBuffer.wrap(buffer.data, buffer.offset, buffer.length); ByteBuffer bb = ByteBuffer.wrap(buffer.data, buffer.offset, buffer.length);
@ -34,8 +34,8 @@ public class AvRtpPacket {
return seqNum; return seqNum;
} }
public AvBufferDescriptor getNewPayloadDescriptor() public AvByteBufferDescriptor getNewPayloadDescriptor()
{ {
return new AvBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12); return new AvByteBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12);
} }
} }

View File

@ -0,0 +1,21 @@
package com.limelight.nvstream.av;
public class AvShortBufferDescriptor {
public short[] data;
public int offset;
public int length;
public AvShortBufferDescriptor(short[] data, int offset, int length)
{
this.data = data;
this.offset = offset;
this.length = length;
}
public AvShortBufferDescriptor(AvShortBufferDescriptor desc)
{
this.data = desc.data;
this.offset = desc.offset;
this.length = desc.length;
}
}

View File

@ -0,0 +1,30 @@
package com.limelight.nvstream.av;
import java.util.LinkedList;
public class AvShortBufferPool {
private LinkedList<short[]> bufferList = new LinkedList<short[]>();
private int bufferSize;
public AvShortBufferPool(int size)
{
this.bufferSize = size;
}
public synchronized short[] allocate()
{
if (bufferList.isEmpty())
{
return new short[bufferSize];
}
else
{
return bufferList.removeFirst();
}
}
public synchronized void free(short[] buffer)
{
bufferList.addFirst(buffer);
}
}

View File

@ -2,11 +2,16 @@ package com.limelight.nvstream.av.audio;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
import com.limelight.nvstream.av.AvShortBufferDescriptor;
import com.limelight.nvstream.av.AvShortBufferPool;
public class AvAudioDepacketizer { public class AvAudioDepacketizer {
private LinkedBlockingQueue<short[]> decodedUnits = new LinkedBlockingQueue<short[]>(); private LinkedBlockingQueue<AvShortBufferDescriptor> decodedUnits =
new LinkedBlockingQueue<AvShortBufferDescriptor>();
private AvShortBufferPool pool = new AvShortBufferPool(OpusDecoder.getMaxOutputShorts());
// Sequencing state // Sequencing state
private short lastSequenceNumber; private short lastSequenceNumber;
@ -34,25 +39,22 @@ public class AvAudioDepacketizer {
lastSequenceNumber = seq; lastSequenceNumber = seq;
// This is all the depacketizing we need to do // This is all the depacketizing we need to do
AvBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor();
// Submit this data to the decoder // Submit this data to the decoder
short[] pcmData = new short[OpusDecoder.getMaxOutputShorts()]; short[] pcmData = pool.allocate();
int decodeLen = OpusDecoder.decode(rtpPayload.data, rtpPayload.offset, rtpPayload.length, pcmData); int decodeLen = OpusDecoder.decode(rtpPayload.data, rtpPayload.offset, rtpPayload.length, pcmData);
if (decodeLen > 0) {
// Return value of decode is frames decoded per channel // Return value of decode is frames decoded per channel
decodeLen *= OpusDecoder.getChannelCount(); decodeLen *= OpusDecoder.getChannelCount();
if (decodeLen > 0) { // Put it on the decoded queue
// Jank! decodedUnits.add(new AvShortBufferDescriptor(pcmData, 0, decodeLen));
short[] trimmedPcmData = new short[decodeLen];
System.arraycopy(pcmData, 0, trimmedPcmData, 0, decodeLen);
decodedUnits.add(trimmedPcmData);
} }
} }
public short[] getNextDecodedData() throws InterruptedException public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException
{ {
return decodedUnits.take(); return decodedUnits.take();
} }

View File

@ -3,7 +3,7 @@ package com.limelight.nvstream.av.video;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvDecodeUnit; import com.limelight.nvstream.av.AvDecodeUnit;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
@ -12,7 +12,7 @@ import android.media.MediaCodec;
public class AvVideoDepacketizer { public class AvVideoDepacketizer {
// Current NAL state // Current NAL state
private LinkedList<AvBufferDescriptor> avcNalDataChain = null; private LinkedList<AvByteBufferDescriptor> avcNalDataChain = null;
private int avcNalDataLength = 0; private int avcNalDataLength = 0;
private int currentlyDecoding; private int currentlyDecoding;
@ -29,8 +29,8 @@ public class AvVideoDepacketizer {
int flags = 0; int flags = 0;
// Check if this is a special NAL unit // Check if this is a special NAL unit
AvBufferDescriptor header = avcNalDataChain.getFirst(); AvByteBufferDescriptor header = avcNalDataChain.getFirst();
AvBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(header); AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(header);
if (specialSeq != null) if (specialSeq != null)
{ {
@ -85,7 +85,7 @@ public class AvVideoDepacketizer {
public void addInputData(AvVideoPacket packet) public void addInputData(AvVideoPacket packet)
{ {
AvBufferDescriptor location = packet.getNewPayloadDescriptor(); AvByteBufferDescriptor location = packet.getNewPayloadDescriptor();
while (location.length != 0) while (location.length != 0)
{ {
@ -93,7 +93,7 @@ public class AvVideoDepacketizer {
int start = location.offset; int start = location.offset;
// Check for a special sequence // Check for a special sequence
AvBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location); AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location);
if (specialSeq != null) if (specialSeq != null)
{ {
if (NAL.isAvcStartSequence(specialSeq)) if (NAL.isAvcStartSequence(specialSeq))
@ -108,7 +108,7 @@ public class AvVideoDepacketizer {
reassembleAvcNal(); reassembleAvcNal();
// Setup state for the new NAL // Setup state for the new NAL
avcNalDataChain = new LinkedList<AvBufferDescriptor>(); avcNalDataChain = new LinkedList<AvByteBufferDescriptor>();
avcNalDataLength = 0; avcNalDataLength = 0;
} }
} }
@ -141,7 +141,7 @@ public class AvVideoDepacketizer {
} }
} }
AvBufferDescriptor data = new AvBufferDescriptor(location.data, start, location.offset-start); AvByteBufferDescriptor data = new AvByteBufferDescriptor(location.data, start, location.offset-start);
if (currentlyDecoding == AvDecodeUnit.TYPE_H264 && avcNalDataChain != null) if (currentlyDecoding == AvDecodeUnit.TYPE_H264 && avcNalDataChain != null)
{ {
@ -172,7 +172,7 @@ public class AvVideoDepacketizer {
lastSequenceNumber = seq; lastSequenceNumber = seq;
// Pass the payload to the non-sequencing parser // Pass the payload to the non-sequencing parser
AvBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor();
addInputData(new AvVideoPacket(rtpPayload)); addInputData(new AvVideoPacket(rtpPayload));
} }
@ -185,7 +185,7 @@ public class AvVideoDepacketizer {
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(AvBufferDescriptor specialSeq) public static boolean isAvcStartSequence(AvByteBufferDescriptor specialSeq)
{ {
if (specialSeq.length != 3 && specialSeq.length != 4) if (specialSeq.length != 3 && specialSeq.length != 4)
return false; return false;
@ -195,7 +195,7 @@ 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 isUnknownStartSequence(AvBufferDescriptor specialSeq) public static boolean isUnknownStartSequence(AvByteBufferDescriptor specialSeq)
{ {
if (specialSeq.length != 3) if (specialSeq.length != 3)
return false; return false;
@ -205,7 +205,7 @@ 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 isAvcFrameStart(AvBufferDescriptor specialSeq) public static boolean isAvcFrameStart(AvByteBufferDescriptor specialSeq)
{ {
if (specialSeq.length != 4) if (specialSeq.length != 4)
return false; return false;
@ -215,7 +215,7 @@ class NAL {
} }
// Returns a buffer descriptor describing the start sequence // Returns a buffer descriptor describing the start sequence
public static AvBufferDescriptor getSpecialSequenceDescriptor(AvBufferDescriptor buffer) public static AvByteBufferDescriptor getSpecialSequenceDescriptor(AvByteBufferDescriptor buffer)
{ {
// 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)
@ -233,19 +233,19 @@ 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 AvBufferDescriptor(buffer.data, buffer.offset, 4); return new AvByteBufferDescriptor(buffer.data, buffer.offset, 4);
} }
else else
{ {
// It's 00 00 00 // It's 00 00 00
return new AvBufferDescriptor(buffer.data, buffer.offset, 3); return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
} }
} }
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 AvBufferDescriptor(buffer.data, buffer.offset, 3); return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
} }
else if (buffer.data[buffer.offset+2] == 0x03) else if (buffer.data[buffer.offset+2] == 0x03)
{ {
@ -267,7 +267,7 @@ class NAL {
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 AvBufferDescriptor(buffer.data, buffer.offset, 3); return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3);
} }
} }
} }

View File

@ -1,17 +1,17 @@
package com.limelight.nvstream.av.video; package com.limelight.nvstream.av.video;
import com.limelight.nvstream.av.AvBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
public class AvVideoPacket { public class AvVideoPacket {
private AvBufferDescriptor buffer; private AvByteBufferDescriptor buffer;
public AvVideoPacket(AvBufferDescriptor rtpPayload) public AvVideoPacket(AvByteBufferDescriptor rtpPayload)
{ {
buffer = new AvBufferDescriptor(rtpPayload); buffer = new AvByteBufferDescriptor(rtpPayload);
} }
public AvBufferDescriptor getNewPayloadDescriptor() public AvByteBufferDescriptor getNewPayloadDescriptor()
{ {
return new AvBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56);
} }
} }