第一节:概述。
首先是 将 他写好的 rtsp 源码上传,用于分析。
已经拷贝完。
第二节: h264 编码概念。
编解码 可以用cpu, 也可以用 bsp
cpu 编解码的效果不好。做控制比较好。
h264 由 VCL, NAL 组成。
NAL 关心的是 压缩的 视频 如何传输。
宏块: MB, 多个像素组成的一块, 因为一幅图片的 一篇区域 颜色是一样的。
片: slice , 比MB 大的概念,具体是什么 ,不清楚呀。
帧: frame
I帧: 非参考帧。
P帧: 参考前面的帧, 它记录的不是 像素,而是 与前面的帧的区别。
B帧: 及参考前面的,又参考后面的。
像素--->宏块---->片----->帧---->序列--->码流。
第三节+ 第四节+第五节+ 第六节, NAL 详解。
VCL是原厂的事情, 我们只关心 NAL。
NAL 是关于网络传输的封包。
SODB: string of data bits , 这就是纯视频流, 可以播放,但是不能传输。
RBSP: raw byte sequence payload ,
NALU : network abstraction layer units
也就是说 NAL, 只是一个头, SODB 就是 新鲜的刚刚压缩完的数据, RBSP trailing bits 不知道是什么, 也就是说说 NALU 加上了 纯数据。
RBSP trailing bits 不知道是什么意思。
海思的 h264的 码流是由 若干个sequence 组成的。
这就是一个 sequenece
一个 sequence 的组成是。
lsps + lpps + lsei +1个I帧 + 若干p帧。
那么 你怎么 知道 ,这个就是 lsps , lpps, lsei , i 帧, p 帧呢,
就是 通过 NALU 来区分的。
也就是说, NALU 就是 lsps, lpps, lsei , i帧, p帧。
分隔符: 00 00 00 01 不是有效数据。
也就是说, lsps , lpps , lsei I帧 ,都要加上分隔符, 后面的p帧 就不加 分隔符了。
分隔符 后面的第一个字节 就是 NALU, 每一个位 都是由特定含义的。
也就是 lsps, lpps, lsei ,I 帧 , p帧 ,都是由 NALU的。
他们的第一个字节 就是 NAL。
这是 8个字节。
0-3 位 ,
4-8 位, 共5位, 可以表示31个数。
5: 代表 I帧
1: 代表 P帧 ,如果没有 B帧的情况下。
7 : 代表 lsps
8: 代表 lpps
6: 代表 lsei
好了, 到目前 一个字节 ,就区分出了, 这个NAUL 是什么类型了, 那么从第一个字节之后,到 00000001 ,之前的解析 都要按照 这个 帧的类型 来去分析这些数据了。
h264 sps 解析。
sps + pps 会影响播放器的行为。
sps 中有 图像的 高 , 宽的分辨率。
这是 sps 的 第一个 字节, 8位的表示。 表示的是 profiel .
level 在后面的字节中有表示。
图像的宽高 也在 后面的字节中。
h264 的 profile + level。
profile 指的是 总体的说明
level 指的是 , 具体的 分辨率啥的。
pps , lei 中的参数就不看了。
知道什么意思就行。
CBR, VBR , 固定码率与 可变码率。 码率就是 每秒钟 编码的次数。
总结一下:
1 、 这里的帧 ,就是 对每一幅图的 压缩。
2 、 然后压缩之后的 出来的 h264 的码流 ,就是 一个一个的sequence 。
3、 一个sequence 就是有 sps , pps , sei , i帧, p帧 , 组成的。
第七节, rtsp 传输源码分析。
这里关键是 他 怎么 打包的 h264 的。
在进行压缩的时候立马 就进入 common_venc 了。
这里就解释了 为什么 运行 rtsp 之后 会有一个 空文件了。
它本来是要往里面写文件的。
但是 后来 就发送出去了,不写文件了。
目前不明白这里的一包数据 ,指的是什么。
还是再 官方的 venc 的基础上改的。
主要改的文件是 sample_venc.c + sample_common_venc.c
1 main
3 RtspServer_init
RtspServerListen
vdRTPSendThread
1 SAMPLE_VENC_720P_CLASSIC
2 SAMPLE_COMM_VENC_StartGetStream
3 SAMPLE_COMM_VENC_GetVencStreamProc
4 SAMPLE_COMM_VENC_Sentjin
VENC_Sent
总结:
1 改的内容与 ortp 的改的内容是一样的。
2 sample_venc.c 中, 多了一个 rtsp 的 init 函数。
3 samle_comm_venc. c 中 多了 , SAMPLE_COMM_VENC_Sentjin 这个发送函数,这个是自己实现的。
4 端口号的配置字段,
5 允许链接的客户端的数量的字段。 MAX_RTSP_CLIENT 默认设置的是 1 .
它这里是用的 是 tcp 。 这里应该是 rtsp 协议。
rtsp , rtp , rtcp 与 udp , tcp
接下来分析 函数 RtspServerListen
5 RtspServerListen
4 socket
3 bind
2 listen
1 accept
16 RtspClientMsg
网络的5层模型。
rtsp 属于应用层。
这两种 消息的格式 ,对应着 , 代码中的 parse + unparse 函数。
这种交互 ,是在 建立了 socket 之后的交互。
其实就是 client 与 server 通信的步骤。
可以看到 这里是 option , describe , setup , paly , 而不是 什么 三次握手。
我想看看 这两部分 , 源码中 是怎么实现的。
接下来对 RtspClientMsg 进行分析。
8 RtspClientMsg
7 ParseRequestString
6 OptionAnswer
5 DescribeAnswer
4 SetupAnswer
3 PlayAnswer
2 PauseAnswer
1 TeardownAnswer
24
descritbeanswer 里面 处理了 sdp , 这样 就不需要 在 vlc 设置 sdp 了。
SetupAnswer 函数 主要设置了 ip 端口的信息。
setup 是客户端 发起的,服务端 要进行解析,它解析出来,
setup 是 udp 的。
这里的东西比较重要。
也就是说,一个 client , 有三个端口, 一个视频的 ,一个音频的,这两个通过 track 来区分。
还有就是, 一个rtcp 的端口,
另外这个 reqchn ,就是 通道,这个应该是 编码的通道吧?
第十一节, rtsp 实战分析。
这里 server 在play 的时候,重新建立了 一个 udp 的连接。
他 把这个新的连接 叫做通道。
总结:
1 板子生成的 packet 是什么没搞清楚。
2 rtsp 发送的时候,看样子 就是 通过两个端口 发送的 音频+ 视频。
数据流 , rtp , 走的是 tcp
控制流, rtcp 走的是 tcp
rtsp 走的是 udp
疑问: 那么 rtcp 与 rtsp 什么关系呢?
服务器 listen 线程一直存在, 客户端 不连接之后,可以关闭 某个 客户端的线程。
16 main
15 RtspServer_init
14 RtspServerListen
13 socket
12 bind
11 listen
10 accept
9 RtspClientMsg
8 ParseRequestString
7 OptionAnswer
6 DescribeAnswer
5 SetupAnswer
4 PlayAnswer
3 PauseAnswer
2 TeardownAnswer
1 vdRTPSendThread
18 SAMPLE_VENC_720P_CLASSIC
1 SAMPLE_COMM_VENC_StartGetStream
2 SAMPLE_COMM_VENC_GetVencStreamProc
3 SAMPLE_COMM_VENC_Sentjin
4 VENC_Sent
这里 vdRTPSendThread , 也调用了 venc_send , 不明白它 发送的是什么。
这是在发送一个 头信息。具体干什么的不知道。
12 HI_VOID* vdRTPSendThread(HI_VOID *p)
11 {
10 while(1)
9 {
8 if(!list_empty(&RTPbuf_head))
7 {
6
5 RTPbuf_s *p = get_first_item(&RTPbuf_head,RTPbuf_s,list);
4 VENC_Sent(p->buf,p->len);
3 list_del(&(p->list));
2 free(p->buf);
1 free(p);
960 p = NULL;
1 count--;
2 //printf("count = %d\n",count);
3
4 }
5 usleep(5000);
6 }
7 }
第十二节 , 直接发送与 环状发送。
为什么会有 缓冲区呢?
因为 消费 与 生产的 速度 是不一定的, 有时候 生产快,有时候消费快,如果 某一个是 固定快的话,那么就没有 缓冲区的必要了。
venc_send 就是 直接就发送了。
那么 缓冲区怎么实现的呢?
在 sample_comm_venc.c 中 。
打开 savestream
注释掉 sample_comm_venc_sendto
创建了一个队列, 并且往队列中放数据。
9 HI_S32 saveStream(VENC_STREAM_S *pstStream)
8 {
7 HI_S32 i,j,lens=0;
6
5 for(j=0;j<MAX_RTSP_CLIENT;j++)//have atleast a connect
4 {
3 if(g_rtspClients[j].status == RTSP_SENDING)
2 {
1 for (i = 0; i < pstStream->u32PackCount; i++)
896 {
1 RTPbuf_s *p = (RTPbuf_s *)malloc(sizeof(RTPbuf_s));
2 INIT_LIST_HEAD(&(p->list));
3
4 lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
5 p->buf = (char *)malloc(lens);
6 p->len = lens;
7 memcpy(p->buf,pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
8
9 list_add_tail(&(p->list),&RTPbuf_head);
10 count++;
11 //printf("count = %d\n",count);
12 }
13 }
14 }
15
16 return HI_SUCCESS;
17 }
然后 再 sample_venc.c 中
将 rtpsendthread 打开。
每次从队列中 拿出一个 buffer.
20 HI_VOID* vdRTPSendThread(HI_VOID *p)
19 {
18 while(1)
17 {
16 if(!list_empty(&RTPbuf_head))
15 {
14
13 RTPbuf_s *p = get_first_item(&RTPbuf_head,RTPbuf_s,list);
12 VENC_Sent(p->buf,p->len);
11 list_del(&(p->list));
10 free(p->buf);
9 free(p);
8 p = NULL;
7 count--;
6 //printf("count = %d\n",count);
5
4 }
3 usleep(5000);
2 }
⚑ 1 }
总结: rtsp 并没有像 ortp 那样 , 去编译库文件, 而是 直接 改的 源码, 这样的话, 更容易编译。
第十三节,分包发送。
rtpstamp ,用来标记 一个 frame 的。
rtp 包头
如果是整包的话,就是 NALU .
如果分包了的话,就会 是 FU indicator + FU header 替代的是 NALU。
就到这里吧。
----------------------------------------------------------
接下来就是 我自己的实验了。
这是重头戏。
首先总结一下, 需要改的东西。
sample_venc.c 中
添加 所有的 函数
还需要 添加 头文件。
然后是添加 rtsp init 函数。 这里注意将 vdRTPSendThread 函数注释掉, 因为 跟 venc_send 是 一样的。
sample_comm_venc.c 中 ,
再 最后保存的时候, 使用的是 自己的发送函数。
当然 依然是 去掉 h265的 部分。
这是我添加的代码:
首先是 sample_venc.c 文件。
#define RTSP_ENABLE 1
#if RTSP_ENABLE
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
int g_nSendDataChn = -1;
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
pthread_mutex_t g_sendmutex;
pthread_t g_SendDataThreadId = 0;
//HAL_CLIENT_HANDLE hMainStreamClient = NULL,hSubStreamClient = NULL,hAudioClient = NULL;
char g_rtp_playload[20];
int g_audio_rate = 8000;
//VIDEO_NORM_E gs_enNorm = VIDEO_ENCODING_MODE_NTSC;//30fps
int g_nframerate;
int exitok = 0;
int udpfd;
int count=0;
struct list_head RTPbuf_head = LIST_HEAD_INIT(RTPbuf_head);
static pthread_t gs_RtpPid;
static char const* dateHeader()
{
static char buf[200];
#if !defined(_WIN32_WCE)
time_t tt = time(NULL);
strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
#endif
return buf;
}
static char* GetLocalIP(int sock)
{
struct ifreq ifreq;
struct sockaddr_in *sin;
char * LocalIP = malloc(20);
strcpy(ifreq.ifr_name,"wlan");
if (!(ioctl (sock, SIOCGIFADDR,&ifreq)))
{
sin = (struct sockaddr_in *)&ifreq.ifr_addr;
sin->sin_family = AF_INET;
strcpy(LocalIP,inet_ntoa(sin->sin_addr));
//inet_ntop(AF_INET, &sin->sin_addr,LocalIP, 16);
}
printf("--------------------------------------------%s\n",LocalIP);
return LocalIP;
}
char* strDupSize(char const* str)
{
if (str == NULL) return NULL;
size_t len = strlen(str) + 1;
char* copy = malloc(len);
return copy;
}
int ParseRequestString(char const* reqStr,
unsigned reqStrSize,
char* resultCmdName,
unsigned resultCmdNameMaxSize,
char* resultURLPreSuffix,
unsigned resultURLPreSuffixMaxSize,
char* resultURLSuffix,
unsigned resultURLSuffixMaxSize,
char* resultCSeq,
unsigned resultCSeqMaxSize)
{
// This parser is currently rather dumb; it should be made smarter #####
// Read everything up to the first space as the command name:
int parseSucceeded = FALSE;
unsigned i;
for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) {
char c = reqStr[i];
if (c == ' ' || c == '\t') {
parseSucceeded = TRUE;
break;
}
resultCmdName[i] = c;
}
resultCmdName[i] = '\0';
if (!parseSucceeded) return FALSE;
// Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows:
unsigned j = i+1;
while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space
for (j = i+1; j < reqStrSize-8; ++j) {
if ((reqStr[j] == 'r' || reqStr[j] == 'R')
&& (reqStr[j+1] == 't' || reqStr[j+1] == 'T')
&& (reqStr[j+2] == 's' || reqStr[j+2] == 'S')
&& (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')
&& reqStr[j+4] == ':' && reqStr[j+5] == '/') {
j += 6;
if (reqStr[j] == '/') {
// This is a "rtsp://" URL; skip over the host:port part that follows:
++j;
while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j;
} else {
// This is a "rtsp:/" URL; back up to the "/":
--j;
}
i = j;
break;
}
}
// Look for the URL suffix (before the following "RTSP/"):
parseSucceeded = FALSE;
unsigned k;
for (k = i+1; k < reqStrSize-5; ++k) {
if (reqStr[k] == 'R' && reqStr[k+1] == 'T' &&
reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') {
while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/"
unsigned k1 = k;
while (k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ') --k1;
// the URL suffix comes from [k1+1,k]
// Copy "resultURLSuffix":
if (k - k1 + 1 > resultURLSuffixMaxSize) return FALSE; // there's no room
unsigned n = 0, k2 = k1+1;
while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++];
resultURLSuffix[n] = '\0';
// Also look for the URL 'pre-suffix' before this:
unsigned k3 = --k1;
while (k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ') --k3;
// the URL pre-suffix comes from [k3+1,k1]
// Copy "resultURLPreSuffix":
if (k1 - k3 + 1 > resultURLPreSuffixMaxSize) return FALSE; // there's no room
n = 0; k2 = k3+1;
while (k2 <= k1) resultURLPreSuffix[n++] = reqStr[k2++];
resultURLPreSuffix[n] = '\0';
i = k + 7; // to go past " RTSP/"
parseSucceeded = TRUE;
break;
}
}
if (!parseSucceeded) return FALSE;
// Look for "CSeq:", skip whitespace,
// then read everything up to the next \r or \n as 'CSeq':
parseSucceeded = FALSE;
for (j = i; j < reqStrSize-5; ++j) {
if (reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' &&
reqStr[j+3] == 'q' && reqStr[j+4] == ':') {
j += 5;
unsigned n;
while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j;
for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) {
char c = reqStr[j];
if (c == '\r' || c == '\n') {
parseSucceeded = TRUE;
break;
}
resultCSeq[n] = c;
}
resultCSeq[n] = '\0';
break;
}
}
if (!parseSucceeded) return FALSE;
return TRUE;
}
int OptionAnswer(char *cseq, int sock)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
cseq,dateHeader(),"OPTIONS,DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN");
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n",buf);
}
return TRUE;
}
return FALSE;
}
int DescribeAnswer(char *cseq,int sock,char * urlSuffix,char* recvbuf)
{
if (sock != 0)
{
char sdpMsg[1024];
char buf[2048];
memset(buf,0,2048);
memset(sdpMsg,0,1024);
char*localip;
localip = GetLocalIP(sock);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n",cseq);
pTemp += sprintf(pTemp,"%s",dateHeader());
pTemp += sprintf(pTemp,"Content-Type: application/sdp\r\n");
char *pTemp2 = sdpMsg;
pTemp2 += sprintf(pTemp2,"v=0\r\n");
pTemp2 += sprintf(pTemp2,"o=StreamingServer 3331435948 1116907222000 IN IP4 %s\r\n",localip);
pTemp2 += sprintf(pTemp2,"s=H.264\r\n");
pTemp2 += sprintf(pTemp2,"c=IN IP4 0.0.0.0\r\n");
pTemp2 += sprintf(pTemp2,"t=0 0\r\n");
pTemp2 += sprintf(pTemp2,"a=control:*\r\n");
/*H264 TrackID=0 RTP_PT 96*/
pTemp2 += sprintf(pTemp2,"m=video 0 RTP/AVP 96\r\n");
pTemp2 += sprintf(pTemp2,"a=control:trackID=0\r\n");
pTemp2 += sprintf(pTemp2,"a=rtpmap:96 H264/90000\r\n");
pTemp2 += sprintf(pTemp2,"a=fmtp:96 packetization-mode=1; sprop-parameter-sets=%s\r\n", "AAABBCCC");
#if 1
/*G726*/
pTemp2 += sprintf(pTemp2,"m=audio 0 RTP/AVP 97\r\n");
pTemp2 += sprintf(pTemp2,"a=control:trackID=1\r\n");
if(strcmp(g_rtp_playload,"AAC")==0)
{
pTemp2 += sprintf(pTemp2,"a=rtpmap:97 MPEG4-GENERIC/%d/2\r\n",16000);
pTemp2 += sprintf(pTemp2,"a=fmtp:97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1410\r\n");
}
else
{
pTemp2 += sprintf(pTemp2,"a=rtpmap:97 G726-32/%d/1\r\n",8000);
pTemp2 += sprintf(pTemp2,"a=fmtp:97 packetization-mode=1\r\n");
}
#endif
pTemp += sprintf(pTemp,"Content-length: %d\r\n", strlen(sdpMsg));
pTemp += sprintf(pTemp,"Content-Base: rtsp://%s/%s/\r\n\r\n",localip,urlSuffix);
//printf("mem ready\n");
strcat(pTemp, sdpMsg);
free(localip);
//printf("Describe ready sent\n");
int re = send(sock, buf, strlen(buf),0);
if(re <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n",buf);
}
}
return TRUE;
}
void ParseTransportHeader(char const* buf,
StreamingMode* streamingMode,
char**streamingModeString,
char**destinationAddressStr,
u_int8_t* destinationTTL,
portNumBits* clientRTPPortNum, // if UDP
portNumBits* clientRTCPPortNum, // if UDP
unsigned char* rtpChannelId, // if TCP
unsigned char* rtcpChannelId // if TCP
)
{
// Initialize the result parameters to default values:
*streamingMode = RTP_UDP;
*streamingModeString = NULL;
*destinationAddressStr = NULL;
*destinationTTL = 255;
*clientRTPPortNum = 0;
*clientRTCPPortNum = 1;
*rtpChannelId = *rtcpChannelId = 0xFF;
portNumBits p1, p2;
unsigned ttl, rtpCid, rtcpCid;
// First, find "Transport:"
while (1) {
if (*buf == '\0') return; // not found
if (strncasecmp(buf, "Transport: ", 11) == 0) break;
++buf;
}
// Then, run through each of the fields, looking for ones we handle:
char const* fields = buf + 11;
char* field = strDupSize(fields);
while (sscanf(fields, "%[^;]", field) == 1) {
if (strcmp(field, "RTP/AVP/TCP") == 0) {
*streamingMode = RTP_TCP;
} else if (strcmp(field, "RAW/RAW/UDP") == 0 ||
strcmp(field, "MP2T/H2221/UDP") == 0) {
*streamingMode = RAW_UDP;
//*streamingModeString = strDup(field);
} else if (strncasecmp(field, "destination=", 12) == 0)
{
//delete[] destinationAddressStr;
free(destinationAddressStr);
//destinationAddressStr = strDup(field+12);
} else if (sscanf(field, "ttl%u", &ttl) == 1) {
destinationTTL = (u_int8_t)ttl;
} else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) {
*clientRTPPortNum = p1;
*clientRTCPPortNum = p2;
} else if (sscanf(field, "client_port=%hu", &p1) == 1) {
*clientRTPPortNum = p1;
*clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1;
} else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
*rtpChannelId = (unsigned char)rtpCid;
*rtcpChannelId = (unsigned char)rtcpCid;
}
fields += strlen(field);
while (*fields == ';') ++fields; // skip over separating ';' chars
if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
}
free(field);
}
int SetupAnswer(char *cseq,int sock,int SessionId,char * urlSuffix,char* recvbuf,int* rtpport, int* rtcpport)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
StreamingMode streamingMode;
char* streamingModeString; // set when RAW_UDP streaming is specified
char* clientsDestinationAddressStr;
u_int8_t clientsDestinationTTL;
portNumBits clientRTPPortNum, clientRTCPPortNum;
unsigned char rtpChannelId, rtcpChannelId;
ParseTransportHeader(recvbuf,&streamingMode, &streamingModeString,
&clientsDestinationAddressStr, &clientsDestinationTTL,
&clientRTPPortNum, &clientRTCPPortNum,
&rtpChannelId, &rtcpChannelId);
//Port clientRTPPort(clientRTPPortNum);
//Port clientRTCPPort(clientRTCPPortNum);
*rtpport = clientRTPPortNum;
*rtcpport = clientRTCPPortNum;
char *pTemp = buf;
char*localip;
localip = GetLocalIP(sock);
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sTransport: RTP/AVP;unicast;destination=%s;client_port=%d-%d;server_port=%d-%d\r\nSession: %d\r\n\r\n",
cseq,dateHeader(),localip,
ntohs(htons(clientRTPPortNum)),
ntohs(htons(clientRTCPPortNum)),
ntohs(2000),
ntohs(2001),
SessionId);
free(localip);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
int PlayAnswer(char *cseq, int sock,int SessionId,char* urlPre,char* recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
char*localip;
localip = GetLocalIP(sock);
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sRange: npt=0.000-\r\nSession: %d\r\nRTP-Info: url=rtsp://%s/%s;seq=0\r\n\r\n",
cseq,dateHeader(),SessionId,localip,urlPre);
free(localip);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
udpfd = socket(AF_INET,SOCK_DGRAM,0);//UDP
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(g_rtspClients[0].rtpport[0]);
server.sin_addr.s_addr=inet_addr(g_rtspClients[0].IP);
connect(udpfd,(struct sockaddr *)&server,sizeof(server));
printf("udp up\n");
}
return TRUE;
}
return FALSE;
}
int PauseAnswer(char *cseq,int sock,char *recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n\r\n",
cseq,dateHeader());
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
int TeardownAnswer(char *cseq,int sock,int SessionId,char *recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",
cseq,dateHeader(),SessionId);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
close(udpfd);
}
return TRUE;
}
return FALSE;
}
void * RtspClientMsg(void*pParam)
{
pthread_detach(pthread_self());
int nRes;
char pRecvBuf[RTSP_RECV_SIZE];
RTSP_CLIENT * pClient = (RTSP_CLIENT*)pParam;
memset(pRecvBuf,0,sizeof(pRecvBuf));
printf("RTSP:-----Create Client %s\n",pClient->IP);
while(pClient->status != RTSP_IDLE)
{
nRes = recv(pClient->socket, pRecvBuf, RTSP_RECV_SIZE,0);
//printf("-------------------%d\n",nRes);
if(nRes < 1)
{
//usleep(1000);
printf("RTSP:Recv Error--- %d\n",nRes);
g_rtspClients[pClient->index].status = RTSP_IDLE;
g_rtspClients[pClient->index].seqnum = 0;
g_rtspClients[pClient->index].tsvid = 0;
g_rtspClients[pClient->index].tsaud = 0;
close(pClient->socket);
break;
}
char cmdName[PARAM_STRING_MAX];
char urlPreSuffix[PARAM_STRING_MAX];
char urlSuffix[PARAM_STRING_MAX];
char cseq[PARAM_STRING_MAX];
ParseRequestString(pRecvBuf,nRes,cmdName,sizeof(cmdName),urlPreSuffix,sizeof(urlPreSuffix),
urlSuffix,sizeof(urlSuffix),cseq,sizeof(cseq));
char *p = pRecvBuf;
printf("<<<<<%s\n",p);
//printf("\--------------------------\n");
//printf("%s %s\n",urlPreSuffix,urlSuffix);
if(strstr(cmdName, "OPTIONS"))
{
OptionAnswer(cseq,pClient->socket);
}
else if(strstr(cmdName, "DESCRIBE"))
{
DescribeAnswer(cseq,pClient->socket,urlSuffix,p);
//printf("-----------------------------DescribeAnswer %s %s\n",
// urlPreSuffix,urlSuffix);
}
else if(strstr(cmdName, "SETUP"))
{
int rtpport,rtcpport;
int trackID=0;
SetupAnswer(cseq,pClient->socket,pClient->sessionid,urlPreSuffix,p,&rtpport,&rtcpport);
sscanf(urlSuffix, "trackID=%u", &trackID);
//printf("----------------------------------------------TrackId %d\n",trackID);
if(trackID<0 || trackID>=2)trackID=0;
g_rtspClients[pClient->index].rtpport[trackID] = rtpport;
g_rtspClients[pClient->index].rtcpport= rtcpport;
g_rtspClients[pClient->index].reqchn = atoi(urlPreSuffix);
if(strlen(urlPreSuffix)<100)
strcpy(g_rtspClients[pClient->index].urlPre,urlPreSuffix);
//printf("-----------------------------SetupAnswer %s-%d-%d\n",
// urlPreSuffix,g_rtspClients[pClient->index].reqchn,rtpport);
}
else if(strstr(cmdName, "PLAY"))
{
PlayAnswer(cseq,pClient->socket,pClient->sessionid,g_rtspClients[pClient->index].urlPre,p);
g_rtspClients[pClient->index].status = RTSP_SENDING;
printf("Start Play\n",pClient->index);
//printf("-----------------------------PlayAnswer %d %d\n",pClient->index);
//usleep(100);
}
else if(strstr(cmdName, "PAUSE"))
{
PauseAnswer(cseq,pClient->socket,p);
}
else if(strstr(cmdName, "TEARDOWN"))
{
TeardownAnswer(cseq,pClient->socket,pClient->sessionid,p);
g_rtspClients[pClient->index].status = RTSP_IDLE;
g_rtspClients[pClient->index].seqnum = 0;
g_rtspClients[pClient->index].tsvid = 0;
g_rtspClients[pClient->index].tsaud = 0;
close(pClient->socket);
}
//if(exitok){ exitok++;return NULL; }
}
printf("RTSP:-----Exit Client %s\n",pClient->IP);
return NULL;
}
void * RtspServerListen(void*pParam)
{
int s32Socket;
struct sockaddr_in servaddr;
int s32CSocket;
int s32Rtn;
int s32Socket_opt_value = 1;
int nAddrLen;
struct sockaddr_in addrAccept;
int bResult;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(RTSP_SERVER_PORT);
s32Socket = socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(s32Socket ,SOL_SOCKET,SO_REUSEADDR,&s32Socket_opt_value,sizeof(int)) == -1)
{
return (void *)(-1);
}
s32Rtn = bind(s32Socket, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
if(s32Rtn < 0)
{
return (void *)(-2);
}
s32Rtn = listen(s32Socket, 50);
if(s32Rtn < 0)
{
return (void *)(-2);
}
nAddrLen = sizeof(struct sockaddr_in);
int nSessionId = 1000;
while ((s32CSocket = accept(s32Socket, (struct sockaddr*)&addrAccept, &nAddrLen)) >= 0)
{
printf("<<<<RTSP Client %s Connected...\n", inet_ntoa(addrAccept.sin_addr));
int nMaxBuf = 10 * 1024; // 脧碌脥鲁艙芦禄谩路脰脜盲 2 x nMaxBuf 碌脛禄潞鲁氓沤贸脨隆
if(setsockopt(s32CSocket, SOL_SOCKET, SO_SNDBUF, (char*)&nMaxBuf, sizeof(nMaxBuf)) == -1)
printf("RTSP:!!!!!! Enalarge socket sending buffer error !!!!!!\n");
int i;
int bAdd=FALSE;
for(i=0;i<MAX_RTSP_CLIENT;i++)
{
if(g_rtspClients[i].status == RTSP_IDLE)
{
memset(&g_rtspClients[i],0,sizeof(RTSP_CLIENT));
g_rtspClients[i].index = i;
g_rtspClients[i].socket = s32CSocket;
g_rtspClients[i].status = RTSP_CONNECTED ;//RTSP_SENDING;
g_rtspClients[i].sessionid = nSessionId++;
strcpy(g_rtspClients[i].IP,inet_ntoa(addrAccept.sin_addr));
pthread_t threadIdlsn = 0;
struct sched_param sched;
sched.sched_priority = 1;
//to return ACKecho
pthread_create(&threadIdlsn, NULL, RtspClientMsg, &g_rtspClients[i]);
//pthread_setschedparam(threadIdlsn,SCHED_RR,&sched);
bAdd = TRUE;
break;
}
}
if(bAdd==FALSE)
{
memset(&g_rtspClients[0],0,sizeof(RTSP_CLIENT));
g_rtspClients[0].index = 0;
g_rtspClients[0].socket = s32CSocket;
g_rtspClients[0].status = RTSP_CONNECTED ;//RTSP_SENDING;
g_rtspClients[0].sessionid = nSessionId++;
strcpy(g_rtspClients[0].IP,inet_ntoa(addrAccept.sin_addr));
pthread_t threadIdlsn = 0;
struct sched_param sched;
sched.sched_priority = 1;
//to return ACKecho
pthread_create(&threadIdlsn, NULL, RtspClientMsg, &g_rtspClients[0]);
//pthread_setschedparam(threadIdlsn,SCHED_RR,&sched);
bAdd = TRUE;
}
//if(exitok){ exitok++;return NULL; }
}
if(s32CSocket < 0)
{
// HI_OUT_Printf(0, "RTSP listening on port %d,accept err, %d\n", RTSP_SERVER_PORT, s32CSocket);
}
printf("----- INIT_RTSP_Listen() Exit !! \n");
return NULL;
}
HI_S32 VENC_Sent(char *buffer,int buflen)
{
HI_S32 i;
int is=0;
int nChanNum=0;
for(is=0;is<MAX_RTSP_CLIENT;is++)
{
if(g_rtspClients[is].status!=RTSP_SENDING)
{
continue;
}
int heart = g_rtspClients[is].seqnum % 10000;
char* nalu_payload;
int nAvFrmLen = 0;
int nIsIFrm = 0;
int nNaluType = 0;
char sendbuf[500*1024+32];
nAvFrmLen = buflen;
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(g_rtspClients[is].rtpport[0]);
server.sin_addr.s_addr=inet_addr(g_rtspClients[is].IP);
int bytes=0;
unsigned int timestamp_increse=0;
timestamp_increse=(unsigned int)(90000.0 / 25);
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
rtp_hdr->payload = RTP_H264;
rtp_hdr->version = 2;
rtp_hdr->marker = 0;
rtp_hdr->ssrc = htonl(10);
if(nAvFrmLen<=nalu_sent_len)
{
rtp_hdr->marker=1;
rtp_hdr->seq_no = htons(g_rtspClients[is].seqnum++);
nalu_hdr =(NALU_HEADER*)&sendbuf[12];
nalu_hdr->F=0;
nalu_hdr->NRI= nIsIFrm;
nalu_hdr->TYPE= nNaluType;
nalu_payload=&sendbuf[13];
memcpy(nalu_payload,buffer,nAvFrmLen);
g_rtspClients[is].tsvid = g_rtspClients[is].tsvid+timestamp_increse;
rtp_hdr->timestamp=htonl(g_rtspClients[is].tsvid);
bytes=nAvFrmLen+ 13 ;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
}
else if(nAvFrmLen>nalu_sent_len)
{
int k=0,l=0;
k=nAvFrmLen/nalu_sent_len;
l=nAvFrmLen%nalu_sent_len;
int t=0;
g_rtspClients[is].tsvid = g_rtspClients[is].tsvid+timestamp_increse;
rtp_hdr->timestamp=htonl(g_rtspClients[is].tsvid);
while(t<=k)
{
rtp_hdr->seq_no = htons(g_rtspClients[is].seqnum++);
if(t==0)
{
rtp_hdr->marker=0;
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F= 0;
fu_ind->NRI= nIsIFrm;
fu_ind->TYPE=28;
fu_hdr =(FU_HEADER*)&sendbuf[13];
fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=1;
fu_hdr->TYPE=nNaluType;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer,nalu_sent_len);
bytes=nalu_sent_len+14;
sendto( udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
t++;
}
else if(k==t)
{
rtp_hdr->marker=1;
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F= 0 ;
fu_ind->NRI= nIsIFrm ;
fu_ind->TYPE=28;
fu_hdr =(FU_HEADER*)&sendbuf[13];
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->TYPE= nNaluType;
fu_hdr->E=1;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer+t*nalu_sent_len,l);
bytes=l+14;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
t++;
}
else if(t<k && t!=0)
{
rtp_hdr->marker=0;
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F=0;
fu_ind->NRI=nIsIFrm;
fu_ind->TYPE=28;
fu_hdr =(FU_HEADER*)&sendbuf[13];
//fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->E=0;
fu_hdr->TYPE=nNaluType;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer+t*nalu_sent_len,nalu_sent_len);
bytes=nalu_sent_len+14;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
t++;
}
}
}
}
//------------------------------------------------------------
}
/******************************************************************************
* funciton : sent H264 stream
******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream)
{
HI_S32 i,flag=0;
for(i=0;i<MAX_RTSP_CLIENT;i++)//have atleast a connect
{
if(g_rtspClients[i].status == RTSP_SENDING)
{
flag = 1;
break;
}
}
if(flag)
{
for (i = 0; i < pstStream->u32PackCount; i++)
{
HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
char sendbuf[320*1024];
//char tmp[640*1024];
lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
//printf("lens = %d, count= %d\n",lens,count++);
VENC_Sent(sendbuf,lens);
lens = 0;
}
}
return HI_SUCCESS;
}
HI_S32 saveStream(VENC_STREAM_S *pstStream)
{
HI_S32 i,j,lens=0;
for(j=0;j<MAX_RTSP_CLIENT;j++)//have atleast a connect
{
if(g_rtspClients[j].status == RTSP_SENDING)
{
for (i = 0; i < pstStream->u32PackCount; i++)
{
RTPbuf_s *p = (RTPbuf_s *)malloc(sizeof(RTPbuf_s));
INIT_LIST_HEAD(&(p->list));
lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
p->buf = (char *)malloc(lens);
p->len = lens;
memcpy(p->buf,pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
list_add_tail(&(p->list),&RTPbuf_head);
count++;
//printf("count = %d\n",count);
}
}
}
return HI_SUCCESS;
}
void RtspServer_init(void)
{
int i;
pthread_t threadId = 0;
memset(&g_rtp_playload,0,sizeof(g_rtp_playload));
strcpy(&g_rtp_playload,"G726-32");
g_audio_rate = 8000;
pthread_mutex_init(&g_sendmutex,NULL);
pthread_mutex_init(&g_mutex,NULL);
pthread_cond_init(&g_cond,NULL);
memset(&g_rtspClients,0,sizeof(RTSP_CLIENT)*MAX_RTSP_CLIENT);
//pthread_create(&g_SendDataThreadId, NULL, SendDataThread, NULL);
struct sched_param thdsched;
thdsched.sched_priority = 2;
//to listen visiting
pthread_create(&threadId, NULL, RtspServerListen, NULL);
//pthread_setschedparam(threadId,SCHED_RR,&thdsched);
printf("RTSP:-----Init Rtsp server\n");
pthread_create(&gs_RtpPid, 0, vdRTPSendThread, NULL);
//exitok++;
}
void RtspServer_exit(void)
{
return;
}
HI_VOID* vdRTPSendThread(HI_VOID *p)
{
while(1)
{
if(!list_empty(&RTPbuf_head))
{
RTPbuf_s *p = get_first_item(&RTPbuf_head,RTPbuf_s,list);
VENC_Sent(p->buf,p->len);
list_del(&(p->list));
free(p->buf);
free(p);
p = NULL;
count--;
//printf("count = %d\n",count);
}
usleep(5000);
}
}
#endif
main 函数里这么添加。
11 #if RTSP_ENABLE
10 RtspServer_init();
9 #endif
8
7 ret = sample_venc_choose_mode(index);
6 if (ret == TD_SUCCESS) {
5 printf("program exit normally!\n");
4 } else {
3 printf("program exit abnormally!\n");
2 }
1
添加需要的库。
17
1 #define RTSP_ENABLE 1
2
3
4 #if RTSP_ENABLE
5
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <netdb.h>
12 #include <sys/socket.h>
13
14 #include <sys/ioctl.h>
15 #include <fcntl.h>
16 #include <pthread.h>
17 #include <sys/ipc.h>
18 #include <sys/msg.h>
19 #include <netinet/if_ether.h>
20 #include <net/if.h>
21
22 #include <linux/if_ether.h>
23 #include <linux/sockios.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 #endif
28
然后是 sample_comm_venc.c 文件。
在最开头 添加。
14 #define RTSP_ENABLE 1
2865 static td_void sample_comm_fd_isset(sample_comm_venc_stream_proc_info *stream_proc_info, fd_set *read_fds,
1 ot_venc_stream_buf_info *stream_buf_info, ot_payload_type *payload_type, sample_venc_getstream_para *para)
2 {
3 td_s32 i, ret;
4
5 // for (i = 0; (i < stream_proc_info->chn_total) && (i < OT_VENC_MAX_CHN_NUM); i++) {
6 //
7 //topeet wang added
8 for (i = 1; (i < stream_proc_info->chn_total) && (i < OT_VENC_MAX_CHN_NUM); i++) {
9 if (FD_ISSET(stream_proc_info->venc_fd[i], read_fds)) {
10 stream_proc_info->venc_chn = para->venc_chn[i];
11 ret = sample_comm_get_stream_from_one_channl(stream_proc_info, i, stream_buf_info, payload_type);
12 if (ret == SAMPLE_RETURN_CONTINUE) {
13 continue;
14 } else if (ret == SAMPLE_RETURN_BREAK) {
15 break;
16 }
17 }
18 }
19 }
然后是 sample_comm_save_frame_to_file 函数。
3 #ifndef __LITEOS__
4 ot_unused(stream_buf_info);
5
6
7
8 #if RTSP_ENABLE
9 SAMPLE_COMM_VENC_Sentjin(&stStream);
10 #else
11 ret = sample_comm_venc_save_stream(stream_proc_info->file[index], stream);
12 #endif
13
接下来编译一遍看看。
出现报错
.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c: In function 'sample_comm_save_frame_to_file':
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c:2777:5: warning: implicit declaration of function 'SAMPLE_COMM_VENC_Sentjin' [-Wimplicit-function-declaration]
2777 | SAMPLE_COMM_VENC_Sentjin(&stStream);
| ^~~~~~~~~~~~~~~~~~~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c:2777:31: error: 'stStream' undeclared (first use in this function); did you mean 'stream'?
2777 | SAMPLE_COMM_VENC_Sentjin(&stStream);
| ^~~~~~~~
| stream
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.c:2777:31: note: each undeclared identifier is reported only once for each function it appears in
make: *** [<builtin>: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common/sample_comm_venc.o] Error 1
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
将函数 SAMPLE_COMM_VENC_Sentjin(&stStream) 改为 SAMPLE_COMM_VENC_Sentjin(&stream)
依然有报错。
/include -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/out/include/exp_inc -DVER_X=1 -DVER_Y=0 -DVER_Z=0 -DVER_P=0 -DVER_B=10 -DUSER_BIT_32 -DKERNEL_BIT_32 -DOT
_RELEASE -Wno-date-time -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT -DBOARD_TYPE=DMEB_QFN -DOT_ACODEC_TYPE_INNER -DOT_VQE_USE_STATIC_MODULE_REGI
STER -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc/../common -I/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/
venc/../audio/adp -c -o sample_venc.o sample_venc.c
sample_venc.c:79:1: error: unknown type name 'RTP_FIXED_HEADER'
79 | RTP_FIXED_HEADER *rtp_hdr;
| ^~~~~~~~~~~~~~~~
sample_venc.c:81:1: error: unknown type name 'NALU_HEADER'
81 | NALU_HEADER *nalu_hdr;
| ^~~~~~~~~~~
sample_venc.c:82:1: error: unknown type name 'FU_INDICATOR'
82 | FU_INDICATOR *fu_ind;
| ^~~~~~~~~~~~
sample_venc.c:83:1: error: unknown type name 'FU_HEADER'
83 | FU_HEADER *fu_hdr;
| ^~~~~~~~~
sample_venc.c:86:1: error: unknown type name 'RTSP_CLIENT'
86 | RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
| ^~~~~~~~~~~
sample_venc.c:86:27: error: 'MAX_RTSP_CLIENT' undeclared here (not in a function)
86 | RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
| ^~~~~~~~~~~~~~~
sample_venc.c:107:8: error: variable 'RTPbuf_head' has initializer but incomplete type
107 | struct list_head RTPbuf_head = LIST_HEAD_INIT(RTPbuf_head);
| ^~~~~~~~~
sample_venc.c:107:32: warning: implicit declaration of function 'LIST_HEAD_INIT' [-Wimplicit-function-declaration]
107 | struct list_head RTPbuf_head = LIST_HEAD_INIT(RTPbuf_head);
| ^~~~~~~~~~~~~~
sample_venc.c:107:47: error: 'RTPbuf_head' has an incomplete type 'struct list_head'
解决:
原来 在 sample_comm.h 中 还有 需要改动的内容。
添加这些内容。
#if RTSP_ENABLE
#include "list.h"
#if !defined(WIN32)
#define __PACKED__ __attribute__ ((__packed__))
#else
#define __PACKED__
#endif
typedef enum
{
RTSP_VIDEO=0,
RTSP_VIDEOSUB=1,
RTSP_AUDIO=2,
RTSP_YUV422=3,
RTSP_RGB=4,
RTSP_VIDEOPS=5,
RTSP_VIDEOSUBPS=6
}enRTSP_MonBlockType;
struct _RTP_FIXED_HEADER
{
/**//* byte 0 */
unsigned char csrc_len:4; /**//* expect 0 */
unsigned char extension:1; /**//* expect 1, see RTP_OP below */
unsigned char padding:1; /**//* expect 0 */
unsigned char version:2; /**//* expect 2 */
/**//* byte 1 */
unsigned char payload:7; /**//* RTP_PAYLOAD_RTSP */
unsigned char marker:1; /**//* expect 1 */
/**//* bytes 2, 3 */
unsigned short seq_no;
/**//* bytes 4-7 */
unsigned long timestamp;
/**//* bytes 8-11 */
unsigned long ssrc; /**//* stream number is used here. */
} __PACKED__;
typedef struct _RTP_FIXED_HEADER RTP_FIXED_HEADER;
struct _NALU_HEADER
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
}__PACKED__; /**//* 1 BYTES */
typedef struct _NALU_HEADER NALU_HEADER;
struct _FU_INDICATOR
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
}__PACKED__; /**//* 1 BYTES */
typedef struct _FU_INDICATOR FU_INDICATOR;
struct _FU_HEADER
{
//byte 0
unsigned char TYPE:5;
unsigned char R:1;
unsigned char E:1;
unsigned char S:1;
} __PACKED__; /**//* 1 BYTES */
typedef struct _FU_HEADER FU_HEADER;
struct _AU_HEADER
{
//byte 0, 1
unsigned short au_len;
//byte 2,3
unsigned short frm_len:13;
unsigned char au_index:3;
} __PACKED__; /**//* 1 BYTES */
typedef struct _AU_HEADER AU_HEADER;
extern void RtspServer_init(void);
extern void RtspServer_exit(void);
int AddFrameToRtspBuf(int nChanNum,enRTSP_MonBlockType eType, char * pData, unsigned int nSize, unsigned int nVidFrmNum,int bIFrm);
extern HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream);
extern HI_S32 saveStream(VENC_STREAM_S *pstStream);
extern HI_VOID* vdRTPSendThread(HI_VOID *p);
#define nalu_sent_len 1400
//#define nalu_sent_len 1400
#define RTP_H264 96
#define RTP_AUDIO 97
#define MAX_RTSP_CLIENT 1
#define RTSP_SERVER_PORT 554
#define RTSP_RECV_SIZE 1024
#define RTSP_MAX_VID (640*1024)
#define RTSP_MAX_AUD (15*1024)
#define AU_HEADER_SIZE 4
#define PARAM_STRING_MAX 100
typedef unsigned short u_int16_t;
typedef unsigned char u_int8_t;
typedef u_int16_t portNumBits;
typedef u_int32_t netAddressBits;
typedef long long _int64;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define AUDIO_RATE 8000
#define PACKET_BUFFER_END (unsigned int)0x00000000
typedef struct
{
int startblock;//浠h〃寮€濮嬫枃浠跺潡鍙?
int endblock;//浠h〃缁撴潫鏂囦欢鍧楀彿
int BlockFileNum;//浠h〃褰曞儚娈垫暟
}IDXFILEHEAD_INFO;//.IDX鏂囦欢鐨勫ご淇℃伅
typedef struct
{
_int64 starttime;//浠h〃寮€濮媠hijian
_int64 endtime;//浠h〃缁撴潫shijian
int startblock;//浠h〃寮€濮嬫枃浠跺潡鍙?
int endblock;//浠h〃缁撴潫鏂囦欢鍧楀彿
int stampnum;//浠h〃鏃堕棿鎴虫暟閲?
}IDXFILEBLOCK_INFO;//.IDX鏂囦欢娈典俊鎭?
typedef struct
{
int blockindex;//浠h〃鎵€鍦ㄦ枃浠跺潡鍙?
int pos;//浠h〃璇ユ椂闂存埑鍦ㄦ枃浠跺潡鐨勪綅缃?
_int64 time;//浠h〃鏃堕棿鎴虫椂闂存埑鐨勬椂闂寸偣
}IDXSTAMP_INFO;//.IDX鏂囦欢鐨勬椂闂存埑淇℃伅
typedef struct
{
char filename[150];//浠h〃鎵€鍦ㄦ枃浠跺潡鍙?
int pos;//浠h〃璇ユ椂闂存埑鍦ㄦ枃浠跺潡鐨勪綅缃?
_int64 time;//浠h〃鏃堕棿鎴虫椂闂存埑鐨勬椂闂寸偣
}FILESTAMP_INFO;//.IDX鏂囦欢鐨勬椂闂存埑淇℃伅
typedef struct
{
char channelid[9];
_int64 starttime;//浠h〃寮€濮媠hijian
_int64 endtime;//浠h〃缁撴潫shijian
_int64 session;
int type; //绫诲瀷
int encodetype;//缂栫爜鏍煎紡;
}FIND_INFO;//.IDX鏂囦欢鐨勬椂闂存埑淇℃伅
typedef enum
{
RTP_UDP,
RTP_TCP,
RAW_UDP
}StreamingMode;
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
AU_HEADER *au_hdr;
extern char g_rtp_playload[20];//脛卢脠脧G726-32
extern int g_audio_rate;//脛卢脠脧8000
typedef enum
{
RTSP_IDLE = 0,
RTSP_CONNECTED = 1,
RTSP_SENDING = 2,
}RTSP_STATUS;
typedef struct
{
int nVidLen;
int nAudLen;
int bIsIFrm;
int bWaitIFrm;
int bIsFree;
char vidBuf[RTSP_MAX_VID];
char audBuf[RTSP_MAX_AUD];
}RTSP_PACK;
typedef struct
{
int index;
int socket;
int reqchn;
int seqnum;
int seqnum2;
unsigned int tsvid;
unsigned int tsaud;
int status;
int sessionid;
int rtpport[2];
int rtcpport;
char IP[20];
char urlPre[PARAM_STRING_MAX];
}RTSP_CLIENT;
typedef struct
{
int vidLen;
int audLen;
int nFrameID;
char vidBuf[RTSP_MAX_VID];
char audBuf[RTSP_MAX_AUD];
}FRAME_PACK;
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;
extern int udpfd;
extern RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
typedef struct _rtpbuf
{
struct list_head list;
HI_S32 len;
char * buf;
}RTPbuf_s;
extern struct list_head RTPbuf_head;
#endif
依然后报错。
rt_demo region scene_auto security_subsys smart_ae svc_venc svp uvc_app venc vgs vie cccccccc
make[1]: Entering directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common'
~~~~~~~~~~Start build audio~~~~~~~~~~
make[1]: Entering directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/audio'
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/audio/../common/sample_comm_venc.o: in function `sample_comm_venc_get_venc_stream_proc':
sample_comm_venc.c:(.text.sample_comm_venc_get_venc_stream_proc+0x59a): undefined reference to `SAMPLE_COMM_VENC_Sentjin'
collect2: error: ld returned 1 exit status
make[1]: *** [/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/audio/../smp_linux.mak:14: sample_audio] Error 1
make[1]: Leaving directory '/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/audio'
make: *** [Makefile:31: audio] Error 2
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample#
解决: 我需要重新编译一下 sample_comm_venc.c
但是依然有报错。
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common# make clean
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common# make
In file included from /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_sys.c:5:
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:143:8: error: unknown type name 'HI_S32'
143 | extern HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream);
| ^~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:143:40: error: unknown type name 'VENC_STREAM_S'
143 | extern HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream);
| ^~~~~~~~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:144:8: error: unknown type name 'HI_S32'
144 | extern HI_S32 saveStream(VENC_STREAM_S *pstStream);
| ^~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:144:26: error: unknown type name 'VENC_STREAM_S'
144 | extern HI_S32 saveStream(VENC_STREAM_S *pstStream);
| ^~~~~~~~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:145:8: error: unknown type name 'HI_VOID'
145 | extern HI_VOID* vdRTPSendThread(HI_VOID *p);
| ^~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:145:33: error: unknown type name 'HI_VOID'
145 | extern HI_VOID* vdRTPSendThread(HI_VOID *p);
| ^~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:167:9: error: unknown type name 'u_int32_t'
167 | typedef u_int32_t netAddressBits;
| ^~~~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:297:2: error: unknown type name 'HI_S32'
297 | HI_S32 len;
| ^~~~~~
make: *** [Makefile:14: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_sys.o] Error 1
这个报错 就是 改类型。
我是这么改的。
改的是 sample_comm.h
12 #define HI_VOID void
11 typedef int HI_S32;
10 typedef unsigned int u_int32_t;
9
5 //extern HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream);
6 //extern HI_S32 saveStream(VENC_STREAM_S *pstStream);
7 //
8 extern HI_S32 SAMPLE_COMM_VENC_Sentjin(ot_venc_stream *pstStream);
9 extern HI_S32 saveStream(ot_venc_stream *pstStream);
10
11 extern HI_VOID* vdRTPSendThread(HI_VOID *p);
编译通过。
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common# make clean
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common# make
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c: In function 'sample_comm_save_frame_to_file':
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c:2777:30: warning: passing argument 1 of 'SAMPLE_COMM_VENC_Sentjin' from incompatible pointer type [-Wincompatible-pointer-types]
2777 | SAMPLE_COMM_VENC_Sentjin(&stream);
| ^~~~~~~
| |
| ot_venc_stream **
In file included from /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c:23:
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm.h:147:56: note: expected 'ot_venc_stream *' but argument is of type 'ot_venc_stream **'
147 | extern HI_S32 SAMPLE_COMM_VENC_Sentjin(ot_venc_stream *pstStream);
| ~~~~~~~~~~~~~~~~^~~~~~~~~
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c: In function 'sample_comm_venc_get_venc_stream_proc':
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c:2787:8: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
2787 | if (ret != TD_SUCCESS) {
| ^
/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common/../common/sample_comm_venc.c:2744:12: note: 'ret' was declared here
2744 | td_s32 ret, fd;
| ^~~
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/common#
然后去编译 sample_venc.c 文件。
依然是有报错。
sample_venc.c:773:12: warning: unused variable 'i' [-Wunused-variable]
773 | HI_S32 i;
| ^
sample_venc.c: At top level:
sample_venc.c:910:33: error: unknown type name 'VENC_STREAM_S'
910 | HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream)
| ^~~~~~~~~~~~~
sample_venc.c:941:19: error: unknown type name 'VENC_STREAM_S'
941 | HI_S32 saveStream(VENC_STREAM_S *pstStream)
| ^~~~~~~~~~~~~
sample_venc.c: In function 'RtspServer_init':
sample_venc.c:976:9: warning: passing argument 1 of 'strcpy' from incompatible pointer type [-Wincompatible-pointer-types]
976 | strcpy(&g_rtp_playload,"G726-32");
| ^~~~~~~~~~~~~~~
| |
| char (*)[20]
In file included from sample_venc.c:7:
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/target/usr/include/string.h:33:15: note: expected 'char * restrict' but argument is of type 'char (*)[20]'
33 | char *strcpy (char *__restrict, const char *__restrict);
| ^
sample_venc.c:985:21: warning: variable 'thdsched' set but not used [-Wunused-but-set-variable]
985 | struct sched_param thdsched;
解决: 在这个文件中 依然去改 这个函数。
改的 是 sample_venc.c
36 /******************************************************************************
35 * funciton : sent H264 stream
34 ******************************************************************************/
33
32 HI_S32 SAMPLE_COMM_VENC_Sentjin(ot_venc_stream *pstStream)
31 {
30 HI_S32 i,flag=0;
29
28 for(i=0;i<MAX_RTSP_CLIENT;i++)//have atleast a connect
27 {
26 if(g_rtspClients[i].status == RTSP_SENDING)
25 {
24 flag = 1;
23 break;
22 }
21 }
20 if(flag)
19 {
18 for (i = 0; i < pstStream->u32PackCount; i++)
17 {
16 HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
15 char sendbuf[320*1024];
14 //char tmp[640*1024];
13 lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
12 memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
11 //printf("lens = %d, count= %d\n",lens,count++);
10 VENC_Sent(sendbuf,lens);
9 lens = 0;
8 }
7
6
5 }
4 return HI_SUCCESS;
3 }
2
1 HI_S32 saveStream(ot_venc_stream *pstStream)
942 {
1 HI_S32 i,j,lens=0;
2
3 for(j=0;j<MAX_RTSP_CLIENT;j++)//have atleast a connect
4 {
5 if(g_rtspClients[j].status == RTSP_SENDING)
6 {
7 for (i = 0; i < pstStream->u32PackCount; i++)
8 {
重新编译之后 依然是 有错误。
sample_venc.c:773:12: warning: unused variable 'i' [-Wunused-variable]
773 | HI_S32 i;
| ^
sample_venc.c: In function 'SAMPLE_COMM_VENC_Sentjin':
sample_venc.c:924:31: error: 'ot_venc_stream' has no member named 'u32PackCount'
924 | for (i = 0; i < pstStream->u32PackCount; i++)
| ^~
sample_venc.c:929:21: error: 'ot_venc_stream' has no member named 'pstPack'; did you mean 'pack'?
929 | lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
| ^~~~~~~
| pack
sample_venc.c:929:50: error: 'ot_venc_stream' has no member named 'pstPack'; did you mean 'pack'?
929 | lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
| ^~~~~~~
| pack
sample_venc.c:930:33: error: 'ot_venc_stream' has no member named 'pstPack'; did you mean 'pack'?
930 | memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
| ^~~~~~~
| pack
sample_venc.c:930:63: error: 'ot_venc_stream' has no member named 'pstPack'; did you mean 'pack'?
930 | memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
| ^~~~~~~
| pack
sample_venc.c:926:38: warning: unused variable 'showflap' [-Wunused-variable]
926 | HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
| ^~~~~~~~
sample_venc.c:926:29: warning: unused variable 'newadd' [-Wunused-variable]
926 | HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
| ^~~~~~
sample_venc.c:926:19: warning: unused variable 'lastadd' [-Wunused-variable]
926 | HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
| ^~~~~~~
sample_venc.c:926:17: warning: unused variable 'j' [-Wunused-variable]
926 | HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
| ^
sample_venc.c:938:12: error: 'HI_SUCCESS' undeclared (first use in this function); did you mean 'TD_SUCCESS'?
938 | return HI_SUCCESS;
| ^~~~~~~~~~
这个错误 也好改,依然是 结构体的问题。
解决:
解释照着 ortp 去改。
改动文件, sample_venc.c
改动如下:
4 /******************************************************************************
3 * funciton : sent H264 stream
2 ******************************************************************************/
1
910 HI_S32 SAMPLE_COMM_VENC_Sentjin(ot_venc_stream *pstStream)
1 {
2 HI_S32 i,flag=0;
3
4 for(i=0;i<MAX_RTSP_CLIENT;i++)//have atleast a connect
5 {
6 if(g_rtspClients[i].status == RTSP_SENDING)
7 {
8 flag = 1;
9 break;
10 }
11 }
12 if(flag)
13 {
14 // for (i = 0; i < pstStream->u32PackCount; i++)
15 for (i = 0; i < pstStream->pack_cnt; i++)
16 {
17 HI_S32 lens=0,j,lastadd=0,newadd=0,showflap=0;
18 char sendbuf[320*1024];
19 //char tmp[640*1024];
20 // lens = pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
21 // memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,lens);
22 lens = pstStream->pack[i].len-pstStream->pack[i].offset;
23 memcpy(&sendbuf[0],pstStream->pack[i].addr+pstStream->pack[i].offset,lens);
24 //printf("lens = %d, count= %d\n",lens,count++);
25 VENC_Sent(sendbuf,lens);
26 lens = 0;
27 }
28
29
30 }
31 return TD_SUCCESS;
32 }
4 HI_S32 saveStream(ot_venc_stream *pstStream)
5 {
6 HI_S32 i,j,lens=0;
7
8 for(j=0;j<MAX_RTSP_CLIENT;j++)//have atleast a connect
9 {
10 if(g_rtspClients[j].status == RTSP_SENDING)
11 {
12 // for (i = 0; i < pstStream->u32PackCount; i++)
13 for (i = 0; i < pstStream->pack_cnt; i++)
14 {
15 RTPbuf_s *p = (RTPbuf_s *)malloc(sizeof(RTPbuf_s));
16 INIT_LIST_HEAD(&(p->list));
17
18 lens = pstStream->pack[i].len-pstStream->pack[i].offset;
19 p->buf = (char *)malloc(lens);
20 p->len = lens;
21 memcpy(p->buf,pstStream->pack[i].addr+pstStream->pack[i].offset,lens);
22
23 list_add_tail(&(p->list),&RTPbuf_head);
24 count++;
25 //printf("count = %d\n",count);
26 }
27 }
28 }
29
30 return TD_SUCCESS;
31 }
32
重新编译 但是依然是报错。
sample_venc.c:140:18: warning: 'gs_RtpPid' defined but not used [-Wunused-variable]
140 | static pthread_t gs_RtpPid;
| ^~~~~~~~~
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_isp.o:(.bss.au_hdr+0x0): multiple definition of `au_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sam
ple/venc/../common/sample_comm_sys.o:(.bss.au_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_isp.o:(.bss.fu_hdr+0x0): multiple definition of `fu_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sam
ple/venc/../common/sample_comm_sys.o:(.bss.fu_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_isp.o:(.bss.fu_ind+0x0): multiple definition of `fu_ind'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sam
ple/venc/../common/sample_comm_sys.o:(.bss.fu_ind+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_isp.o:(.bss.nalu_hdr+0x0): multiple definition of `nalu_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp
/sample/venc/../common/sample_comm_sys.o:(.bss.nalu_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_isp.o:(.bss.rtp_hdr+0x0): multiple definition of `rtp_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/s
ample/venc/../common/sample_comm_sys.o:(.bss.rtp_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_vi.o:(.bss.au_hdr+0x0): multiple definition of `au_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/samp
le/venc/../common/sample_comm_sys.o:(.bss.au_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musleabi/bin/ld: /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_
linux/source/mpp/sample/venc/../common/sample_comm_vi.o:(.bss.fu_hdr+0x0): multiple definition of `fu_hdr'; /home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/samp
le/venc/../common/sample_comm_sys.o:(.bss.fu_hdr+0x0): first defined here
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/bin/../lib/gcc/arm-linux-musleabi/10.3.0/../../../../arm-linux-musl
解决:
最终在 sample_comm.h 中 注释掉定义。
18 typedef enum
17 {
16 RTP_UDP,
15 RTP_TCP,
14 RAW_UDP
13 }StreamingMode;
12
11
10 // RTP_FIXED_HEADER *rtp_hdr;
9 // NALU_HEADER *nalu_hdr;
8 // FU_INDICATOR *fu_ind;
7 // FU_HEADER *fu_hdr;
6 // AU_HEADER *au_hdr;
5
4
3 extern char g_rtp_playload[20];//脛卢脠脧G726-32
2 extern int g_audio_rate;//脛卢脠脧8000
1
244 typedef enum
1 {
2 RTSP_IDLE = 0,
3 RTSP_CONNECTED = 1,
4 RTSP_SENDING = 2,
然后在 sample_venc.c 中 ,加上 static .
11
10 #if RTSP_ENABLE
9
8 static RTP_FIXED_HEADER *rtp_hdr;
7 static NALU_HEADER *nalu_hdr;
6 static FU_INDICATOR *fu_ind;
5 static FU_HEADER *fu_hdr;
4
3
2 RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
1
118 int g_nSendDataChn = -1;
E 1 pthread_mutex_t g_mutex; ■ Unknown type name 'pthread_mutex_t'
E 2 pthread_cond_t g_cond; ■ Unknown type name 'pthread_cond_t'; did you mean 'thread_contrl'? (fix available)
E 3 pthread_mutex_t g_sendmutex;
最终编译通过。
| |
| char (*)[20]
In file included from sample_venc.c:7:
/opt/linux/x86-arm/arm-v01c02-linux-musleabi-gcc/target/usr/include/string.h:33:15: note: expected 'char * restrict' but argument is of type 'char (*)[20]'
33 | char *strcpy (char *__restrict, const char *__restrict);
| ^
sample_venc.c:988:21: warning: variable 'thdsched' set but not used [-Wunused-but-set-variable]
988 | struct sched_param thdsched;
| ^~~~~~~~
sample_venc.c:975:6: warning: unused variable 'i' [-Wunused-variable]
975 | int i;
| ^
sample_venc.c: In function 'VENC_Sent':
sample_venc.c:904:1: warning: control reaches end of non-void function [-Wreturn-type]
904 | }
| ^
At top level:
sample_venc.c:139:18: warning: 'gs_RtpPid' defined but not used [-Wunused-variable]
139 | static pthread_t gs_RtpPid;
| ^~~~~~~~~
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
(myenv) root@topeet:/home/topeet/source_code/Hi3516CV610_SDK_V1.0.1.0/smp/a7_linux/source/mpp/sample/venc#
接下来 放到 板子上 测试一下 , 程序能不能运行。
先不管 vlc .
居然没有报错。
~ # ./sample_venc 0
RTSP:-----Init Rtsp server
wrap online is 1, buf line is 128, buf size is 458544
[MPP] Version: [HI3516CV610_MPP_V1.0.1.0 B040 Release], Build Time[Sep 7 2024, 17:51:12]
linear mode
===================================================================================
vi_pipe:0,== SC4336P_MIPI_27Minput_2lane_10bit_630Mbps_2560x1440_30fps Init OK! ==
===================================================================================
ISP Dev 0 running !
please input choose gop mode!
0) normal p.
1) dual p.
2) smart p.
random: crng init done
0
please input choose rc mode!
c) cbr.
v) vbr.
b) abr.
a) avbr.
x) cvbr.
q) qvbr.
f) fix_qp
c
please press twice ENTER to exit this sample
program exit normally!
~ #
继续测试,当我 打开 vlc 时 出现这个报错。
linear mode
===================================================================================
vi_pipe:0,== SC4336P_MIPI_27Minput_2lane_10bit_630Mbps_2560x1440_30fps Init OK! ==
===================================================================================
ISP Dev 0 running !
please input choose gop mode!
0) normal p.
1) dual p.
2) smart p.
random: crng init done
0
please input choose rc mode!
c) cbr.
v) vbr.
b) abr.
a) avbr.
x) cvbr.
q) qvbr.
f) fix_qp
c
please press twice ENTER to exit this sample
<<<<RTSP Client 192.168.1.114 Connected...
RTSP:-----Create Client 192.168.1.114
<<<<<SETUP rtsp://192.168.1.121:554/stream_chn.h264 RTSP/1.0
CSeq: 0
Transport: RTP/AVP;unicast;client_port=9284-9285
--------------------------------------------
>>>>>RTSP/1.0 200 OK
CSeq: 0
Date: Thu, Jan 01 1970 00:01:10 GMT
Transport: RTP/AVP;unicast;destination=;client_port=9284-9285;server_port=53255-53511
Session: 1000
<<<<<PLAY rtsp://192.168.1.121:554/stream=0 RTSP/1.0
CSeq: 1
Session: 1000
: RTP/AVP;unicast;client_port=9284-9285
--------------------------------------------
>>>>>RTSP/1.0 200 OK
CSeq: 1
Date: Thu, Jan 01 1970 00:01:10 GMT
Range: npt=0.000-
Session: 1000
RTP-Info: url=rtsp:///;seq=0
udp up
Start Play
Segmentation fault
~ #
感觉跟我之前的重复定义 是 有关的。
这个报错解决不了了。
但是我发现一个 重要的错误。
注意:
他可以这样写。
但是我必须这样写。
因为我这里 本身已经是指针了。
报错终于改好了。
改的是 ,去掉头文件的重复的定义,
并且 在 sample_venc.c 中的函数中。
改了这些 结构体。
出现过 , pstStream 的地方 ,都要做相应的改动。
最终测试 结果可以了。
>>>>>RTSP/1.0 200 OK
CSeq: 3
Date: Thu, Jan 01 1970 00:03:30 GMT
Content-Type: application/sdp
Content-length: 357
Content-Base: rtsp://client_port=62728-62/stream_chn0.h264/
v=0
o=StreamingServer 3331435948 1116907222000 IN IP4 client_port=62728-62
s=H.264
c=IN IP4 0.0.0.0
t=0 0
a=control:*
m=video 0 RTP/AVP 96
a=control:trackID=0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=AAABBCCC
m=audio 0 RTP/AVP 97
a=control:trackID=1
a=rtpmap:97 G726-32/8000/1
a=fmtp:97 packetization-mode=1
<<<<<SETUP rtsp://client_port=62728-62/stream_chn0.h264/trackID=0 RTSP/1.0
CSeq: 4
User-Agent: LibVLC/2.2.6 (LIVE555 Streaming Media v2016.02.22)
Transport: RTP/AVP;unicast;client_port=53120-53121
--------------------------------------------client_port=62728-62
>>>>>RTSP/1.0 200 OK
CSeq: 4
Date: Thu, Jan 01 1970 00:03:30 GMT
Transport: RTP/AVP;unicast;destination=client_port=62728-62;client_port=53120-53121;server_port=53255-53511
Session: 1002
<<<<<SETUP rtsp://client_port=62728-62/stream_chn0.h264/trackID=1 RTSP/1.0
CSeq: 5
User-Agent: LibVLC/2.2.6 (LIVE555 Streaming Media v2016.02.22)
Transport: RTP/AVP;unicast;client_port=53122-53123
Session: 1002
--------------------------------------------client_port=53120-53
>>>>>RTSP/1.0 200 OK
CSeq: 5
Date: Thu, Jan 01 1970 00:03:30 GMT
Transport: RTP/AVP;unicast;destination=client_port=53120-53;client_port=53122-53123;server_port=53255-53511
Session: 1002
<<<<<PLAY rtsp://client_port=62728-62/stream_chn0.h264/ RTSP/1.0
CSeq: 6
User-Agent: LibVLC/2.2.6 (LIVE555 Streaming Media v2016.02.22)
Session: 1002
Range: npt=0.000-
;client_port=53122-53123
Session: 1002
--------------------------------------------client_port=62728-62
>>>>>RTSP/1.0 200 OK
CSeq: 6
Date: Thu, Jan 01 1970 00:03:30 GMT
Range: npt=0.000-
Session: 1002
RTP-Info: url=rtsp://client_port=62728-62/stream_chn0.h264;seq=0
udp up
Start Play
<<<<<TEARDOWN rtsp://client_port=62728-62/stream_chn0.h264/ RTSP/1.0
CSeq: 7
User-Agent: LibVLC/2.2.6 (LIVE555 Streaming Media v2016.02.22)
Session: 1002
npt=0.000-
;client_port=53122-53123
Session: 1002
>>>>>RTSP/1.0 200 OK
CSeq: 7
Date: Thu, Jan 01 1970 00:03:50 GMT
Session: 1002
RTSP:-----Exit Client 192.168.1.114
^C^Cprogram exit normally!
~ # ^C
将 ortp 可以的代码 + rtsp 可以的代码 打包 保存到网盘中