Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Не надо писать в комментариях про организацию на большую букву «I». Их Server использует SQLite, SSL, avcodec (ffmpeg)… но я не видел у них поддержку Onvif, видимо потому что они выпускают «свои» камеры.
/**
* Created by calc on 17.07.14.
* http://tools.ietf.org/html/rfc3550#page-19
*
* From wireshark:
* RTCP senders report (200)
* 01234567 01234567 01234567 01234567
* +--------+--------+--------+--------+
* |V P RC | type201| length (octets) |
* v-2bit
* p-1bit
* 01234567 01234567 01234567 01234567
* +--------+--------+--------+--------+
* SSRC
* NTP timestamp MSW
* NTP timestamp LSW
* RTPWrapper timestamp
* senders packet count
* senders octet count
*
* RTCP source description (202)
* +--------+--------+--------+--------+
* |V P SC | type202| length |
* chunks:
* Chunk 1:
* +--------+--------+--------+--------+
* Identifier (SSRC?)
* SDES:
* +--------+--------+
* type length Text... End(0)
*
*
* +--------+--------+--------+--------+
* |V P RC | type201| length (octets) |
* ssrc
* Sources:
* +-Source1:
* +-Identifier (4bytes)
* +-SSRC content
* + fraction lost 1byte
* + Cumulative number of packets lost: -1 (3 bytes)
* + extended highest sequence number received
* + cycle 2b
* + number 2b
* + jitter 4b
* + LSR (middle of NTP timestamp)
* + Delay since last SR 4b
*
*
*
*/
public static byte[] response201(RTCP rtcp, int loop, int seq, int channel, long last, int jitter){
byte[] buffer = new byte[32];
int i = 0;
//header
buffer[i++] = (byte)0x81; //1000 0001
buffer[i++] = (byte)RTCP.TYPE_RECEIVER_REPORT;
buffer[i++] = 0; buffer[i++] = 7; // 32/4-1
//my ssrc
System.arraycopy(ssrc, 0, buffer, i, ssrc.length);
i += ssrc.length;
buffer[i-1] = (byte)channel;
//source 1
System.arraycopy(rtcp.getBuffer(), rtcp.getSSRCStart(), buffer, i, 4);
i += 4;
//fraction lost
buffer[i++] = (byte)0x00;
//Cumulative number of packets lost: -1
/*buffer[i++] = (byte)0xff;
buffer[i++] = (byte)0xff;
buffer[i++] = (byte)0xff;*/
buffer[i++] = 0;
buffer[i++] = 0;
buffer[i++] = 0;
//Extended highest sequence number received:
buffer[i++] = BIT.HiByte(BIT.LoWord(loop));
buffer[i++] = BIT.LoByte(BIT.LoWord(loop));
buffer[i++] = BIT.HiByte(BIT.LoWord(seq));
buffer[i++] = BIT.LoByte(BIT.LoWord(seq));
//Interarrival jitter:
buffer[i++] = BIT.HiByte(BIT.HiWord(jitter));
buffer[i++] = BIT.LoByte(BIT.HiWord(jitter));
buffer[i++] = BIT.HiByte(BIT.LoWord(jitter));
buffer[i++] = BIT.LoByte(BIT.LoWord(jitter));
//Last SR timestamp: 3810671619 (0xe3223c03)
buffer[i++] = BIT.HiByte(BIT.LoWord(rtcp.getHiNTPTimestamp()));
buffer[i++] = BIT.LoByte(BIT.LoWord(rtcp.getHiNTPTimestamp()));
buffer[i++] = BIT.HiByte(BIT.HiWord(rtcp.getLowNTPTimestamp()));
buffer[i++] = BIT.LoByte(BIT.HiWord(rtcp.getLowNTPTimestamp()));
//Delay since last SR timestamp: 71531 (1091 milliseconds)
//1/65536
long now = System.currentTimeMillis();
int range = (int)(((double)(now - last)/1000) * 65536);
buffer[i++] = BIT.HiByte(BIT.HiWord(range));
buffer[i++] = BIT.LoByte(BIT.HiWord(range));
buffer[i++] = BIT.HiByte(BIT.LoWord(range));
buffer[i++] = BIT.LoByte(BIT.LoWord(range));
/*buffer[i++] = 0;
buffer[i++] = 0;
buffer[i++] = 0x06;
buffer[i++] = 0x68;*/
return buffer;
}
private Thread createRTCPThread(){
return new Thread(new Runnable() {
private void send(Source s){
if(s.lastRTCP == null) return;
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] frame = {'$', (byte)s.controlCh, 0, 52};
try {
bo.write(frame);
RTCP r = s.lastRTCP;
do {
if(r.getPT() == RTCP.TYPE_SENDER_REPORT){
bo.write(
RTCP.response201(r, s.loop, s.sequence, s.controlCh,
s.lastRTCPTime, (int)s.jitter));
}
else if(r.getPT() == RTCP.TYPE_SOURCE_DESCRIPTION){
bo.write(RTCP.response202(r, s.controlCh));
} else {
System.out.println("RTCP Thread - Херня какая то: " + r.getPT());
}
}while ( (r = r.getNextRTCP()) != null);
out.write(bo.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while(!stop){
try {
Thread.sleep(4500);
} catch (InterruptedException e) {
e.printStackTrace();
}
send(sources.get(0));
//send ch1
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//send ch2
send(sources.get(1));
}
}
});
}
private class Source{
public int ch;
public int controlCh;
public int SSRC;
public RTCP lastRTCP;
public long lastRTCPTime;
public long jitter;
public long transit;
public int loop;
public int sequence;
//Перевезти в эти переменные массив os[]
private OutputStream dataOut;
private OutputStream controlOut;
public void calculate(RTPWrapper rtp){
long ts = uInt.get(rtp.getTimestamp());
long arrival = System.currentTimeMillis() / 1000L;
long transit = arrival - ts;
long d = transit - this.transit;
this.transit = transit;
if(d < 0) d = -d;
jitter += (1./16.) * ((double)d - jitter);
int oldSeq = sequence;
int newSeq = rtp.getSequence();
if(newSeq < oldSeq) loop++;
sequence = newSeq;
}
}

Пока все производители камер не перейдут на «православный» web h264
А сервер нужен для стандартизации потоков с камер. После этого можно и в web, и в файлы, и в космос.
IP camera Name DCS-2103
Time & Date Wed Jan 16 07:32:58 2013
Firmware Version 1.20.00
MAC Address F0:7D:68:09:E4:F4
IP Address 10.112.28.231
IP Subnet Mask 255.255.255.0
Default Gateway 10.112.28.253
Primary DNS 10.112.1.1
Secondary DNS 10.112.2.1
PPPoE Disable
DDNS Disable
В сентябре новая работа будет искаться.
Почему простые вещи делают сложными, неужели только от жадности?
Еще раз о видеонаблюдении, камерах, RTSP, onvif. И «велосипед»!