Remove jlibrtp (finally). CPU decoding support (works great on Tegra 4, not so well on Tegra 3)

This commit is contained in:
Cameron Gutman
2013-11-20 00:00:00 -05:00
parent 0504bed5e9
commit 16d629f5cf
333 changed files with 398 additions and 29536 deletions

View File

@@ -54,6 +54,7 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView);
sv.setOnGenericMotionListener(this);
sv.setOnTouchListener(this);
sv.getHolder().setFixedSize(1280, 720);
// Start the connection
conn = new NvConnection(Game.this.getIntent().getStringExtra("host"), Game.this, sv.getHolder().getSurface());

View File

@@ -3,13 +3,12 @@ package com.limelight.nvstream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import jlibrtp.Participant;
import jlibrtp.RTPSession;
import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvByteBufferPool;
import com.limelight.nvstream.av.AvRtpPacket;
@@ -29,7 +28,6 @@ public class NvAudioStream {
private AudioTrack track;
private RTPSession session;
private DatagramSocket rtp;
private AvAudioDepacketizer depacketizer = new AvAudioDepacketizer();
@@ -63,11 +61,7 @@ public class NvAudioStream {
t.join();
} catch (InterruptedException e) { }
}
if (session != null) {
//session.endSession();
}
if (track != null) {
track.release();
}
@@ -86,6 +80,9 @@ public class NvAudioStream {
} catch (SocketException e) {
e.printStackTrace();
return;
} catch (UnknownHostException e) {
e.printStackTrace();
return;
}
setupAudio();
@@ -102,12 +99,10 @@ public class NvAudioStream {
}).start();
}
private void setupRtpSession(String host) throws SocketException
private void setupRtpSession(String host) throws SocketException, UnknownHostException
{
rtp = new DatagramSocket(RTP_PORT);
session = new RTPSession(rtp, null);
session.addParticipant(new Participant(host, RTP_PORT, 0));
rtp.connect(InetAddress.getByName(host), RTP_PORT);
}
public void trim()
@@ -248,15 +243,18 @@ public class NvAudioStream {
@Override
public void run() {
// PING in ASCII
final byte[] pingPacket = new byte[] {0x50, 0x49, 0x4E, 0x47};
// RTP payload type is 127 (dynamic)
session.payloadType(127);
final byte[] pingPacketData = new byte[] {0x50, 0x49, 0x4E, 0x47};
DatagramPacket pingPacket = new DatagramPacket(pingPacketData, pingPacketData.length);
// Send PING every 100 ms
while (!isInterrupted())
{
session.sendData(pingPacket);
try {
rtp.send(pingPacket);
} catch (IOException e) {
abort();
return;
}
try {
Thread.sleep(100);

View File

@@ -137,12 +137,13 @@ public class NvConnection {
try {
startSteamBigPicture();
performHandshake();
videoStream.startVideoStream(host, video);
videoStream.setupVideoStream(host, video);
audioStream.startAudioStream(host);
beginControlStream();
controlStream.startJitterPackets();
startController();
activity.hideSystemUi();
videoStream.startVideoStream(host);
} catch (XmlPullParserException e) {
e.printStackTrace();
displayToast(e.getMessage());

View File

@@ -4,8 +4,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
@@ -18,9 +20,6 @@ import com.limelight.nvstream.av.video.CpuDecoderRenderer;
import com.limelight.nvstream.av.video.DecoderRenderer;
import com.limelight.nvstream.av.video.MediaCodecDecoderRenderer;
import jlibrtp.Participant;
import jlibrtp.RTPSession;
import android.view.Surface;
public class NvVideoStream {
@@ -30,8 +29,7 @@ public class NvVideoStream {
private LinkedBlockingQueue<AvRtpPacket> packets = new LinkedBlockingQueue<AvRtpPacket>();
private RTPSession session;
private DatagramSocket rtp, rtcp;
private DatagramSocket rtp;
private Socket firstFrameSocket;
private LinkedList<Thread> threads = new LinkedList<Thread>();
@@ -59,9 +57,6 @@ public class NvVideoStream {
if (rtp != null) {
rtp.close();
}
if (rtcp != null) {
rtcp.close();
}
if (firstFrameSocket != null) {
try {
firstFrameSocket.close();
@@ -75,9 +70,6 @@ public class NvVideoStream {
} catch (InterruptedException e) { }
}
if (session != null) {
//session.endSession();
}
if (decrend != null) {
decrend.release();
}
@@ -119,17 +111,13 @@ public class NvVideoStream {
}
}
public void setupRtpSession(String host) throws SocketException
public void setupRtpSession(String host) throws SocketException, UnknownHostException
{
rtp = new DatagramSocket(RTP_PORT);
rtcp = new DatagramSocket(RTCP_PORT);
rtp.connect(InetAddress.getByName(host), RTP_PORT);
rtp.setReceiveBufferSize(2097152);
System.out.println("RECV BUF: "+rtp.getReceiveBufferSize());
System.out.println("SEND BUF: "+rtp.getSendBufferSize());
session = new RTPSession(rtp, rtcp);
session.addParticipant(new Participant(host, RTP_PORT, RTCP_PORT));
}
public void setupDecoderRenderer(Surface renderTarget) {
@@ -150,8 +138,19 @@ public class NvVideoStream {
decrend.setup(1280, 720, renderTarget);
}
public void startVideoStream(final String host)
{
// Read the first frame to start the UDP video stream
try {
readFirstFrame(host);
} catch (IOException e2) {
abort();
return;
}
}
public void startVideoStream(final String host, final Surface surface)
public void setupVideoStream(final String host, final Surface surface)
{
// This thread becomes the output display thread
Thread t = new Thread() {
@@ -163,8 +162,11 @@ public class NvVideoStream {
// Open RTP sockets and start session
try {
setupRtpSession(host);
} catch (SocketException e1) {
e1.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
return;
} catch (UnknownHostException e) {
e.printStackTrace();
return;
}
@@ -173,14 +175,6 @@ public class NvVideoStream {
// the reference frame
startUdpPingThread();
// Read the first frame to start the UDP video stream
try {
readFirstFrame(host);
} catch (IOException e2) {
abort();
return;
}
// Start the receive thread early to avoid missing
// early packets
startReceiveThread();
@@ -191,6 +185,7 @@ public class NvVideoStream {
// Start decoding the data we're receiving
startDecoderThread();
// Start the renderer
decrend.start();
}
};
@@ -293,15 +288,18 @@ public class NvVideoStream {
@Override
public void run() {
// PING in ASCII
final byte[] pingPacket = new byte[] {0x50, 0x49, 0x4E, 0x47};
// RTP payload type is 127 (dynamic)
session.payloadType(127);
final byte[] pingPacketData = new byte[] {0x50, 0x49, 0x4E, 0x47};
DatagramPacket pingPacket = new DatagramPacket(pingPacketData, pingPacketData.length);
// Send PING every 100 ms
while (!isInterrupted())
{
session.sendData(pingPacket);
try {
rtp.send(pingPacket);
} catch (IOException e) {
abort();
return;
}
try {
Thread.sleep(100);

View File

@@ -2,7 +2,7 @@ package com.limelight.nvstream.av.audio;
public class OpusDecoder {
static {
System.loadLibrary("nv_av_dec");
System.loadLibrary("nv_opus_dec");
}
public static native int init();

View File

@@ -2,12 +2,20 @@ package com.limelight.nvstream.av.video;
public class AvcDecoder {
static {
System.loadLibrary("nv_av_dec");
// FFMPEG dependencies
System.loadLibrary("avutil-52");
System.loadLibrary("swresample-0");
System.loadLibrary("swscale-2");
System.loadLibrary("avcodec-55");
System.loadLibrary("avformat-55");
System.loadLibrary("avfilter-3");
System.loadLibrary("nv_avc_dec");
}
public static native int init(int width, int height);
public static native void destroy();
public static native int getCurrentFrame(byte[] yuvframe, int size);
public static native boolean getCurrentFrame(int[] rgbframe, int sizeints);
public static native int getFrameSize();
public static native int decode(byte[] indata, int inoff, int inlen);
}

View File

@@ -2,6 +2,8 @@ package com.limelight.nvstream.av.video;
import java.nio.ByteBuffer;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.Surface;
import com.limelight.nvstream.av.AvByteBufferDescriptor;
@@ -12,25 +14,58 @@ public class CpuDecoderRenderer implements DecoderRenderer {
private Surface renderTarget;
private ByteBuffer decoderBuffer;
private Thread rendererThread;
private int width, height;
@Override
public void setup(int width, int height, Surface renderTarget) {
this.renderTarget = renderTarget;
this.width = width;
this.height = height;
int err = AvcDecoder.init(width, height);
if (err != 0) {
//throw new IllegalStateException("AVC decoder initialization failure: "+err);
throw new IllegalStateException("AVC decoder initialization failure: "+err);
}
decoderBuffer = ByteBuffer.allocate(128*1024);
}
private int getPerFrameDelayMs(int frameRate) {
return 1000 / frameRate;
}
@Override
public void start() {
rendererThread = new Thread() {
@Override
public void run() {
int[] frameBuffer = new int[AvcDecoder.getFrameSize()];
while (!isInterrupted())
{
try {
// CPU decoding frame rate target is 30 fps
Thread.sleep(getPerFrameDelayMs(30));
} catch (InterruptedException e) {
return;
}
if (!AvcDecoder.getCurrentFrame(frameBuffer, frameBuffer.length))
continue;
// Draw the new bitmap to the canvas
Canvas c = renderTarget.lockCanvas(null);
c.drawBitmap(frameBuffer, 0, width, 0, 0, width, height, false, null);
renderTarget.unlockCanvasAndPost(c);
}
}
};
rendererThread.start();
}
@Override
public void stop() {
rendererThread.interrupt();
}
@Override
@@ -46,6 +81,6 @@ public class CpuDecoderRenderer implements DecoderRenderer {
decoderBuffer.put(bbd.data, bbd.offset, bbd.length);
}
//AvcDecoder.decode(decoderBuffer.array(), 0, decodeUnit.getDataLength());
AvcDecoder.decode(decoderBuffer.array(), 0, decodeUnit.getDataLength());
}
}