mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-04-05 23:46:04 +00:00
Remove jlibrtp (finally). CPU decoding support (works great on Tegra 4, not so well on Tegra 3)
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user