Android的监控一般都是需要用到Jni的,然后进行NDK编译,现在的工业探头走的都是srtp协议,所以接下来就走一下这个协议,首先我们需要创建一个线程用来负责走tcp协议,让探头给我们发送视频数据void *conTrolThread(void *lpParam) {
char szResponse[1024];
char szSendBuf[1024];
int nRet = 0;
int nTimeOut = 5000;
// setsockopt(rtsp_Socket, SOL_SOCKET, SO_RCVTIMEO, (char*) &nTimeOut,
// sizeof(nTimeOut));
rtsp_Socket = socket(AF_INET, SOCK_STREAM, 0);//创建socket
if (rtsp_Socket < 0) {//告诉Java创建Sock失败
return 0;
}
struct sockaddr_in addrSrv;
addrSrv.sin_addr.s_addr = inet_addr(m_IP);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(m_Port);
if (SOCKET_ERROR == connect(rtsp_Socket, (struct sockaddr*) &addrSrv,
sizeof(struct sockaddr))) {//告诉Java创建Sock失败
LOGD("失败\n");
close(rtsp_Socket);
rtsp_Socket = -1;
return 0;
}
char lstrOptions[1024] = "OPTIONS rtsp://%s:%d/H264 RTSP/1.0\r\n"
"CSeq: 1\r\n"
"\r\n";
sprintf(szSendBuf, lstrOptions, m_IP, m_Port);
send(rtsp_Socket, szSendBuf, 1024, 0);
memset(szResponse, 0, sizeof(szResponse));
nRet = recv(rtsp_Socket, &szResponse[0], 1024, 0);
char lstrDescribe[1024] = "DESCRIBE rtsp://%s:%d/H264 RTSP/1.0\r\n"
"CSeq: 2\r\n"
"Content-Length: 0\r\n"
"\r\n";
memset(szSendBuf, 0, sizeof(szSendBuf));
sprintf(szSendBuf, lstrDescribe, m_IP, m_Port);
send(rtsp_Socket, szSendBuf, 1024, 0);
memset(szResponse, 0, sizeof(szResponse));
nRet = recv(rtsp_Socket, &szResponse[0], 1024, 0);
char lstrSetup[1024] = "SETUP rtsp://%s:%d/H264 RTSP/1.0\r\n"
"CSeq: 3\r\n"
"Transport: RTP/AVP;unicast;client_port=6666-6667\r\n"
"\r\n";
memset(szSendBuf, 0, sizeof(szSendBuf));
sprintf(szSendBuf, lstrSetup, m_IP, m_Port);
send(rtsp_Socket, szSendBuf, 1024, 0);
memset(szResponse, 0, sizeof(szResponse));
nRet = recv(rtsp_Socket, &szResponse[0], 1024, 0);
char Session[100];
int i = 0, j = 0;
for (; i < strlen(szResponse) - 9; i++) {
if ('S' == szResponse[i] && 'e' == szResponse[i + 1] && 's'
== szResponse[i + 2] && 's' == szResponse[i + 3] && 'i'
== szResponse[i + 4] && 'o' == szResponse[i + 5] && 'n'
== szResponse[i + 6] && ':' == szResponse[i + 7] && ' '
== szResponse[i + 8]) {
while (szResponse[i + 9 + j] != '\r' && szResponse[i + 10 + j]
!= '\n') {
Session[j] = szResponse[i + 9 + j];
j++;
}
break;
}
}
char lstrPlay[1024] = "PLAY rtsp://%s:%d/H264 RTSP/1.0\r\n"
"CSeq: 4\r\n"
"Content-Length: 0\r\n"
"Session: %s\r\n"
"Range: npt=0.000-\r\n"
"\r\n";
memset(szSendBuf, 0, sizeof(szSendBuf));
sprintf(szSendBuf, lstrPlay, m_IP, m_Port, Session);
send(rtsp_Socket, szSendBuf, 1024, 0);
send(rtsp_Socket, lstrDescribe, 1024, 0);
memset(szResponse, 0, sizeof(szResponse));
nRet = recv(rtsp_Socket, &szResponse[0], 1024, 0);
LOGD("\n");
}
接下来创建一个接收线程用来负责数据的接收
void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) { (jvm_save)->AttachCurrentThread(&env_save, NULL); jarrayVideo = (env_save)->NewByteArray(352 * 288 * 2); int hr; unpack = new RtpUnPack(hr); int n; int outSize = 0; socklen_t len = clilen; unsigned char mesg[20480]; int isFindIFrame = 0; long timebase = 0; InitDecoder(352, 288); while (canReceive) { /* waiting for receive data */ memset(mesg, 0, sizeof(mesg)); n = recvfrom(sockfd, mesg, 2048, 0, pcliaddr, &len); outSize = 0; //接受到视频数据开始拼桢 BYTE *pFrame = unpack->Parse_RTP_Packet(mesg, n, &outSize); if (timebase == 0 || timebase <= unpack->m_RTP_Header.ts) { timebase = unpack->m_RTP_Header.ts; } else { continue; } if (pFrame != NULL) { if (isFindIFrame == 0) { if (outSize > 1456) { isFindIFrame = 1; } else { continue; } } int len = outSize; if (DecoderNal(pFrame, len, videoVideoData) > 0) { disPlayVideo(0, (char *) videoVideoData, c->width, c->height, 0); } } } UninitDecoder(); (env_save)->ReleaseByteArrayElements(jarrayVideo, (jbyte*) videoVideoData, 0); (jvm_save)->DetachCurrentThread(); } void *recvThread(void *lpParam) { int sockfd; struct sockaddr_in servaddr, cliaddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */ /* init servaddr */ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(6666); /* bind address and port to socket */ if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) { perror("bind error"); exit(1); } do_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)); LOGD("接收线程关闭\n"); }