package javaforce.voip; /** * Encodes/Decodes RTP/JPEG packets (type 26). * * http://tools.ietf.org/rfc/rfc2435.txt * * @author pquiring */ import java.util.*; import javaforce.*; public class RTPJPEG { public RTPJPEG() { ssrc = new Random().nextInt(); } /** Encodes a raw JPEG data into multiple RTP packets. */ public byte[][] encode(byte jpeg[], int x, int y) { int cnt = (jpeg.length + mtu - 1) / mtu; int len = jpeg.length; byte packets[][] = new byte[cnt][]; int packetLength; int offset = 0; for(int a=0;a<cnt;a++) { if (len > mtu) packetLength = mtu; else packetLength = len; packets[a] = new byte[packetLength + 12 + 8]; //12=RTP.length 8=rtp_jpeg_header.length RTPChannel.buildHeader(packets[a], RTP.CODEC_JPEG.id, seqnum, timestamp, ssrc, a == cnt-1); buildHeader(packets[a], x, y, offset); System.arraycopy(jpeg, offset, packets[a], 12 + 8, packetLength); offset += packetLength; len -= packetLength; } packets[cnt-1][1] |= 0x80; //mark last packet (marker) seqnum++; timestamp += 100; //??? 10 fps ??? return packets; } public byte[] decode(byte rtp[]) { if (rtp.length < 12 + 8) return null; //bad packet if (partial == null) partial = new byte[0]; int offset = ((int)rtp[13]) & 0xff; offset <<= 8; offset += ((int)rtp[14]) & 0xff; offset <<= 8; offset += ((int)rtp[15]) & 0xff; if (offset != partial.length) { //lost a packet JFLog.log("RTPJPEG:decode:lost a packet or not in order"); partial = null; return null; } int jpegLength = rtp.length - 12 - 8; int partialLength = partial.length; partial = JF.copyOf(partial, partial.length + jpegLength); System.arraycopy(rtp, 12+8, partial, partialLength, jpegLength); if ((rtp[1] & 0x80) == 0x80) { //check for marker byte[] full = partial; partial = null; return full; } return null; } private static void buildHeader(byte data[], int x, int y, int offset) { data[12] = 0; //type-specfic ??? data[13] = (byte) ((offset & 0xff0000) >> 16); data[14] = (byte) ((offset & 0xff00) >> 8); data[15] = (byte) (offset & 0xff); data[16] = 0; //type ?? data[17] = 0; //Q ?? data[18] = (byte)(x/8); //width data[19] = (byte)(y/8); //height } //mtu = 1500 - 14(ethernet) - 20(ip) - 8(udp) - 12(rtp) - 8(rtp_jpeg_header) = 1438 bytes payload per packet private static final int mtu = 1438; private int seqnum; private int timestamp; private int ssrc; private byte partial[]; }