1. 程式人生 > >(轉)RTSP協議詳解

(轉)RTSP協議詳解

定義 attach highlight not xtend prev desc 設備 代理服

轉自:https://www.cnblogs.com/lidabo/p/6553212.html RTSP簡介 RTSP(Real Time Streaming Protocol)是由Real Network和Netscape共同提出的如何有效地在IP網絡上傳輸流媒體數據的應用層協議。RTSP對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸數據,RTSP的作用相當於流媒體服務器的遠程控制。服務器端可以自行選擇使用TCP或UDP來傳送串流內容,它的語法和運作跟HTTP 1.1類似,但並不特別強調時間同步,所以比較能容忍網絡延遲。而且允許同時多個串流需求控制(Multicast),除了可以降低服務器端的網絡用量,還可以支持多方視頻會議(Video onference)。 因為與HTTP1.1的運作方式相似,所以代理服務器《Proxy》的快取功能《Cache》也同樣適用於RTSP,並因RTSP具有重新導向功能,可視實際負載情況來轉換提供服務的服務器,以避免過大的負載集中於同一服務器而造成延遲。
rtsp和http的區別和聯系 (1)聯系:兩者都用純文本來發送消息,且rtsp協議的語法也和HTTP類似。Rtsp一開始這樣設計,也是為了能夠兼容使用以前寫的HTTP協議分析代碼 。 (2)區別:rtsp是有狀態的,不同的是RTSP的命令需要知道現在正處於一個什麽狀態,也就是說rtsp的命令總是按照順序來發送,某個命令總在另外一個命令之前要發送。Rtsp不管處於什麽狀態都不會去斷掉連接。,而http則不保存狀態,協議在發送一個命令以後,連接就會斷開,且命令之間是沒有依賴性的。rtsp協議使用554端口,http使用80端口。
rtsp和sip的區別和聯系 SIP(Session Initiation Protocol),是基於IP的一個應用層控制協議。由於SIP是基於純文本的信令協議,可以管理不同接入網絡上的會話等。會話可以是終端設備之間任何類型的通信,如視頻會話、既時信息處理或協作會話。該協議不會定義或限制可使用的業務,傳輸、服務質量、計費、安全性等問題都由基本核心網絡和其它協議處理。 (1)聯系:sip和rtsp都是應用層的控制協議,負責一次通信過程的建立和控制和結束,不負責中間的傳輸部分。他們都是基於純文本的信令協議,穿墻性能良好。支持tcp、udp,支持多方通信。他們都需要服務器支持,都支持會話中重定向。sip和rtsp 都使用sdp協議來傳送媒體參數,使用rtp(rtcp)協議來傳輸媒體流。 (2)區別:rtsp是專門為流媒體制定的協議,在多個媒體流的時間同步方面比sip強大。rtsp還提供網絡負載均衡的功能,減輕服務器壓力和網絡帶寬要求。sip一般用來創建一次音頻、視頻通話(雙向),而rtsp一般用來做視頻點播、視頻監控等(單向)。當然,從原理上講,rtsp也可以做雙向的視頻通話。
RTSP和RTP(rtcp)的關系 技術分享圖片
rtsp負責建立和控制會話,rtp負責多媒體的傳輸,rtcp配合rtp做控制和流量統計,他們是合作的關系。
RTSP的消息 RTSP的消息有兩大類,一是請求消息(request),一是回應消息(response),兩種消息的格式不同。 請求消息格式:
方法 URI RTSP版本 CR LF
消息頭 CR LF CR LF
消息體 CR LF

其中方法包括OPTIONS、SETUP、PLAY、TEARDOWN等待,URI是接收方(服務端)的地址,例如:rtsp://192.168.22.136:5000/v0,每行後面的CR LF表示回車換行,需要接收端有相應的解析,最後一個消息頭需要有兩個CR LF。

回應消息格式:
RTSP版本 狀態碼 解釋 CR LF
消息頭 CR LF CR LF
消息體 CR LF
其中RTSP版本一般都是RTSP/1.0,狀態碼是一個數值,200表示成功,解釋是與狀態碼對應的文本解釋。

