发送端用Jrtplib库进行发送,接收端通过VLC接收并播放——有参考代码

来源:互联网 发布:薛之谦 像风一样 知乎 编辑:程序博客网 时间:2024/06/18 10:52

http://bbs.csdn.net/topics/370233508



刚刚接触视频流不久,现在需要将编码后的视频流(H264编码)发送到局域网接收端并显示出来,发送端我使用了Jrtplib库,进行发送,接收端通过VLC接收并播放,功能都已经完全实现,但现在有一个问题,我的视频流是实时的,但是VLC接收并播放时,总是出现停顿几秒钟的现象,停顿后就继续播,而且与实际图像有延时,大概两三秒的样子,找不出来到底是什么问题,希望有过类似经验的兄弟姐妹们帮忙看看,万分感激。。。
  •  
  •  
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
回复次数:17
#1 得分:0回复于: 2011-10-08 14:26:51
是不是我描述的很混乱啊。。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#2 得分:0回复于: 2011-10-08 14:56:09
接收端用VLC播放时,视频不流畅,总是中断,跳帧。。这是怎么回事啊,整体还有延时。。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#3 得分:0回复于: 2011-10-09 13:47:54
帖子沉了。。。恳求各位帮忙解答。。。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#4 得分:0回复于: 2011-10-09 18:17:27
丢包,解码失败的原因。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#5 得分:0回复于: 2011-10-10 10:51:36
你做得出这样的程序,应该知道调试方法把,先测试出问题发生的模块位置,一点一滴的找到出错的地方就可以。
编码,打包传输,网络接收,解码 就四个模块,先自己用UDP,别用Jrtplib,测试(说句心里话,Jrtplib我用过,真不知道哪点比UDP强,局域网看不出效果,internet卡的要死,还不如UDP丢几个包,虽然有点花屏但很流畅),当然UDP要有点控制,至少包的顺序要调整。
     你提的问题,别人不可能很正确的回答你,因为哪个模块都有可能发生这种问题,关键靠自己去发现。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#6 得分:0回复于: 2011-10-10 12:58:43
先抓包看看数据包是不是一下子就到了客户端,排查一下在哪边卡住了。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#7 得分:0回复于: 2011-10-10 14:12:12
谢谢楼上几位的回答,可能我问的不够具体
编码和发送,都是保证每秒钟25帧处理的,但是用JRTPLIB发送后,用VCL播放,就出现丢帧和延时了,大概2、3秒吧
我编码和发送即使需要时间处理,但也不可能延时2、3秒
我之前自己手动封装RTP包然后发送,就不会出现这么大延时,但是视频往往在播放时会中断,中断后就不能继续播放了,所以才想到加上RTCP协议,就用了JRTPLIB库了。
稍后我会把代码发上来,大家帮忙看一下。。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#8 得分:0回复于: 2011-10-10 14:16:13
C/C++ code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include "StdAfx.h"
#include "RTPClass.h"
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
 
 
//////
 
CRTPClass::CRTPClass(void)
{
    bInitRTP = false;
}
 
//////////////////////////////////////////////////////////////////////////
 
