前兩天把攝像頭網絡傳輸程序搞定了,傳輸效果也挺不錯,至少沒有出現畫面錯誤。那接下來,我想探究一下這個程序的效率:傳輸速度,顯示速度,內存佔用等等。
先說速度的問題吧。說道速度,那就要拿東西來計時,計算每一幀需要消耗的時間,取個倒數,就是fps了。怎麼計時呢?
把c語言 計時作爲關鍵字百度一下,有好幾個方法。那是不是隨便選一個用呢,答案肯定非也。如果都一樣,那還需要那麼多方法幹什麼,是吧~所以得選一個適合的,適合當前這個問題的。那我先把各種方法來實驗一遍,找到一個最好的用:
首先是clock():
這個函數在<time.h>中,返回值類型是clock_t,精度:毫秒級,誤差比較大
#include <stdio.h>
#include <time.h>
int main() {
clock_t start, end;
long timeuse;
start = clock();
printf("start : %d\n", start);
sleep(1);
// usleep(200000);
end = clock();
printf("end : %d\n", end);
timeuse = end - start;
printf("time use : %d\n", timeuse);
return 0;
}
運行了10次,居然沒有一次是精準的,誤差很大。。。這讓我很驚訝,網上的代碼運行起來能精確的毫秒級,但我不清楚爲什麼,誤差這麼大。。。顯然這個肯定不能用在我的程序裏。
然後gettimeofday():
在<sys/time.h>中,無返回值,精度:微妙級,很精準!!
#include <stdio.h>
#include <sys/time.h>
int main() {
struct timeval t_start, t_end;
long timeuse;
gettimeofday(&t_start, NULL);
sleep(2);
usleep(500000);
gettimeofday(&t_end, NULL);
timeuse = 1000000 * (t_end.tv_sec - t_start.tv_sec) + t_end.tv_usec - t_start.tv_usec;
timeuse /= 1000;
printf("time used : %d ms\n", timeuse);
return 0;
}
timeval 结构定义为:
struct timeval{
long tv_sec; //秒
long tv_usec; //微秒
};
經過測試,這個函數準精度很高,精度也很高!就選這個了~~
還有一個time():
頭文件是<time.h>,返回值是以格林尼治时间(GMT)为标准,从1970年1月1日00:00:00到现在的此时此刻所经过的秒数,精度嘛,就是秒啦
#include <stdio.h>
#include <time.h>
int main() {
time_t start,end;
start =time(NULL);//or time(&start);
printf("start : %d\n", start);
//…calculating…
sleep(1);
end =time(NULL);
printf("end : %d\n", end);
printf("time used = %d\n", end - start);
return 0;
}
明顯這個也不符合我的需求。。。
但是這些方法都能獲取時間和經過的時間,適用於不同的場合吧~
接下來把第二種方法加到我的服務端程序中:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <cv.h>
#include <highgui.h>
#define BUFFSIZE 16*1024
long Time_calc(struct timeval start, struct timeval end) {
return (1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec) / 1000;
}
int main(int argc, char *argv[]) {
int skfd, cnfd, addr_len, i;
long imagedataleft = 0;
struct sockaddr_in srv_addr, clt_addr;
int portnumber;
char hello[] = "~~WELCOME~~\n";
char *databuff = {0};
int framerate = 0;
char sync[2] = {0, 0};
struct timeval t_start, t_end;
long timeuse;
IplImage *frame = 0, header;
if(2 != argc || 0 > (portnumber = atoi(argv[1]))) {
printf("Usage:%s port\n", argv[0]);
exit(1);
}
if(-1 == (skfd = socket(AF_INET, SOCK_STREAM, 0))) {
perror("Socket Error:");
exit(1);
}
bzero(&srv_addr, sizeof(struct sockaddr_in));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
srv_addr.sin_port = htons(portnumber);
if(-1 == bind(skfd, (struct sockaddr *)(&srv_addr), sizeof(struct sockaddr))) {
perror("Bind error:");
exit(1);
}
//開啓監聽
if(-1 == listen(skfd, 4)) {
perror("Listen error:");
exit(1);
}
//阻塞接受請求
addr_len = sizeof(struct sockaddr_in);
if(-1 == (cnfd = accept(skfd, (struct sockaddr *)(&clt_addr), &addr_len))) {
perror("Accept error:");
exit(1);
}
printf("Connect from %s:%u ...!\n", inet_ntoa(clt_addr.sin_addr), ntohs(clt_addr.sin_port));
//初次應答
if(-1 == write(cnfd, hello, strlen(hello))) {
perror("Send error:");
exit(1);
}
//接收index
if(-1 == read(cnfd, (char*)&header, sizeof(IplImage))) {
perror("Read index Error:");
exit(1);
}
//用收到的index參數創建一個新的圖像
frame = cvCreateImageHeader(cvSize(header.width, header.height), header.depth, header.nChannels);
//創建imageData接收緩存
databuff = (char*)malloc(frame->imageSize);
//圖像數據直接指向接收緩存
frame->imageData = databuff;
//創建窗口
cvNamedWindow("camera-server", 1);
while(1) {
gettimeofday(&t_start, NULL);
imagedataleft = 0;
while(imagedataleft < frame->imageSize) {
if((i = read(cnfd, databuff + imagedataleft, BUFFSIZE)) == -1) {
perror("Read Data Error:");
exit(1);
}
//同步數據流
if(-1 == write(cnfd, sync, 2)) {
perror("Sync Error:");
exit(1);
}
imagedataleft += BUFFSIZE;
if(i < BUFFSIZE) {
printf("recv finished!!\n");
break;
}
}
cvShowImage("camera-server", frame);
if(-1 == write(cnfd, "frame done", 10)) {
perror("Ack Error:");
exit(1);
}
gettimeofday(&t_end, NULL);
timeuse = Time_calc(t_start, t_end);
printf("time used : %d || fps : %d\n", timeuse, 1000/timeuse);
if(27 == cvWaitKey(1)) break;
}
free(databuff);
cvReleaseImage(&frame);
cvDestroyWindow("camera-server");
close(cnfd);
close(skfd);
exit(0);
}
再把cilent.c中的cvWaitKey()和cvShowImage()函數注釋掉,就是全速傳輸啦。
可是fps好像不太穩定,有時候是16~17幀,但喲時候只有一半了,待我仔細找找問題出在哪裏~
==================================經過調試,終於發現了問題所在:
攝像頭會自動調節曝光時間:光線強時,曝光時間短,大概50ms;反之,時間會長,長達100ms以上(這是我筆記本自帶的攝像頭)。而數據傳輸處只消耗了3ms,一幀imageData有921600字節,可以忽略每次傳輸後的應答,那淨傳輸的速度就是307M/s,是很快的速度了。