終於搗鼓出點東西了!高興啊~~~哈哈哈哈,首先感謝網絡上的資源的幫助。
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打不開。