转自:http://blog.csdn.net/baby313/article/details/7353605

本文会带领着你一步步动手实现一个简单的RTP传输服务器,旨在了解RTP流媒体传输协议以及一些关于多媒体编解码的知识。

关于RTP协议的必备知识

要动手实现一个协议,当然首先需要阅读该协议的文档。RTP协议的文档,有rfc1889、rfc1890、rfc3550,其中rfc3550是现在的版本,另外两个是过期版。这个协议可以在ietf的官网找到:http://tools.ietf.org/html/rfc3550

RTP packet

RTP是基于UDP协议的,RTP服务器会通过UDP协议,通常每次会发送一个RTP packet。客户端通过解析RTP packet,读取其中的数据然后进行播放了。

RTP packet的结构如下:

  1. RTP Header:RTP 包的头部
  2. contributing sources:个数为0-n个,所以可以为空。具体定义参考rfc3550
  3. RTP payload:即RTP要传输的数据

RTP Header

这是RTP流的头部,在网上搜索RTP格式,就会搜到很多文章介绍这个头部的定义。我们这里参考rfc3550的定义,在5.1节(http://tools.ietf.org/html/rfc3550#section-5.1)。

0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

每行是32 bits,由此可以直观看到每个表示部分所占的位数。简单介绍一下:

V(version):2 bits,RTP的版本,这里统一为2

P(padding):1 bit,如果置1,在packet的末尾被填充,填充有时是方便一些针对固定长度的算法的封装

X(extension):1 bit,如果置1,在RTP Header会跟着一个header extension

CC(CSRC count): 4 bits,表示头部后contributing sources的个数

M(marker): 1 bit,具体这位的定义会在一个profile里

PT(playload type): 7 bits,表示所传输的多媒体的类型,对应的编号在另一份文档rfc3551中有列出(http://tools.ietf.org/html/rfc3551)

sequence number: 16 bits,每个RTP packet的sequence number会自动加一,以便接收端检测丢包情况

timestamp: 32 bits,时间戳

SSRC: 32 bits,同步源的id,没两个同步源的id不能相同

CSRC: 上文说到,个数由CC指定,范围是0-15

以上的一些概念是一些要实现RTP服务器所必备的知识。介绍的非常简略,详细的定义还是要参考rfc3550原文。

动手实践

我们既然已经知道了RTP packet的结构,那么我们以前用到的RTP流是否也是这样的结构呢?如何验证呢?接下来,我们就一步步验证RTP流的结构。

我们知道RTP是基于UDP协议的,那么我们就先做一个简单的UDP接受端,看看我们可以从RTP服务器接受到什么信息。要实现这个接受端,你需要有一定的网络编程经验,至于具体到操作系统、编程环境、开发语言等都不限制。为了简单,我这里用Python给出一个小小的例子程序。

  1. import socket
  2. # Build a socket to receive data from RTP server.
  3. # Here we use SOCK_DGRAM, because RTP is on UDP.
  4. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  5. sock.bind(("localhost", 6666))
  6. for i in range(5):
  7. # We just get 16 bytes to analyze the RTP Header.
  8. buf = sock.recv(16)
  9. # Output the result in octal.
  10. for c in buf:
  11. print "%x" % ord(c),
  12. print
  13. sock.close()

这就是接受程序啦,非常短小,而且有简单注释,这里就不解释了。

接受端已经做好了,那么去哪里找RTP服务器作发送端呢?你可以用一些搭建流媒体服务器的工具,我这里选用的是强大的VLC。关于VLC搭建流媒体服务器的方法,请参考我前面的文章基于移动平台的多媒体框架——用VLC搭建简单的流媒体服务器。这里需要注意几个配置的地方,一是选择Destination的时候要选择RTP而不要选择RTSP,然后地址可以填写本机ip地址或直接写localhost,端口号填写的要和接受端一致,这里是6666。配置好之后的string应该类似于:

:sout=#rtp{dst=localhost,port=6666,mux=ts} :no-sout-rtp-sap :no-sout-standard-sap :ttl=1

服务端配置完成之后,开始Stream。这时打开接受端,就会接受到一些数据,我接收到的数据开头是:

80 a1 20 43 8c cf 76 3c 93 59 d 74 47 0 44 10
80 a1 20 44 8c cf 79 4b 93 59 d 74 47 40 42 36
80 a1 20 45 8c cf 7d 36 93 59 d 74 47 0 44 1a
80 a1 20 46 8c cf 81 21 93 59 d 74 47 40 45 1a
80 a1 20 47 8c cf 85 c 93 59 d 74 47 0 45 1b
这是十六进制的表示。我们依照上面的Header的格式对其进行解读:
第一个byte 80 表示:

V(version)=2

P(padding)=0

X(extension)=0

CC(CSRC count)=0

第二个byte a1 表示:

M(marker)=1

PT(playload type)=33(对照rfc3551可以发现,33表示MP2T AV,正是我们用VLC Stream的格式类型)

后面的2bytes的sequence number我们可以直观的看出是在加一,4bytes的timestamp也是在不断递增的。再之后的93 59 d 74就是SSRC id了,由于CC为0,所以没有CCRC。再之后的几位都是RTP所要传输的数据了。

总结

对RTP协议的熟悉是实现它的基础。这里我只是做一个简单的介绍,需要详细了解,读官方的文档是必不可少的步骤。

通过写一个小程序打印出RTP流中具体的数据,并没有对实现RTP服务器有直接帮助。但是可以让你对协议本身以及编程环境更加熟悉,也方便了以后实现过程中进行调试。不论你在什么环境用什么语言实现,都强烈建议写一个这样的小程序。

自己动手写RTP服务器——关于RTP协议的更多相关文章

  1. 自己动手写RTP服务器——用RTP协议传输TS流

    上一篇文章我们介绍了关于RTP协议的知识,那么我们现在就自己写一个简单的传输TS流媒体的RTP服务器吧. 预备知识 关于TS流的格式:TS流封装的具体格式请参考文档ISO/IEC 13818-1.这里 ...

  2. 自己动手写http服务器——主程序(三)

    功能:目前只支持对资源的访问. 使用的模型:多线程加epoll,与传统的一个连接请求一个线程处理不同的是,这个模型只为那些需要服务的连接请求调用线程进行处理, 整个模型的大致流程 创建一个线程持对象, ...

  3. 自己动手写http服务器——处理http连接(二)

    关于http报文格式请看这篇文章 //http_conn.h #ifndef HTTPCONNECTION_H #define HTTPCONNECTION_H #include <unistd ...

  4. 自己动手写http服务器——线程池(一)

    创建一个线程池,每有一个连接对象就将它添加到工作队列中,线程池中的线程通过竞争来取得任务并执行它(它是通过信号量实现的). //filename threadpool.h #ifndef THREAD ...

  5. 自己动手写RTP服务器——传输所有格式的视频

    上一篇文章我们介绍了如何用一个简单的UDP socket搭建一个RTP服务器.我把这份80行的代码呈现到客户面前的时候,就有人不满意了. 还有人在参考的时候会问:“楼主你的TS格式的文件是哪里来的?应 ...

  6. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  7. Git服务器、http协议及XCode

    本来费了老鼻子牛劲搭好了SVN,可以通过web进行访问,也弄好了eclipse和XCode,结果几个开发的同事说要上git,悲了个催,又开始折腾git. 因为公司只有一个公网的http出口,因此开始了 ...

  8. Ubuntu搭建NFS服务器,NFS协议详细分析

    目录 1. Ubuntu搭建NFS服务器 2. NFS协议分析 2.1 实验拓扑: 2.2 在kali抓包分析 1. Ubuntu搭建NFS服务器 ​ NFS(Network FileSystem,网 ...

  9. JavaSE 手写 Web 服务器(一)

    原文地址:JavaSE 手写 Web 服务器(一) 博客地址:http://www.extlight.com 一.背景 某日,在 Java 技术群中看到网友讨论 tomcat 容器相关内容,然后想到自 ...

随机推荐

  1. 【leetcode】Regular Expression Matching

    Regular Expression Matching Implement regular expression matching with support for '.' and '*'. '.' ...

  2. centos7删除已经安装的docker

    centos下可以使用yum来删除docker. 列出docker包的具体的名字. $ yum list installed | grep docker docker-engine.x86_64 -0 ...

  3. c++ 文件utf-8格式

    #include <stdio.h> int i = 0; while (i < 20) {    i++;    WriteLog("d:\\log.txt", ...

  4. 3.js模式-策略模式

    1. 策略模式 策略模式定义一系列的算法,把它们封装起来,并且可以互相替换. var strategies = { isNonEmpty: function(value,errMsg){ if(val ...

  5. 使用ssh正向连接、反向连接、做socks代理的方法

     ssh -L 219.143.16.157:58080:172.21.163.32:8080 用户名@localhost -p 10142  在 219.143.16.157机器执行   将ssh隧 ...

  6. OKhttp的封装(上)

    自从介绍了OKhttp3的一些基本使用之后,又偷了下懒,所以它的续篇被搁置了一段时间,现在补充. OKhttpManager.Class  请求工具类 package com.example.admi ...

  7. 【hadoop2.6.0】数据丢失问题解决

    想自己走一遍从代码到运行的流程,结果各种错,郁闷啊. 问题① http://localhost:50070/ 里面一进去就告诉我块丢了.... 解决: bin/hadoop fsck -delete ...

  8. 【mongo】pymongo通过_id删除数据

    来源:http://www.educity.cn/wenda/361741.html pymongo 根据 objectId _id 来删除数据想要删除数据,根据_id ,是最靠谱的,具体方法因为 _ ...

  9. ASP.NET 下载文件并继续执行JS解决方法

    需求说明:当用户点击按钮时使当前按钮为不可用,并打开新页面,关闭新页面时,按钮变为可用.并且如果不关闭新页面,当前按钮过10秒钟自动变为可用. 包含3个页面: 一.按钮页 前台代码:当刷新后采用js进 ...

  10. .net 获取https页面的信息 在iis7.5服务器上不管用

    让我纠结了一天多的问题,给大家看下,有相同情况的可以不用浪费时间了,本人当时找了好半天都没找到什么有用的信息,项目在本地没有问题,但部署在服务器后,获取不到https页面的信息,加入下面的代码就可以了 ...