156 lines
4.0 KiB
Java
156 lines
4.0 KiB
Java
package com.limelight.nvstream;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.net.DatagramSocket;
|
|
import java.net.Socket;
|
|
import java.net.SocketException;
|
|
import java.net.UnknownHostException;
|
|
import java.nio.ByteBuffer;
|
|
|
|
import jlibrtp.DataFrame;
|
|
import jlibrtp.Participant;
|
|
import jlibrtp.RTPAppIntf;
|
|
import jlibrtp.RTPSession;
|
|
|
|
import android.media.MediaCodec;
|
|
import android.media.MediaCodec.BufferInfo;
|
|
import android.media.MediaFormat;
|
|
import android.view.Surface;
|
|
|
|
public class NvVideoStream implements RTPAppIntf {
|
|
public static final int RTP_PORT = 47998;
|
|
public static final int RTCP_PORT = 47999;
|
|
public static final int FIRST_FRAME_PORT = 47996;
|
|
|
|
private MediaCodec codec;
|
|
|
|
private InputStream getFirstFrame(String host) throws UnknownHostException, IOException
|
|
{
|
|
Socket s = new Socket(host, FIRST_FRAME_PORT);
|
|
return s.getInputStream();
|
|
}
|
|
|
|
public void startVideoStream(final String host, final Surface surface)
|
|
{
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
public void run() {
|
|
|
|
byte[] firstFrame = new byte[98];
|
|
try {
|
|
System.out.println("VID: Waiting for first frame");
|
|
InputStream firstFrameStream = getFirstFrame(host);
|
|
|
|
int offset = 0;
|
|
do
|
|
{
|
|
offset = firstFrameStream.read(firstFrame, offset, firstFrame.length-offset);
|
|
} while (offset != firstFrame.length);
|
|
System.out.println("VID: First frame read ");
|
|
} catch (UnknownHostException e2) {
|
|
// TODO Auto-generated catch block
|
|
e2.printStackTrace();
|
|
return;
|
|
} catch (IOException e2) {
|
|
// TODO Auto-generated catch block
|
|
e2.printStackTrace();
|
|
return;
|
|
}
|
|
|
|
final DatagramSocket rtp, rtcp;
|
|
try {
|
|
rtp = new DatagramSocket(RTP_PORT);
|
|
rtcp = new DatagramSocket(RTCP_PORT);
|
|
} catch (SocketException e1) {
|
|
// TODO Auto-generated catch block
|
|
e1.printStackTrace();
|
|
return;
|
|
}
|
|
|
|
codec = MediaCodec.createDecoderByType("video/avc");
|
|
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1280, 720);
|
|
codec.configure(mediaFormat, surface, null, 0);
|
|
codec.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
|
|
codec.start();
|
|
|
|
|
|
int inputIndex = codec.dequeueInputBuffer(-1);
|
|
if (inputIndex >= 0)
|
|
{
|
|
ByteBuffer buf = codec.getInputBuffers()[inputIndex];
|
|
|
|
buf.clear();
|
|
buf.put(firstFrame);
|
|
|
|
codec.queueInputBuffer(inputIndex,
|
|
0, firstFrame.length,
|
|
100, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
|
|
}
|
|
|
|
RTPSession session = new RTPSession(rtp, rtcp);
|
|
session.addParticipant(new Participant(host, RTP_PORT, RTCP_PORT));
|
|
session.RTPSessionRegister(NvVideoStream.this, null, null);
|
|
|
|
for (;;)
|
|
{
|
|
BufferInfo info = new BufferInfo();
|
|
int outIndex = codec.dequeueOutputBuffer(info, -1);
|
|
switch (outIndex) {
|
|
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
|
|
System.out.println("Output buffers changed");
|
|
break;
|
|
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
|
|
System.out.println("Output format changed");
|
|
break;
|
|
case MediaCodec.INFO_TRY_AGAIN_LATER:
|
|
System.out.println("Try again later");
|
|
break;
|
|
default:
|
|
if (outIndex >= 0)
|
|
{
|
|
codec.releaseOutputBuffer(outIndex, true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
@Override
|
|
public void receiveData(DataFrame frame, Participant participant) {
|
|
|
|
ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
|
|
|
|
int inputIndex = codec.dequeueInputBuffer(-1);
|
|
if (inputIndex >= 0)
|
|
{
|
|
ByteBuffer buf = codecInputBuffers[inputIndex];
|
|
|
|
buf.clear();
|
|
buf.put(frame.getConcatenatedData());
|
|
|
|
if (buf.position() != 1024)
|
|
{
|
|
System.out.println("Data length: "+buf.position());
|
|
System.out.println(buf.get()+" "+buf.get()+" "+buf.get());
|
|
}
|
|
|
|
codec.queueInputBuffer(inputIndex,
|
|
0, buf.position(),
|
|
10000000, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void userEvent(int type, Participant[] participant) {
|
|
}
|
|
|
|
@Override
|
|
public int frameSize(int payloadType) {
|
|
return 1;
|
|
}
|
|
}
|