狀態碼由三位數組成,表示方法執行的結果,定義如下:

1XX:保留,將來使用;

2XX:成功,操作被接收、理解、接受(received,understand,accepted);

3XX:重定向,要完成操作必須進行進一步操作;

4XX:客戶端出錯,請求有語法錯誤或無法實現;

5XX:服務器出錯,服務器無法實現合法的請求。


RTSP的方法


rtsp中定義的方法有:OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SCALE, GET_PARAMETER ,SET_PARAMETER 1.OPTION 目的是得到服務器提供的可用方法: OPTIONS rtsp://192.168.20.136:5000/xxx666 RTSP/1.0 CSeq: 1 //每個消息都有序號來標記,第一個包通常是option請求消息 User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) 服務器的回應信息包括提供的一些方法,例如: RTSP/1.0 200 OK Server: UServer 0.9.7_rc1 Cseq: 1 //每個回應消息的cseq數值和請求消息的cseq相對應 Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SCALE, GET_PARAMETER //服務器提供的可用的方法 2.DESCRIBE C向S發起DESCRIBE請求,為了得到會話描述信息(SDP): DESCRIBE rtsp://192.168.20.136:5000/xxx666 RTSP/1.0 CSeq: 2 token: Accept: application/sdp User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) 服務器回應一些對此會話的描述信息(sdp): RTSP/1.0 200 OK Server: UServer 0.9.7_rc1 Cseq: 2 x-prev-url: rtsp://192.168.20.136:5000 x-next-url: rtsp://192.168.20.136:5000 x-Accept-Retransmit: our-retransmit x-Accept-Dynamic-Rate: 1 Cache-Control: must-revalidate Last-Modified: Fri, 10 Nov 2006 12:34:38 GMT Date: Fri, 10 Nov 2006 12:34:38 GMT Expires: Fri, 10 Nov 2006 12:34:38 GMT Content-Base: rtsp://192.168.20.136:5000/xxx666/ Content-Length: 344 Content-Type: application/sdp v=0 //以下都是sdp信息 o=OnewaveUServerNG 1451516402 1025358037 IN IP4 192.168.20.136 s=/xxx666 u=http:/// e=admin@ c=IN IP4 0.0.0.0 t=0 0 a=isma-compliance:1,1.0,1 a=range:npt=0- m=video 0 RTP/AVP 96 //m表示媒體描述,下面是對會話中視頻通道的媒體描述 a=rtpmap:96 MP4V-ES/90000 a=fmtp:96 profile-level-id=245;config=000001B0F5000001B509000001000000012000C888B0E0E0FA62D089028307 a=control:trackID=0//trackID=0表示視頻流用的是通道0 3.SETUP 客戶端提醒服務器建立會話,並確定傳輸模式: SETUP rtsp://192.168.20.136:5000/xxx666/trackID=0 RTSP/1.0 CSeq: 3 Transport: RTP/AVP/TCP;unicast;interleaved=0-1 User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) //uri中帶有trackID=0,表示對該通道進行設置。Transport參數設置了傳輸模式,包的結構。接下來的數據包頭部第二個字節位置就是interleaved,它的值是每個通道都不同的,trackID=0的interleaved值有兩個0或1,0表示rtp包,1表示rtcp包,接受端根據interleaved的值來區別是哪種數據包。 服務器回應信息: RTSP/1.0 200 OK Server: UServer 0.9.7_rc1 Cseq: 3 Session: 6310936469860791894 //服務器回應的會話標識符 Cache-Control: no-cache Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=6B8B4567 4.PLAY 客戶端發送播放請求: PLAY rtsp://192.168.20.136:5000/xxx666 RTSP/1.0 CSeq: 4 Session: 6310936469860791894 Range: npt=0.000- //設置播放時間的範圍 User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) 服務器回應信息: RTSP/1.0 200 OK Server: UServer 0.9.7_rc1 Cseq: 4 Session: 6310936469860791894 Range: npt=0.000000- RTP-Info: url=trackID=0;seq=17040;rtptime=1467265309 //seq和rtptime都是rtp包中的信息 5.TEARDOWN 客戶端發起關閉請求: TEARDOWN rtsp://192.168.20.136:5000/xxx666 RTSP/1.0 CSeq: 5 Session: 6310936469860791894 User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10) 服務器回應: RTSP/1.0 200 OK Server: UServer 0.9.7_rc1 Cseq: 5 Session: 6310936469860791894 Connection: Close 以上方法都是交互過程中最為常用的,其它還有一些重要的方法如get/set_parameter,pause,redirect等等 ps: sdp的格式 v=<version> o=<username> <session id> <version> <network type> <address type> <address> s=<session name> i=<session description> u=<URI> e=<email address> p=<phone number> c=<network type> <address type> <connection address> b=<modifier>:<bandwidth-value> t=<start time> <stop time> r=<repeat interval> <active duration> <list of offsets from start-time> z=<adjustment time> <offset> <adjustment time> <offset> .... k=<method> k=<method>:<encryption key> a=<attribute> a=<attribute>:<value> m=<media> <port> <transport> <fmt list> v = (協議版本) o = (所有者/創建者和會話標識符) s = (會話名稱) i = * (會話信息) u = * (URI 描述) e = * (Email 地址) p = * (電話號碼) c = * (連接信息) b = * (帶寬信息) z = * (時間區域調整) k = * (加密密鑰) a = * (0 個或多個會話屬性行) 時間描述: t = (會話活動時間) r = * (0或多次重復次數) 媒體描述: m = (媒體名稱和傳輸地址) i = * (媒體標題) c = * (連接信息 — 如果包含在會話層則該字段可選) b = * (帶寬信息) k = * (加密密鑰) a = * (0 個或多個媒體屬性行)


