终于捣鼓出点东西了!高兴啊~~~哈哈哈哈,首先感谢网络上的资源的帮助。
1、RFC3550,3551,2190--ENU,http://www.faqs.org/rfcs/rfc3551.html
2、CodeProject上的VideoNet:http://www.codeproject.com/KB/IP/videonet.aspx
3、RFC3550--CHS,http://www.rosoo.net/a/201001/8356.html
4、CSDN以及Rosoo上的关于时间戳的讲解;
CSDN: http://blog.csdn.net/ldd909/article/details/6183439
Rosoo:http://www.rosoo.net/a/201102/10965.html
5、关于RTP的协议分析:http://blog.csdn.net/bripengandre/article/details/2238818
6、关于H.263介绍:http://blog.csdn.net/menuconfig/article/details/2649041
7、百度百科的RTP/RTCP的词条介绍:http://baike.baidu.com/view/1149098.html。
下面是程序的main源文件,需要的配置是VS2005+opencv2.2+jrtplib+h.263的编解码,所有的库文件等在压缩包中都有,整个工程的下载:http://download.csdn.net/source/3497956
main源码如下:是在前面几篇文章的基础上修改整合而成,仅用作测试
#include "header_rtph263.h" using namespace jrtplib; #ifdef SERVER #undef SERVER #endif #define SERVER //if defined than as a sender, else as a receiver #ifdef SERVER #define PORT_BASE 8000 #define DEST_PORT 2000 #else #define PORT_BASE 2000 #define DEST_PORT 3000 #endif //#define CAMERA //if defined open default camera by opencv, else read from avi files int ByteCount = 0; unsigned char cdata[20000]; int cbuffer_size = 20000; unsigned char rgbdata[400000]; int buffersize = 400000; //编码回调 void OwnWriteFunction(int byte) { if(ByteCount<cbuffer_size) { cdata[ByteCount]=(unsigned char)byte; ++ByteCount; } } void checkerror(int rtperr) { if (rtperr < 0) { std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl; exit(-1); } } int main(int argc, char **argv) { //opencv var Mat frame; Mat temp[3]; VideoCapture capture; int frameCount = 0; //h263 ----------encoder/decoder init uchar *readData = NULL; uchar *imgBuffer = NULL; unsigned int yuv[WIDTH*HEIGHT*3/2]; CParam h263Param; Bits bits; InitLookupTable(); h263Param.format = PARAM_FORM; InitH263Encoder(&h263Param); WriteByteFunction = OwnWriteFunction; InitH263Decoder(); //rtp---initialze and creation WSADATA dat; WSAStartup(MAKEWORD(2,2), &dat); const size_t MaxPackSize = 20000; RTPSession session; RTPSessionParams sessionparams; sessionparams.SetOwnTimestampUnit(1.0/90000.0); //for video ---see RFC2190 RTPUDPv4TransmissionParams transparams; transparams.SetPortbase(PORT_BASE); int status = session.Create(sessionparams,&transparams); checkerror(status); uint8_t localip[]={127, 0, 0, 1}; RTPIPv4Address addr(localip, DEST_PORT); status = session.AddDestination(addr); checkerror(status); session.SetDefaultPayloadType(34); //PT for H.263----see RFC2190 session.SetDefaultMark(true); //true or false ?? both ok for my test session.SetDefaultTimestampIncrement(3600); // =90000/25 session.SetMaximumPacketSize(MaxPackSize); #ifdef SERVER #ifdef CAMERA capture.open(0); #else capture.open("d:\\video\\petsc1.avi"); #endif if (!capture.isOpened()) { cout<<"open video/camera failed!"<<endl; return -1; } capture>>frame; if (frame.empty()) { cout<<"grab frame failed! exit...."<<endl; return -1; } namedWindow("raw", CV_WINDOW_AUTOSIZE); while (waitKey(40) != 27) //25 fps { capture>>frame; if (frame.empty()) { cout<<"grab frame failed! exit...."<<endl; return -1; } ++frameCount; resize(frame, temp[0], cv::Size(WIDTH, HEIGHT)); //resize to CIF imshow("raw", temp[0]); ////---------------------------compress image frames-------------------------// ConvertRGB2YUV(WIDTH, HEIGHT, temp[0].data, yuv); ByteCount = 0; h263Param.format = PARAM_FORM; h263Param.inter = CPARAM_INTRA; h263Param.Q_intra = 8; h263Param.data = yuv; CompressFrame(&h263Param, &bits); cout<<"compressed byte count is: "<<ByteCount<<endl; ///-------------------------------------------------------------------------// status = session.SendPacket(cdata, ByteCount); checkerror(status); } #else namedWindow("got", CV_WINDOW_AUTOSIZE); int packetNum = 0; while(waitKey(40) != 27) //25fps { session.BeginDataAccess(); if (session.GotoFirstSourceWithData()) { do { RTPPacket *packet; while( (packet = session.GetNextPacket()) != NULL) { cout<<"packet count: "<<++packetNum<<endl; size_t dataLen = packet->GetPayloadLength(); cout<<"payload length: "<<dataLen<<endl; readData = packet->GetPayloadData(); imgBuffer = new uchar[dataLen]; memcpy(imgBuffer, readData, dataLen); ///----------------------------decompress--------------------------// DecompressFrame(imgBuffer, dataLen, rgbdata, buffersize); ///----------------------------------------------------------------// Mat GotImg(HEIGHT, WIDTH, CV_8UC3, rgbdata); if(GotImg.empty()) { cout<<"got image has no data, exiting...."<<endl; return -1; } imshow("got", GotImg); //release buffers and packet delete []imgBuffer; imgBuffer = NULL; session.DeletePacket(packet); } } while (session.GotoNextSourceWithData()); } session.EndDataAccess(); } #endif /////////////////////////////////////////////////////////////////// //release resources cvDestroyAllWindows(); ExitH263Decoder(); ExitH263Encoder(&h263Param); RTPTime delay(5.0); session.BYEDestroy(delay, "trans over", 10); WSACleanup(); return 0; }
经测试在本机收发正常,在实验室的两台机子上也成功收发。
需要注意的是,整个程序由宏#define SERVER来控制是作为接受还是发送,定义了SERVER则程序作为发送方,否则作为接受方。如果是发送avi文件的话,可能需要转换一下格式,有些avi直接使用opencv打不开。