--------------------更新2018.08.20-------------------
添加http_tunnel_example.cpp作为RtspOverHttp示例程序。
--------------------更新2018.08.20结束-------------------
一、example逻辑伪码
myRTSPClient附带3个example程序:simple_example、complete_example、common_example。后两个example都是从simple_example中衍生出来的,以下将以simple_example为主进行解析,并且会在最后说明一下另两个example与simple_example的差别。
以下是simple_example简化后的伪代码,以便理解:
1. main():
2. myRtspClient Client;
3. Client.SetURI("rtsp://127.0.0.1/ansersion");
4. Client.SendDESCRIBE();
5. Client.SendSETUP();
6. Client.SendPLAY();
7. Write 1000 RTP Data to file "test_packet_recv.h264";
8. Client.SendTEARDOWN();
9. return;
二、simple_example.cpp代码注释
1 #include <iostream> 2 #include "rtspClient.h" 3 #include <stdio.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 9 using std::cout; 10 using std::endl; 11 12 int main(int argc, char *argv[]) 13 { 14 string RtspUri("rtsp://127.0.0.1/ansersion"); 15 // string RtspUri("rtsp://192.168.81.145/ansersion"); 16 RtspClient Client; 17 18 /* Set up rtsp server resource URI */ 19 Client.SetURI(RtspUri); 20 21 /* Send DESCRIBE command to server */ 22 Client.DoDESCRIBE(); 23 24 /* Parse SDP message after sending DESCRIBE command */ 25 Client.ParseSDP(); // 解析RTSP服务端受理DESCRIBE命令后返回的SDP信息 26 27 /* Send SETUP command to set up all 'audio' and 'video' 28 * sessions which SDP refers. */ 29 Client.DoSETUP(); 30 31 printf("start PLAY "); 32 printf("SDP: %s ", Client.GetSDP().c_str()); 33 34 /* Send PLAY command to play only the 35 * 'video' sessions.*/ 36 Client.DoPLAY("video"); 37 38 /* Receive 1000 RTP 'video' packets 39 * note(FIXME): 40 * if there are several 'video' session 41 * refered in SDP, only receive packets of the first 42 * 'video' session, the same as 'audio'.*/ 43 int packet_num = 0; 44 uint8_t buf[65534]; 45 size_t size = 0; 46 47 /* Write h264 video data to file "test_packet_recv.h264" 48 * Then it could be played by ffplay */ 49 int fd = open("test_packet_recv.h264", O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); 50 if(Client.GetSPSNalu(buf, &size)) { // 解码SDP中关于H264的SPS的数据 51 if(write(fd, buf, size) < 0) { // 将SPS写入文件 52 perror("write"); 53 } 54 } else { 55 printf("SPS error "); 56 } 57 58 if(Client.GetPPSNalu(buf, &size)) { // 解码SDP中关于H264的PPS的数据 59 if(write(fd, buf, size) < 0) { // 将PPS写入文件 60 perror("write"); 61 } 62 } else { 63 printf("PPS error "); 64 } 65 66 while(++packet_num < 1000) { // 接收1000个H264的数据包(确切的说是1000个NALU) 67 if(!Client.GetMediaData("video", buf, &size)) continue; 68 if(write(fd, buf, size) < 0) { 69 perror("write"); 70 } 71 printf("recv %lu ", size); 72 } 73 74 printf("start TEARDOWN "); 75 /* Send TEARDOWN command to teardown all of the sessions */ 76 Client.DoTEARDOWN(); 77 78 return 0; 79 } 80
三、common_example.cpp和complete_example.cpp
common_example.cpp不同于simple_example.cpp的地方只有开头几行,这些代码是为了可以用参数指定RTSP URI。
1 int main(int argc, char *argv[]) 2 { 3 if(argc != 2) { 4 cout << "Usage: " << argv[0] << " <URL>" << endl; 5 cout << "For example: " << endl; 6 cout << argv[0] << " rtsp://127.0.0.1/ansersion" << endl; 7 return 1; 8 } 9 cout << "Start play " << argv[1] << endl; 10 cout << "Then put video data into test_packet_recv.h264" << endl; 11 string RtspUri(argv[1]); 12 // string RtspUri("rtsp://192.168.81.145/ansersion"); 13 RtspClient Client; 14 15 /* Set up rtsp server resource URI */ 16 Client.SetURI(RtspUri); 17 ...... 18 return 0; 19 }
complete_example.cpp不同于simple_example.cpp的地方,就在于每次发送RTSP命令时, 它都会检查命令发送是否成功,并且检验返回信息是否是“200 OK”。
1 int main(int argc, char * argv[]) 2 { 3 ...... 4 /* Send DESCRIBE command to server */ 5 if(Client.DoDESCRIBE() != RTSP_NO_ERROR) { 6 printf("DoDESCRIBE error "); 7 return 0; 8 } 9 printf("%s ", Client.GetResponse().c_str()); 10 /* Check whether server return '200'(OK) */ 11 if(!Client.IsResponse_200_OK()) { 12 printf("DoDESCRIBE error "); 13 return 0; 14 } 15 ...... 16 return 0; 17 }
OK!以上便是myRTSP的基础内容。