RTSP客戶端的JAVA實現


3.1 接口IEvent.java

接口IEvent.java的代碼如下:

Java代碼
  1. package com.amigo.rtsp;
  2. import java.io.IOException;
  3. import java.nio.channels.SelectionKey;
  4. /** *//**
  5. * IEvent.java 網絡事件處理器,當Selector可以進行操作時,調用這個接口中的方法.
  6. * 2007-3-22 下午03:35:51
  7. * @author sycheng
  8. * @version 1.0
  9. */
  10. public interface IEvent {
  11. /** *//**
  12. * 當channel得到connect事件時調用這個方法.
  13. * @param key
  14. * @throws IOException
  15. */
  16. void connect(SelectionKey key) throws IOException;
  17. /** *//**
  18. * 當channel可讀時調用這個方法.
  19. * @param key
  20. * @throws IOException
  21. */
  22. void read(SelectionKey key) throws IOException;
  23. /** *//**
  24. * 當channel可寫時調用這個方法.
  25. * @throws IOException
  26. */
  27. void write() throws IOException;
  28. /** *//**
  29. * 當channel發生錯誤時調用.
  30. * @param e
  31. */
  32. void error(Exception e);
  33. }

3.2 RTSP的測試類:RTSPClient.java
RTSP的測試類RTSPClient.java類的代碼如下所示:

