linux 使用jrtplib收发h.264视频文件
来源:互联网 发布:windows仿mac软件 编辑:程序博客网 时间:2024/06/05 14:12
之前介绍过自己直接使用RTP收发h.264数据,这样有一个麻烦就是RTP协议的各个参数需要自己一个一个位的去填充,这样不利于发送也不方便接收。jrtplib库就刚好解决了这样的麻烦,同时它还提供了很多RTCP的信息查询接口,这样为实现实时流控制提供了方便。
在本文中,将介绍h264 通过jrtplib库来实现实时的发送和接收。发送方发送,按照编码的习惯,我们习惯上是每完成一帧数据的编码就整一帧数据的发送。与此类似,在接收端,我们也是喜欢将整一帧的数据接收完整后再进行解码等处理。但是,这样会带来一个问题,我们网络最大传输单位MUT 一般是1400个字节,而我们进行h.264数据编码的时候,很多数据帧会大于1400帧,所以需要分开几个数据包来发送,在接收的时候,需要将分开的数据包再合成一个数据帧。
注明:
下面代码是在我电脑写的最简程序。
发送端IP:192.168.0.5
接收端IP:192.168.0.6
发送端口:6666
接收端口:6664
注意几点:
(1)jrtplib不能使用基数端口,基数端口用来建立RTCP
(2)jrtplib设置的默认MUT是1400,但是实际每包数据不能发送1400字节,因为它还有TCP 头数据
receive.c
/*============================================================================= * FileName: receive.cpp * Desc: reveive h.264 from RTP server * Author: licaibiao * LastChange: 2017-04-22 * =============================================================================*/#include <jrtplib3/rtpsession.h>#include <jrtplib3/rtpudpv4transmitter.h>#include <jrtplib3/rtpipv4address.h>#include <jrtplib3/rtpsessionparams.h>#include <jrtplib3/rtperrors.h>#include <jrtplib3/rtplibraryversion.h>#include <jrtplib3/rtppacket.h>#include <stdlib.h>#include <stdio.h>#include <iostream>#include <string>using namespace jrtplib;void checkerror(int rtperr){if (rtperr < 0){std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;exit(-1);}}int main(void){RTPSession sess;uint16_t portbase = 6664;int status;bool done = false;RTPUDPv4TransmissionParams transparams;RTPSessionParams sessparams;sessparams.SetOwnTimestampUnit(1.0/10.0);sessparams.SetAcceptOwnPackets(true);transparams.SetPortbase(portbase);status = sess.Create(sessparams,&transparams);checkerror(status);sess.BeginDataAccess();RTPTime delay(0.001);RTPTime starttime = RTPTime::CurrentTime();FILE *fd;size_t len;uint8_t *loaddata;RTPPacket *pack;uint8_t buff[1024*100] = {0};int pos = 0;fd = fopen("./test_recv.h264","wb+");while (!done){status = sess.Poll();checkerror(status);if (sess.GotoFirstSourceWithData()){do{while ((pack = sess.GetNextPacket()) != NULL){loaddata = pack->GetPayloadData();len = pack->GetPayloadLength();if(pack->GetPayloadType() == 96) //H264{if(pack->HasMarker()) // the last packet{memcpy(&buff[pos],loaddata,len);fwrite(buff, 1, pos+len, fd);pos = 0;}else{memcpy(&buff[pos],loaddata,len);pos = pos + len;}}else{printf("!!! GetPayloadType = %d !!!! \n ",pack->GetPayloadType());}sess.DeletePacket(pack);}} while (sess.GotoNextSourceWithData());}RTPTime::Wait(delay);RTPTime t = RTPTime::CurrentTime();t -= starttime;if (t > RTPTime(40.0))done = true;}fclose(fd);sess.EndDataAccess();delay = RTPTime(10.0);sess.BYEDestroy(delay,0,0); return 0;}发送端程序 sender
/*============================================================================= * FileName: sender.cpp * Desc: sending h.264 data to client * Author: licaibiao * LastChange: 2017-04-22 * =============================================================================*/#include <jrtplib3/rtpsession.h>#include <jrtplib3/rtpudpv4transmitter.h>#include <jrtplib3/rtpipv4address.h>#include <jrtplib3/rtpsessionparams.h>#include <jrtplib3/rtperrors.h>#include <jrtplib3/rtplibraryversion.h>#include <stdlib.h>#include <stdio.h>#include <iostream>#include <string>using namespace jrtplib;#define MAXLEN(RTP_DEFAULTPACKETSIZE - 100)void checkerror(int rtperr){if (rtperr < 0){std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;exit(-1);}}class MyRTPSession : public RTPSession{ public: MyRTPSession(void); ~MyRTPSession(void); void SendH264Nalu(RTPSession* sess,uint8_t* m_h264Buf,int buflen); protected: };MyRTPSession::MyRTPSession(void){} MyRTPSession::~MyRTPSession(void){}int main(void){ int i; int num;int status; RTPSession sess; MyRTPSession sender;uint16_t portbase = 6666; uint16_t destport = 6664;uint8_t destip[]={192,168,0,6};RTPUDPv4TransmissionParams transparams;RTPSessionParams sessparams; /* set h264 param */ sessparams.SetUsePredefinedSSRC(true); //设置使用预先定义的SSRC sessparams.SetOwnTimestampUnit(1.0/9000.0); /* 设置采样间隔 */ sessparams.SetAcceptOwnPackets(true); //接收自己发送的数据包 transparams.SetPortbase(portbase);status = sess.Create(sessparams,&transparams);checkerror(status);RTPIPv4Address addr(destip,destport);status = sess.AddDestination(addr);checkerror(status); sess.SetDefaultTimestampIncrement(3600);/* 设置时间戳增加间隔 */ sess.SetDefaultPayloadType(96); sess.SetDefaultMark(true); FILE *fd; int pos = 0; int header_flag = 0; uint8_t buff[1024*100] = {0}; fd = fopen("./test.h264","rb"); fread(buff, 1, 4, fd); if((buff[0]==0)&&(buff[1]==0)&&(buff[2]==0)&&(buff[3]==1)){ header_flag = 1; pos = 4; }else{ header_flag = 0; pos = 3; } while((feof(fd)==0)) { buff[pos++] = fgetc(fd); if(header_flag == 1){ //00 00 00 01 if((buff[pos-1]==1)&&(buff[pos-2]==0)&&(buff[pos-3]==0)&&(buff[pos-4]==0)){ sender.SendH264Nalu(&sess, buff,pos-4); buff[0] = 0x00; buff[1] = 0x00; buff[2] = 0x00; buff[3] = 0x01;pos = 4;RTPTime::Wait(0.03); } } else{ if((buff[pos-1]==1)&&(buff[pos-2]==0)&&(buff[pos-3]==0)){ sender.SendH264Nalu(&sess, buff, pos-3); buff[0] = 0x00; buff[1] = 0x00; buff[3] = 0x01; pos = 3;RTPTime::Wait(0.03); } } } if(pos != 0){ sender.SendH264Nalu(&sess,buff,pos); }fclose(fd);printf("end of the read\n");sess.BYEDestroy(RTPTime(10,0),0,0); return 0;}
在上面的代码中,去掉了void SendH264Nalu(RTPSession* sess,uint8_t* m_h264Buf,int buflen) 函数的实现
完整的代码可以在这里下载:linux 使用jrtplib收发h.264视频文件
0 0
- linux 使用jrtplib收发h.264视频文件
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 使用jrtplib传输H.264视频文件(3)
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 使用jrtplib传输H.264视频文件(3)
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 使用jrtplib传输H.264视频文件(3)
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 使用jrtplib传输H.264视频文件(3)
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 使用jrtplib传输H.264视频文件(3)
- 使用jrtplib(RTP)传输H.264视频文件(1)
- 使用jrtplib(RTP)传输H.264视频文件(2)
- 插入排序——希尔排序
- Bash-shell
- Java设计模式《十八》桥接模式
- LeetCode 543. Diameter of Binary Tree
- bfs和dfs:poj2386和leetcode130
- linux 使用jrtplib收发h.264视频文件
- 无法打开输入文件“libcaffe.lib” 解决方法
- SpringMVC简单注解实例--简要调用过程
- Angular2源码解读之ChangeDetection
- angular.copy()
- Java RandomAccessFile用法
- vim实现两个文件之间的复制
- Java设计模式《十九》命令模式
- C++派生类的构造函数和析构函数