1、怎麼實現最小的RTSP伺服器
親 很高興為你解答 以下答案有道友提供
//////rtsp.c//////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <netdb.h>
#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h> //close()
#include "h264.h"
//#define DEST_PORT 8888
typedef struct
{
int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size; //! Nal Unit Buffer size
int forbidden_bit; //! should be always FALSE
int nal_reference_idc; //! NALU_PRIORITY_xxxx
int nal_unit_type; //! NALU_TYPE_xxxx
char *buf; //! contains the first byte followed by the EBSP
unsigned short lost_packets; //! true, if packet loss is detected
} NALU_t;
FILE *bits = NULL; //!< the bit stream file
static int FindStartCode2 (unsigned char *Buf);//查找開始字元0x000001
static int FindStartCode3 (unsigned char *Buf);//查找開始字元0x00000001
//static bool flag = true;
static int info2=0, info3=0;
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
/**
int sock_init(int sockfd,struct sockaddr_in addr,int SERVER_PORT)
{
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
printf("sockfd is %d\n",sockfd);
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(SERVER_PORT);
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in))<0)
{
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
printf("init successfel!!\nport is %dsockfd is %d\n",SERVER_PORT,sockfd);
return 0;
}
*/
char* sock_recv(int sockfd,struct sockaddr *addr_client,int *addrlen)
{
//int *tem_len = &addrlen;
socklen_t len;
printf("sock_recv sockfd is %d\n",sockfd);
char *recv_buffer = malloc (sizeof (char));
//printf("sock_recv sockfd is88888888888888 %d\n",sockfd);
int n;
n=recvfrom(sockfd,recv_buffer,256,0,addr_client,&len);
//printf("recv number is %d\n",n);
if(0)
{
printf("recvfrom error!\n");
exit (1);
}
if(-1==n)
{
perror("recv error:");
}
else
{
addrlen=(int *)len;
printf("sock recv success!!\n");
/** char IPdotdec[20]; //存放點分十進制IP地址
struct in_addr s =
inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
printf("addr_client.data=%s\n",IPdotdec);
*/ printf("addr_len=%ld\n",addrlen);
}
return recv_buffer;
}
//為NALU_t結構體分配內存空間
NALU_t *AllocNALU(int buffersize)
{
NALU_t *n;
if ((n = (NALU_t*)calloc (1, sizeof (NALU_t))) == NULL)
{
printf("AllocNALU: n");
exit(0);
}
n->max_size=buffersize;
if ((n->buf = (char*)calloc (buffersize, sizeof (char))) == NULL)
{
free (n);
printf ("AllocNALU: n->buf");
exit(0);
}
return n;
}
//釋放
void FreeNALU(NALU_t *n)
{
if (n)
{
if (n->buf)
{
free(n->buf);
n->buf=NULL;
}
free (n);
}
}
void OpenBitstreamFile (char *fn)
{
if (NULL == (bits=fopen(fn, "rb")))
{
printf("open file error\n");
exit(0);
}
printf("test264 open successful!\n");
}
//這個函數輸入為一個NAL結構體,主要功能為得到一個完整的NALU並保存在NALU_t的buf中,獲取他的長度,填充F,IDC,TYPE位。
//並且返回兩個開始字元之間間隔的位元組數,即包含有前綴的NALU的長度
int GetAnnexbNALU (NALU_t *nalu)
{
int pos = 0;
int StartCodeFound, rewind;
unsigned char *Buf;
if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL)
printf ("GetAnnexbNALU: Could not allocate Buf memory\n");
nalu->startcodeprefix_len=3;//初始化碼流序列的開始字元為3個位元組
if (3 != fread (Buf, 1, 3, bits))//從碼流中讀3個位元組
{
free(Buf);
return 0;
}
info2 = FindStartCode2 (Buf);//判斷是否為0x000001
if(info2 != 1)
{
//如果不是,再讀一個位元組
if(1 != fread(Buf+3, 1, 1, bits))//讀一個位元組
{
free(Buf);
return 0;
}
info3 = FindStartCode3 (Buf);//判斷是否為0x00000001
if (info3 != 1)//如果不是,返回-1
{
free(Buf);
return -1;
}
else
{
//如果是0x00000001,得到開始前綴為4個位元組
pos = 4;
nalu->startcodeprefix_len = 4;
}
}
else
{
//如果是0x000001,得到開始前綴為3個位元組
nalu->startcodeprefix_len = 3;
pos = 3;
}
//查找下一個開始字元的標志位
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (!StartCodeFound)
{
if (feof (bits))//判斷是否到了文件尾
{
nalu->len = (pos-1)-nalu->startcodeprefix_len;
memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);
nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
free(Buf);
return pos-1;
}
Buf[pos++] = fgetc (bits);//讀一個位元組到BUF中
info3 = FindStartCode3(&Buf[pos-4]);//判斷是否為0x00000001
if(info3 != 1)
info2 = FindStartCode2(&Buf[pos-3]);//判斷是否為0x000001
StartCodeFound = (info2 == 1 || info3 == 1);
}
// Here, we have found another start code (and read length of startcode bytes more than we should
// have. Hence, go back in the file
rewind = (info3 == 1)? -4 : -3;
if (0 != fseek (bits, rewind, SEEK_CUR))//把文件指針指向前一個NALU的末尾
{
free(Buf);
printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
}
// Here the Start code, the complete NALU, and the next start code is in the Buf.
// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code
// 不管有沒有再次讀到 頭 ,其主要 關心的還是 nalu->len
nalu->len = (pos+rewind)-nalu->startcodeprefix_len;
memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//拷貝一個完整NALU,不拷貝起始前綴0x000001或0x00000001
nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bit
nalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bit
nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bit
free(Buf);
return (pos+rewind);//返回兩個開始字元之間間隔的位元組數,即包含有前綴的NALU的長度
}
//輸出NALU長度和TYPE
void mp(NALU_t *n)
{
if (!n)return;
//printf("a new nal:");
printf(" len: %d ", n->len);
printf("nal_unit_type: %x\n", n->nal_unit_type);
}
希望能幫助你
2、有支持3種碼流的網路攝像機嗎?
我知道網視無憂這個品牌的網路攝像機可以支持3種碼流,可以滿足本地,互聯網,跨平台訪問的要求,有興趣可以找他們廠家詳細了解。
3、這個算25MB的高清碼流嗎?
D1格式一般一張圖片是220K,
定碼率下一個小時一個通道錄像文件大小的計算公式如下:
碼流(kbit/s) ÷ 8 × 3600 ÷ 1024 (單位:MB)
意思是1秒鍾8張圖片的情況下,3600秒是1小時,得出來的數是多少Kb,除以1024,得出1個通道用D1格式記錄的文件大小。
一般D1(4cif)錄像1小時是100M,你調成2幀每秒除以4,最後就是1小時25MB了
12小時300MB
120G=120*1024MB=12880MB
12880MB/25(MB/小時)=4900小時
算上光照不夠的情況下每小時文件會增大5M,估計你可以保存4500小時
你可以選擇覆蓋
問題2:
普通攝像機達到 D1沒問題,這個碼率主要是對硬碟錄像機或者是視頻伺服器來說的
問題三
白平衡你需要設置AUTO,這樣白天夜間色溫差別會小點
櫃台不算太長,但我還是建議你選擇一個較小的空間進行監控,不過一般來說在看清人臉的前提下,普通攝像機能看清楚4米左右的范圍
給你個公式,我經常用的
正確選用鏡頭焦距的理論計算
攝取景物的鏡頭視場角是極為重要的參數,鏡頭視場角隨鏡頭焦距及攝像機規格大小而變化(其變化關系如前所述),覆蓋景物鏡頭的焦距可用下述公式計算:
(1)f=u·D/U
(2)f=h·D/H
f:鏡頭焦距、U:景物實際高度、H:景物實際寬度、D:鏡頭至景物實測距離、u:圖像高度、h:圖像寬度
舉例說明:
當選用1/2〃鏡頭時,圖像尺寸為u=4.8mm,h=6.4mm。鏡頭至景物距離D=3500mm,景物的實際高度為U=2500mm(景物的實際寬度可由下式算出H=1.333·U,這種關系由攝像機取景器CCD片決定)。
將以上參數代入公式(1)中,可得f=4.8·3500/2500=6.72mm,故選用6mm定焦鏡頭即可。
強烈建議你選用攝像機的時候不要貪圖便宜去選擇國產的、有各種功能的攝像機,因為你如果買來,用3個月之後你會後悔的,因為原材料就不是一個等級的。
三星或者sony是最好的選擇,你有錢可以選福特
4、我的視頻使用300Kbps的碼流,我的伺服器帶寬是10M,請問我的伺服器能承受同時多少人的視頻訪問。
應該是273個,帶寬10m/s=10*1024KB/S
而300Kbps=37.5KB/S
所以10240除以37.5等於273.06666不盡
故可以承受約273人的訪問 不過這是全速版理論值
考慮到服權務器工作狀態(不滿載,不超載)和網路狀況
應該在220人左右吧
自己算的 看著給吧
5、如何將伺服器上採集的海康H.264碼流進行後期傳送及處理?
1
2的話重新編解碼費時
6、如何通過python把一段碼流發到伺服器
建議看看socket通信那部分, 很簡單的,碼流你確定可以處理ok?我覺得你會處理碼流,一個socket通信算個p!
7、視頻監控系統中,解析度與碼流的關系?
D1格式一般一張圖片是220K,
定碼率下一個小時一個通道錄像文件大小的計算公式如下:
碼流(kbit/s) ÷ 8 × 3600 ÷ 1024 (單位:MB)
意思是1秒鍾8張圖片的情況下,3600秒是1小時,得出來的數是多少Kb,除以1024,得出1個通道用D1格式記錄的文件大小。
一般D1(4cif)錄像1小時是100M,你調成2幀每秒除以4,最後就是1小時25MB了
12小時300MB
120G=120*1024MB=12880MB
12880MB/25(MB/小時)=4900小時
算上光照不夠的情況下每小時文件會增大5M,估計你可以保存4500小時
你可以選擇覆蓋
問題2:
普通攝像機達到 D1沒問題,這個碼率主要是對硬碟錄像機或者是視頻伺服器來說的
問題三
白平衡你需要設置AUTO,這樣白天夜間色溫差別會小點
櫃台不算太長,但我還是建議你選擇一個較小的空間進行監控,不過一般來說在看清人臉的前提下,普通攝像機能看清楚4米左右的范圍
給你個公式,我經常用的
正確選用鏡頭焦距的理論計算
攝取景物的鏡頭視場角是極為重要的參數,鏡頭視場角隨鏡頭焦距及攝像機規格大小而變化(其變化關系如前所述),覆蓋景物鏡頭的焦距可用下述公式計算:
(1)f=u·D/U
(2)f=h·D/H
f:鏡頭焦距、U:景物實際高度、H:景物實際寬度、D:鏡頭至景物實測距離、u:圖像高度、h:圖像寬度
舉例說明:
當選用1/2〃鏡頭時,圖像尺寸為u=4.8mm,h=6.4mm。鏡頭至景物距離D=3500mm,景物的實際高度為U=2500mm(景物的實際寬度可由下式算出H=1.333·U,這種關系由攝像機取景器CCD片決定)。
將以上參數代入公式(1)中,可得f=4.8·3500/2500=6.72mm,故選用6mm定焦鏡頭即可。
強烈建議你選用攝像機的時候不要貪圖便宜去選擇國產的、有各種功能的攝像機,因為你如果買來,用3個月之後你會後悔的,因為原材料就不是一個等級的。
三星或者sony是最好的選擇,你有錢可以選福特
8、網路攝像機一般佔用網路帶寬是多少?
那要看你網路攝像機的解析度了。
一般CIF在500Kbps左右;D1在1.5Mbps左右 100W佔用3Mbps左右;200W佔用5Mbps左右。(注意是Mbps不是MBps),圖像流暢,動態畫面基本不會出現馬賽克現象。