Java代碼
  1. package com.amigo.rtsp;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.nio.ByteBuffer;
  5. import java.nio.channels.SelectionKey;
  6. import java.nio.channels.Selector;
  7. import java.nio.channels.SocketChannel;
  8. import java.util.Iterator;
  9. import java.util.concurrent.atomic.AtomicBoolean;
  10. public class RTSPClient extends Thread implements IEvent {
  11. private static final String VERSION = " RTSP/1.0/r/n";
  12. private static final String RTSP_OK = "RTSP/1.0 200 OK";
  13. /** *//** 遠程地址 */
  14. private final InetSocketAddress remoteAddress;
  15. /** *//** * 本地地址 */
  16. private final InetSocketAddress localAddress;
  17. /** *//** * 連接通道 */
  18. private SocketChannel socketChannel;
  19. /** *//** 發送緩沖區 */
  20. private final ByteBuffer sendBuf;
  21. /** *//** 接收緩沖區 */
  22. private final ByteBuffer receiveBuf;
  23. private static final int BUFFER_SIZE = 8192;
  24. /** *//** 端口選擇器 */
  25. private Selector selector;
  26. private String address;
  27. private Status sysStatus;
  28. private String sessionid;
  29. /** *//** 線程是否結束的標誌 */
  30. private AtomicBoolean shutdown;
  31. private int seq=1;
  32. private boolean isSended;
  33. private String trackInfo;
  34. private enum Status {
  35. init, options, describe, setup, play, pause, teardown
  36. }
  37. public RTSPClient(InetSocketAddress remoteAddress,
  38. InetSocketAddress localAddress, String address) {
  39. this.remoteAddress = remoteAddress;
  40. this.localAddress = localAddress;
  41. this.address = address;
  42. // 初始化緩沖區
  43. sendBuf = ByteBuffer.allocateDirect(BUFFER_SIZE);
  44. receiveBuf = ByteBuffer.allocateDirect(BUFFER_SIZE);
  45. if (selector == null) {
  46. // 創建新的Selector
  47. try {
  48. selector = Selector.open();
  49. } catch (final IOException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. startup();
  54. sysStatus = Status.init;
  55. shutdown=new AtomicBoolean(false);
  56. isSended=false;
  57. }
  58. public void startup() {
  59. try {
  60. // 打開通道
  61. socketChannel = SocketChannel.open();
  62. // 綁定到本地端口
  63. socketChannel.socket().setSoTimeout(30000);
  64. socketChannel.configureBlocking(false);
  65. socketChannel.socket().bind(localAddress);
  66. if (socketChannel.connect(remoteAddress)) {
  67. System.out.println("開始建立連接:" + remoteAddress);
  68. }
  69. socketChannel.register(selector, SelectionKey.OP_CONNECT
  70. | SelectionKey.OP_READ | SelectionKey.OP_WRITE, this);
  71. System.out.println("端口打開成功");
  72. } catch (final IOException e1) {
  73. e1.printStackTrace();
  74. }
  75. }
  76. public void send(byte[] out) {
  77. if (out == null || out.length < 1) {
  78. return;
  79. }
  80. synchronized (sendBuf) {
  81. sendBuf.clear();
  82. sendBuf.put(out);
  83. sendBuf.flip();
  84. }
  85. // 發送出去
  86. try {
  87. write();
  88. isSended=true;
  89. } catch (final IOException e) {
  90. e.printStackTrace();
  91. }
  92. }
  93. public void write() throws IOException {
  94. if (isConnected()) {
  95. try {
  96. socketChannel.write(sendBuf);
  97. } catch (final IOException e) {
  98. }
  99. } else {
  100. System.out.println("通道為空或者沒有連接上");
  101. }
  102. }
  103. public byte[] recieve() {
  104. if (isConnected()) {
  105. try {
  106. int len = 0;
  107. int readBytes = 0;
  108. synchronized (receiveBuf) {
  109. receiveBuf.clear();
  110. try {
  111. while ((len = socketChannel.read(receiveBuf)) > 0) {
  112. readBytes += len;
  113. }
  114. } finally {
  115. receiveBuf.flip();
  116. }
  117. if (readBytes > 0) {
  118. final byte[] tmp = new byte[readBytes];
  119. receiveBuf.get(tmp);
  120. return tmp;
  121. } else {
  122. System.out.println("接收到數據為空,重新啟動連接");
  123. return null;
  124. }
  125. }
  126. } catch (final IOException e) {
  127. System.out.println("接收消息錯誤:");
  128. }
  129. } else {
  130. System.out.println("端口沒有連接");
  131. }
  132. return null;
  133. }
  134. public boolean isConnected() {
  135. return socketChannel != null && socketChannel.isConnected();
  136. }
  137. private void select() {
  138. int n = 0;
  139. try {
  140. if (selector == null) {
  141. return;
  142. }
  143. n = selector.select(1000);
  144. } catch (final Exception e) {
  145. e.printStackTrace();
  146. }
  147. // 如果select返回大於0,處理事件
  148. if (n > 0) {
  149. for (final Iterator<SelectionKey> i = selector.selectedKeys()
  150. .iterator(); i.hasNext();) {
  151. // 得到下一個Key
  152. final SelectionKey sk = i.next();
  153. i.remove();
  154. // 檢查其是否還有效
  155. if (!sk.isValid()) {
  156. continue;
  157. }
  158. // 處理事件
  159. final IEvent handler = (IEvent) sk.attachment();
  160. try {
  161. if (sk.isConnectable()) {
  162. handler.connect(sk);
  163. } else if (sk.isReadable()) {
  164. handler.read(sk);
  165. } else {
  166. // System.err.println("Ooops");
  167. }
  168. } catch (final Exception e) {
  169. handler.error(e);
  170. sk.cancel();
  171. }
  172. }
  173. }
  174. }
  175. public void shutdown() {
  176. if (isConnected()) {
  177. try {
  178. socketChannel.close();
  179. System.out.println("端口關閉成功");
  180. } catch (final IOException e) {
  181. System.out.println("端口關閉錯誤:");
  182. } finally {
  183. socketChannel = null;
  184. }
  185. } else {
  186. System.out.println("通道為空或者沒有連接");
  187. }
  188. }
  189. @Override
  190. public void run() {
  191. // 啟動主循環流程
  192. while (!shutdown.get()) {
  193. try {
  194. if (isConnected()&&(!isSended)) {
  195. switch (sysStatus) {
  196. case init:
  197. doOption();
  198. break;
  199. case options:
  200. doDescribe();
  201. break;
  202. case describe:
  203. doSetup();
  204. break;
  205. case setup:
  206. if(sessionid==null&&sessionid.length()>0){
  207. System.out.println("setup還沒有正常返回");
  208. }else{
  209. doPlay();
  210. }
  211. break;
  212. case play:
  213. doPause();
  214. break;
  215. case pause:
  216. doTeardown();
  217. break;
  218. default:
  219. break;
  220. }
  221. }
  222. // do select
  223. select();
  224. try {
  225. Thread.sleep(1000);
  226. } catch (final Exception e) {
  227. }
  228. } catch (final Exception e) {
  229. e.printStackTrace();
  230. }
  231. }
  232. shutdown();
  233. }
  234. public void connect(SelectionKey key) throws IOException {
  235. if (isConnected()) {
  236. return;
  237. }
  238. // 完成SocketChannel的連接
  239. socketChannel.finishConnect();
  240. while (!socketChannel.isConnected()) {
  241. try {
  242. Thread.sleep(300);
  243. } catch (final InterruptedException e) {
  244. e.printStackTrace();
  245. }
  246. socketChannel.finishConnect();
  247. }
  248. }
  249. public void error(Exception e) {
  250. e.printStackTrace();
  251. }
  252. public void read(SelectionKey key) throws IOException {
  253. // 接收消息
  254. final byte[] msg = recieve();
  255. if (msg != null) {
  256. handle(msg);
  257. } else {
  258. key.cancel();
  259. }
  260. }
  261. private void handle(byte[] msg) {
  262. String tmp = new String(msg);
  263. System.out.println("返回內容:");
  264. System.out.println(tmp);
  265. if (tmp.startsWith(RTSP_OK)) {
  266. switch (sysStatus) {
  267. case init:
  268. sysStatus = Status.options;
  269. break;
  270. case options:
  271. sysStatus = Status.describe;
  272. trackInfo=tmp.substring(tmp.indexOf("trackID"));
  273. break;
  274. case describe:
  275. sessionid = tmp.substring(tmp.indexOf("Session: ") + 9, tmp
  276. .indexOf("Date:"));
  277. if(sessionid!=null&&sessionid.length()>0){
  278. sysStatus = Status.setup;
  279. }
  280. break;
  281. case setup:
  282. sysStatus = Status.play;
  283. break;
  284. case play:
  285. sysStatus = Status.pause;
  286. break;
  287. case pause:
  288. sysStatus = Status.teardown;
  289. shutdown.set(true);
  290. break;
  291. case teardown:
  292. sysStatus = Status.init;
  293. break;
  294. default:
  295. break;
  296. }
  297. isSended=false;
  298. } else {
  299. System.out.println("返回錯誤:" + tmp);
  300. }
  301. }
  302. private void doTeardown() {
  303. StringBuilder sb = new StringBuilder();
  304. sb.append("TEARDOWN ");
  305. sb.append(this.address);
  306. sb.append("/");
  307. sb.append(VERSION);
  308. sb.append("Cseq: ");
  309. sb.append(seq++);
  310. sb.append("/r/n");
  311. sb.append("User-Agent: RealMedia Player HelixDNAClient/10.0.0.11279 (win32)/r/n");
  312. sb.append("Session: ");
  313. sb.append(sessionid);
  314. sb.append("/r/n");
  315. send(sb.toString().getBytes());
  316. System.out.println(sb.toString());
  317. }
  318. private void doPlay() {
  319. StringBuilder sb = new StringBuilder();
  320. sb.append("PLAY ");
  321. sb.append(this.address);
  322. sb.append(VERSION);
  323. sb.append("Session: ");
  324. sb.append(sessionid);
  325. sb.append("Cseq: ");
  326. sb.append(seq++);
  327. sb.append("/r/n");
  328. sb.append("/r/n");
  329. System.out.println(sb.toString());
  330. send(sb.toString().getBytes());
  331. }
  332. private void doSetup() {
  333. StringBuilder sb = new StringBuilder();
  334. sb.append("SETUP ");
  335. sb.append(this.address);
  336. sb.append("/");
  337. sb.append(trackInfo);
  338. sb.append(VERSION);
  339. sb.append("Cseq: ");
  340. sb.append(seq++);
  341. sb.append("/r/n");
  342. sb.append("Transport: RTP/AVP;UNICAST;client_port=16264-16265;mode=play/r/n");
  343. sb.append("/r/n");
  344. System.out.println(sb.toString());
  345. send(sb.toString().getBytes());
  346. }
  347. private void doOption() {
  348. StringBuilder sb = new StringBuilder();
  349. sb.append("OPTIONS ");
  350. sb.append(this.address.substring(0, address.lastIndexOf("/")));
  351. sb.append(VERSION);
  352. sb.append("Cseq: ");
  353. sb.append(seq++);
  354. sb.append("/r/n");
  355. sb.append("/r/n");
  356. System.out.println(sb.toString());
  357. send(sb.toString().getBytes());
  358. }
  359. private void doDescribe() {
  360. StringBuilder sb = new StringBuilder();
  361. sb.append("DESCRIBE ");
  362. sb.append(this.address);
  363. sb.append(VERSION);
  364. sb.append("Cseq: ");
  365. sb.append(seq++);
  366. sb.append("/r/n");
  367. sb.append("/r/n");
  368. System.out.println(sb.toString());
  369. send(sb.toString().getBytes());
  370. }
  371. private void doPause() {
  372. StringBuilder sb = new StringBuilder();
  373. sb.append("PAUSE ");
  374. sb.append(this.address);
  375. sb.append("/");
  376. sb.append(VERSION);
  377. sb.append("Cseq: ");
  378. sb.append(seq++);
  379. sb.append("/r/n");
  380. sb.append("Session: ");
  381. sb.append(sessionid);
  382. sb.append("/r/n");
  383. send(sb.toString().getBytes());
  384. System.out.println(sb.toString());
  385. }
  386. public static void main(String[] args) {
  387. try {
  388. // RTSPClient(InetSocketAddress remoteAddress,
  389. // InetSocketAddress localAddress, String address)
  390. RTSPClient client = new RTSPClient(
  391. new InetSocketAddress("218.207.101.236", 554),
  392. new InetSocketAddress("192.168.2.28", 0),
  393. "rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp");
  394. client.start();
  395. } catch (Exception e) {
  396. e.printStackTrace();
  397. }
  398. }
  399. }

其中:rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp為我在網上找到的一個rtsp的sdp地址,讀者可自行更換,RTSP的默認端口為554.
3.3 運行結果
運行RTSPClient.java,運行結果如下所示:

Java代碼
  1. 端口打開成功
  2. OPTIONS rtsp://218.207.101.236:554/mobile/3/67A451E937422331 RTSP/1.0
  3. Cseq: 1
  4. 返回內容:
  5. RTSP/1.0 200 OK
  6. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  7. Cseq: 1
  8. Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD
  9. DESCRIBE rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp RTSP/1.0
  10. Cseq: 2
  11. 返回內容:
  12. RTSP/1.0 200 OK
  13. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  14. Cseq: 2
  15. Content-length: 421
  16. Date: Mon, 03 Aug 2009 08:50:36 GMT
  17. Expires: Mon, 03 Aug 2009 08:50:36 GMT
  18. Content-Type: application/sdp
  19. x-Accept-Retransmit: our-retransmit
  20. x-Accept-Dynamic-Rate: 1
  21. Content-Base: rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp/
  22. v=0
  23. o=MediaBox 127992 137813 IN IP4 0.0.0.0
  24. s=RTSP Session
  25. i=Starv Box Live Cast
  26. c=IN IP4 218.207.101.236
  27. t=0 0
  28. a=range:npt=now-
  29. a=control:*
  30. m=video 0 RTP/AVP 96
  31. b=AS:20
  32. a=rtpmap:96 MP4V-ES/1000
  33. a=fmtp:96 profile-level-id=8; config=000001b008000001b5090000010000000120008440fa282c2090a31f; decode_buf=12586
  34. a=range:npt=now-
  35. a=framerate:5
  36. a=framesize:96 176-144
  37. a=cliprect:0,0,144,176
  38. a=control:trackID=1
  39. SETUP rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp/trackID=1
  40. RTSP/1.0
  41. Cseq: 3
  42. Transport: RTP/AVP;UNICAST;client_port=16264-16265;mode=play
  43. 返回內容:
  44. RTSP/1.0 200 OK
  45. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  46. Cseq: 3
  47. Session: 15470472221769
  48. Date: Mon, 03 Aug 2009 08:50:36 GMT
  49. Expires: Mon, 03 Aug 2009 08:50:36 GMT
  50. Transport: RTP/AVP;UNICAST;mode=play;client_port=16264-16265;server_port=20080-20081
  51. PLAY rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp RTSP/1.0
  52. Session: 15470472221769
  53. Cseq: 4
  54. 返回內容:
  55. RTSP/1.0 200 OK
  56. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  57. Cseq: 4
  58. Session: 15470472221769
  59. RTP-Info: url=rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp/trackID=1;seq=0;rtptime=0
  60. PAUSE rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp/ RTSP/1.0
  61. Cseq: 5
  62. Session: 15470472221769
  63. 返回內容:
  64. RTSP/1.0 200 OK
  65. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  66. Cseq: 5
  67. Session: 15470472221769
  68. TEARDOWN rtsp://218.207.101.236:554/mobile/3/67A451E937422331/8jH5QPU5GWS07Ugn.sdp/ RTSP/1.0
  69. Cseq: 6
  70. User-Agent: RealMedia Player HelixDNAClient/10.0.0.11279 (win32)
  71. Session: 15470472221769
  72. 返回內容:
  73. RTSP/1.0 200 OK
  74. Server: PVSS/1.4.8 (Build/20090111; Platform/Win32; Release/StarValley; )
  75. Cseq: 6
  76. Session: 15470472221769
  77. Connection: Close
  78. 端口關閉成功

對照運行結果,讀者可以熟悉RTSP的常用命令.

(轉)RTSP協議詳解