void CRTPClass::SetRTPParam(CString ip,int port)
{
    rtp_ip = ip;
    rtp_port = port;
 
}
bool CRTPClass::InitRTP()
{
    //rtp_ip = ip;
    //rtp_port = port;
 
    if ( InitSocket())
    {
        //RTP+RTCP库初始化SOCKET环境
        RTPUDPv4TransmissionParams transparams;
        RTPSessionParams sessparams;
        sessparams.SetOwnTimestampUnit(1.0/90000.0);       //时间戳单位   
        sessparams.SetAcceptOwnPackets(true);
 
         
        uint16_t portbase = rtp_port*10; //PORT_LOCAL;
        transparams.SetPortbase(portbase);       
 
        int status;   
 
        status = sess.Create(sessparams,&transparams);   
        if (!checkerror(status))
        {
            return false;
        }
         
        uint32_t destip;
        destip = inet_addr(rtp_ip);
        destip = ntohl(destip);
        uint16_t destport = rtp_port;
        RTPIPv4Address addr(destip,rtp_port);
        status = sess.AddDestination(addr);
        if (!checkerror(status))
        {
            return false;
        }
 
        sess.SetDefaultPayloadType(96);
        sess.SetDefaultMark(false);
        sess.SetDefaultTimestampIncrement(3600);
 
        bInitRTP = true;
        return true;
    }
     
    return false;
}
bool CRTPClass::InitSocket()
{
    int Error;
    WORD VersionRequested;
    WSADATA WsaData;
    VersionRequested=MAKEWORD(2,2);
    Error=WSAStartup(VersionRequested,&WsaData); //启动WinSock2
    if(Error!=0)
    {
        return false;
    }
    else
    {
        if(LOBYTE(WsaData.wVersion)!=2||HIBYTE(WsaData.wHighVersion)!=2)
        {
            WSACleanup();
            return false;
        }
 
    }
    return true;
 
}
void CRTPClass::SendRTPH264(unsigned char* m_h264Buf,int buflen) 
{
    if (!bInitRTP)
    {
        if (!InitRTP())
        {
            TRACE("InitRTP fail\n");
            return;
        }
    }
     
    unsigned char *pbuf  = new  unsigned char[buflen];
    memcpy(pbuf,m_h264Buf,buflen);
 
    char sendbuf[1400];
    memset(sendbuf,0,1400);
 
    int status;   
 
    if (buflen<=MAX_RTP_PKT_LENGTH)
    {   
        memcpy(sendbuf,pbuf,buflen);       
        status = sess.SendPacket((void *)sendbuf,buflen/*,payload,false,timestamp*/);
         
        checkerror(status);
 
    }   
    else if(buflen>=MAX_RTP_PKT_LENGTH)
    {
        //TRACE("buflen = %d\n",buflen);
        //得到该nalu需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送
        int k=0,l=0;       
        k=buflen/MAX_RTP_PKT_LENGTH;
        l=buflen%MAX_RTP_PKT_LENGTH;
        int t=0;//用于指示当前发送的是第几个分片RTP包       
 
        char nalHeader =pbuf[0]; // NALU 头
        while(t<k||(t==k&&l>0))               
        {   
            if((0==t)||(t<k&&0!=t))//第一包到最后一包的前一包
            {
                sendbuf[0] = (nalHeader & 0x60)|28;               
                sendbuf[1] = (nalHeader & 0x1f);
                if (0==t)
                {
                    sendbuf[1] |= 0x80;
                }
 
                memcpy(sendbuf+2,&pbuf[t*MAX_RTP_PKT_LENGTH],MAX_RTP_PKT_LENGTH+2);
             
                             
                status = sess.SendPacket((void *)sendbuf,MAX_RTP_PKT_LENGTH+2/*,payload,false,timestamp*/);
                 
                checkerror(status);
 
                t++;
 
            }
            //最后一包
            else if((k==t&&l>0)||(t==(k-1)&&l==0)
            {
                 
                int iSendLen;
                if (l>0)
                {
                    iSendLen = buflen-t*MAX_RTP_PKT_LENGTH;
                }
                else
                    iSendLen = MAX_RTP_PKT_LENGTH;
 
                sendbuf[0] = (nalHeader & 0x60)|28;               
                sendbuf[1] = (nalHeader & 0x1f);
                sendbuf[1] |= 0x40;
 
                memcpy(sendbuf+2,&pbuf[t*MAX_RTP_PKT_LENGTH],iSendLen+2);
                //TRACE("start = %d,len = %d\n",t*MAX_RTP_PKT_LENGTH,iSendLen);
                status = sess.SendPacket((void *)sendbuf,iSendLen+2/*,payload,false,timestamp*/);
                 
                checkerror(status);
                t++;
                //    Sleep(100);
            }
    }
 
#ifndef RTP_SUPPORT_THREAD
        status = sess.Poll();
        checkerror(status);
#endif 
        RTPTime::Wait(RTPTime(0,500));   //第一个参数为秒,第二个参数为毫秒
    }
 
    delete []pbuf;
     
}
void CRTPClass::CloseSocket()
{
 
    if (bInitRTP)
    {
         
        //发送一个BYE包离开会话,最多等待3秒钟,超时则不发送
        sess.BYEDestroy(RTPTime(3,0),0,0);
 
#ifdef WIN32
        WSACleanup();
#endif // WIN32
    }
}
 
bool CRTPClass::checkerror(int rtperr)
{
    if (rtperr < 0)
    {
        TRACE("ERROR:%s\n",RTPGetErrorString(rtperr));       
        return false;
    }
    return true;
}
对我有用[1] 丢个板砖[0] 引用 | 举报 | 管理
#9 得分:0回复于: 2011-10-10 14:17:22
调用FFMEPG编码函数后就调用这个类的SendRTPH264函数,将编码后的缓冲区和长度传入该函数



原创粉丝点击