这段时间做实时视频的网页直播遇到了很多困难。
开始时,迫于项目时间的压力,觉得没有足够的时间学习和分析如何将实时视频发送到RTMP流媒体服务器作为实时流,只好使用最粗糙的做法是:先把获取到的 实时视频以RTP包的形式 发送给本机,然后本机程序中调用ffmpeg将接收到的RTP包 以RTMP的形式转发到Red5,最后,从网页上获取播放列表,播放实时视频。
这种做法中存在很多问题:(1)多了一层rtp包到rtmp服务器的转发,浪费很多处理器的时间。(2)多了一层转发,系统稳定性很有问题。在视频流转发 了一定时间后,ffmpeg会奇怪地停止转发,原因不明。(3)ffmpeg的视频流播放控制难以实现。在网页上停止播放和继续播放视频时,既要控制发送 RTP包,又要控制RTMP包,很麻烦。
后来,分析了一下ffmpeg的源代码,发现FFmpeg中对RTMP的支持部分就是使用了RTMPDump中的librtmp。于是,我就打算直接使用librtmp与Red5建立rtmp连接,将实时视频直接发到Red5。
最近过年,在家里闲着,就认真研究一下如何使用librtmp直接将实时视频发送到Red5。我们首先要做的就是编译出librtmp的动态库和静态库。
RTMPDump项目官方网站在:http://rtmpdump.mplayerhq.hu/ 。对RTMP协议的实现在其中librtmp中。这是一个匈牙利人在2009年,Adobe公司还没有公开RTMP协议的情况下对RTMP协议的实现得。 官方网站中只提供了程序源代码和动态链接库(dll),要在开发中方便地使用RTMPDump,还需要自己编译它的静态库(lib)。
==> 编译librtmp静态库
从官方网站http://rtmpdump.mplayerhq.hu/ 下载RTMPDump源代码。
要编译librtmp,还需要另外3个库:zlib、OpenSSL、PolarSSL。
zlib是用于数据压缩的函数库,数据压缩效果比较好,早在1995年就发布了第一版,目前仅支持LZ77变种算法、DEFLATE算法。(http://www.zlib.net/)。
OpenSSL和PolarSSL 是对SSL(Security Socket Layer,加密套接字协议层)的实现。(http://www.openssl.org/ http://polarssl.org/)。
(1)使用VC++6.0新建一个静态库工程,命名为librtmp,如下图所示:
(2)把RTMPDump源代码目录下的librtmp目录下的所有文件 复制到工程目录librtmp\下,并在VC++6.0中的Source Files和Header Files文件夹中添加librtmp相应的文件,如下图所示:
(3)下载zlib开发包 http://download.csdn.net/source/3013660。把其中的zdll.lib、zlib.def、zlib.h、zconf.h放到新建的工程目录librtmp\下。
(4)下载openssl开发包 http://download.csdn.net/source/3013684。 把其中的libeay32.lib、ssleay32.lib 及openssl文件夹 复制到工程目录librtmp\下,并在VC++6.0的“工具”->“选项”->“目录”-> “ Include files ”中添加当前的工程目录librtmp\。如下图所示:
(5) 下载PolarSSL源代码 http://download.csdn.net/source/3013696。解压出来,用VC++6.0打开\visualc\polarssl.dsw ,可以编译出静态库(polarssl.lib)。然后将头文件所在的文件夹polarssl\ 和polarssl.lib复制到工程目录librtmp\下。
(6)编译静态库工程,这时会在多个文件中出现这样一个错误: error C2065: '__FUNCTION__' : undeclared identifier 。解决办法是,在存在这个错误的.c文件的中添加一个宏定义:#define __FUNCTION__ "" 。问题就解决了。再编译工程即可得到librtmp.lib,如下图所示:
(7)但是,这样编译出来的librtmp.lib在使用的时候会出现很多个外部符号未定义的错误。如下图所示:
这是librtmp的条件编译导致的问题,解决方法是:在rtmp_sys.h中把代码:
#ifdef _XBOX
#include <xtl.h>
#include <winsockx.h>
#define snprintf _snprintf
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define vsnprintf _vsnprintf
#else /* !_XBOX */
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
改为
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define vsnprintf _vsnprintf
然后,删除rtmp.c中的如下代码:
#ifdef _DEBUG
fwrite(buf, 1, len, netstackdump);
#endif
和
#ifdef _DEBUG
extern FILE *netstackdump;
extern FILE *netstackdump_read;
#endif
和
#ifdef _DEBUG
fwrite(ptr, 1, nBytes, netstackdump_read);
#endif
(8)编译rtmp.c即可得到librtmp.lib
我已经将rtmpdump编译好的静态库、动态库以及源代码打成一个包,放到 http://download.csdn.net/source/3033310。如果不想自己编译,可以从这里下载。也可以从javaeye博客中下载:http://c1zhao.javaeye.com/blog/901900。