使用ffmpeg+crtmpserver搭建文件的伪直播

Tutorial: How to "live stream" a media file

如何"直播"一个媒体文件

I have tried a while to setup a free (open source etc.) live streaming solution 


which is able to stream “anything” to a flash frontend. The basic idea is to 


stream TV from v4l2 (and similar), but I also wanted to stream files (movies). 


I found that most tutorials only show how to setup the streaming or only show 


how to get a flash player up and running. The whole roundtrip is not really described 


and has its own difficulties. This tutorial describes the whole “roundtrip” 


from a media file on your disk to displaying it in a browser. I know that 


there are easier ways to send a media file to some player in a browser and I also know 


that playing a file is not really live streaming. (This is why I have put it in double quotes.) 


However, it shows the principle and it might be easier to set this up as a first step.


本文讲解如何搭建一个媒体文件(如电影)在flash前端直播的解决方案,


并详述了整个过程:


  从硬盘上的媒体文件到在浏览器中播放;

Maybe important to note that this is targeted to a Linux server, I don’t know how and 


if it works with other operating systems.


本文是基干Linux服务器实现的;

一、概览 Overview


The whole roundtrip looks as follows:


整个流程如下:


  file → ffmpeg → crtmpserver → jwplayer/haxe ( → apache)

ffpmeg : 


  is used to convert the input to h264/aac in an MPEG-TS container 


  and sends it to crtmpserver using UDP


  ffmpeg将输入转换成以MPEG-TS封装的H264/aac格式,并通过UDP协议发送到crtmpserver;

crtmpserver :


  acts as the RTMP server (you might have guessed this)


  crtmpserver作为RTMP server;

jwplayer :


  can then play the stream. With using haXe, it is possible to create your own players


  jwplayer可以用来播放流。


  也可以使用haXe, 来创建自己的播放器;


  


apache :


  is the webserver


  Apache是Webserver;

二、ffmpeg


The following command line converts <filename-of-movie> to h264/aac, puts it into an TS container 


and sends it using UDP. (I have split this on several lines for readability.)


下面的命令行将<filename-of-movie>转码成h264/aac,并封装进TS协议,并通过UDP发送;

> ffmpeg -i "<filename-of-movie>" -re 


         -vcodec libx264 -vpre default -vpre baseline 


         -b 500000 -s 320x180 -strict experimental -g 25 -me_method zero 


         -acodec aac -ab 96000 -ar 48000 -ac 2 -vbsf h264_mp4toannexb 


         -f mpegts udp://127.0.0.1:10000?pkt_size=1316


This command line simulates a live stream. It does not wait for anything to receive the stream, 


it just pumps the data through port 10000 at the speed the movie should play. 


(You should see some ffmpeg output about frames, fps etc.) This is achieved by the ”-re” 


which makes ffmpeg to read the data with (maximum) the framerate which the movie has. 


In addition, the UDP protocol does not wait for the answer of any receiver like TCP would do. 


(As far as I understand.)


这个命令行模仿了一个直播流;它不用等待流的接收端;


它通过端口10000以电影播放的速度吐出数据,这是通过参数“-re”实现的;


它指示了ffmpeg以电影的最大帧率读取数据;


另外,UDP不像TCP,它不用等待接收端的应答;

In my tests, <filename-of-movie> always is in an AVI container, with DivX/XviD and MP3. 


It should, however, work as well with any other movie formats ffmpeg understands properly.


在我的测试中,<filename-of-movie>是以DivX/XviD 和 MP3编码,并以AVI格式封装;


ffmpeg也支持很多其它的文件格式;

The ffmpeg command line above was taken from the wowza documentation. 


I have only experimented a bit to enhance the performance. 


So I have changed the ”-g 60” to ”-g 25” as it seems more appropriate to me 


and added the ”-me_method zero” as it was considered in the ffmpeg documentation as being faster. 


The ffmpeg documentation also mentions using ”-intra”, but this did not work. 


The stream never played in the flash player. (I don't have an explanation for that.)


上面的ffmpeg命令行是我从wowza 的文档中看到的,我做了我所知道的性能提升;


如将 “-g 60 ”改成 “-g 25”等;


更多的可以去看ffmpeg文档

三、crtmpserver


I have checked out and compiled the sources from svn as described on the crtmpserver website. 


After that, the server can be run. I have tried the same with other free rtmp servers 


and it did not work. E.g. I did never succeed with compiling red5. With crtmpserver, 


it just worked. It is also not that complicated to understand the coding. 


(Even if there could be some more comments…)


下载并编译crtmpserver后,就可以启动运行了;

I.e. just get and compile crtmpserver as described in the crtmpserver documentation.

To enable it to receive an UDP TS stream, the following needs to be added to the file 


crtmpserver/builders/cmake/crtmpserver/crtmpserver.lua


为了能接收UDP TS 流,需要对crtmpserver/builders/cmake/crtmpserver/crtmpserver.lua添加


如下配置项:


    {


            ip="0.0.0.0",


            port=10000,


            protocol="inboundUdpTs"


    }, 


This should be added to the acceptors part of the flvplayback application. 


This tells crtmpserver that there should be a stream in a TS container sent via UDP on port 10000. 


(See also rtmpserver.lua for the whole file.)


这个配置项需要添加在“flvplayback”应用的接收器部分;


它告诉crtmpserver需要接收通过UDP向端口10000发送TS 流;

After changing this and running the ffmpeg command line above, run the server with the config file 


as argument, like


修改完成后,启动crtmpserver:

> cd crtmpserver/builders/cmake


> ./crtmpserver/crtmpserver crtmpserver/crtmpserver.lua


(I don't know yet why it only works from the cmake directory. 


Running from the crtmpserver directory itself did not work for me.)

UPDATE: This happens because cmake is used for building the development version of the server. 


It has all the binaries/libraries paths hardcoded in by the GCC linker. 


This is why you can't move around any binaries/libraries. If the production version is required 


(independent paths, maximum optimization, etc), make or packing scripts should be used instead.


The documentation about installing/compiling the server will be changed to reflect that.


更正:


为什么要在cmake目录下启动程序,是因为使用的是server的开发版;


它对应的所有 binaries/libraries的路径都是对GCC固定的;


因此,不能移动任何 binaries/bibraries;


产品版本则没有这样的限制;

I keep having the issue that crtmpserver does not start up when I try it the first time 


after booting the machine. This is because there is another rtmp server (red5) installed 


as well. This needs to be stopped first, at least as long as it runs on the same port. 


I.e. all other rtmp servers should be stopped. On my sytsem, this is done like this:


如果服务器上启动了其它的RTMP服务,crtmpserver将不能正常工作,要先关掉其它的RTMP服务;

> /etc/rc2.d/S20red5-server stop

Apparently, this needs to be done as root.

Apart from some (maybe a lot) warnings, the crtmpserver output should contain something like


  ...basetsappprotocolhandler.cpp:49 Stream available (1): ts_2_257_256


Remember the “ts_2_257_256”, or whatever it exactly looks like. This is the name of the 


stream which is later needed in the flash player. The name might depend on the ffmpeg 


version and on the crtmpserver config and version. 


Generally, it has the format “ts_<id>_<audio-pid>_<video-pid>”.


启动后,crtmpserver会有一些信息提示和警告;并且包含有如下的信息:


  ...basetsappprotocolhandler.cpp:49 Stream available (1): ts_2_257_256


需要记下“ts_2_257_256”,


因为这个流的名字要用在后面的flash播放器;


这个名字依据ffmpeg和crtmpserver版本的不同,可能也会有差异;


通常,它的格式是:


  ts_<id>_<audio-pid>_<video-pid>

crtmpserver now sends the stream as crtmpserver://<your-ip>/flvplayback/ts_2_257_256. 


This URI can be used to point a flash player to the stream. I have successfully done 


this with a very simple player written in Haxe and with JWPlayer as well.


这时,crtmpserver就可以以URI“crtmpserver://<your-ip>/flvplayback/ts_2_257_256”发送流了;


这个URI用在flash播放器的流指定;


播放器可以通过Haxe和JWPlayer来实现;

But first, we need a webserver. Playing the streams from an embedded player using local 


files seems to have some security issues, so flash does not allow it easily.


但在实现播放之前,需要有一个webserver; 


因为使用本地文件实现的内嵌播放器来播放流有一些安全问题,


所以flash不提倡这么做;

四、apache


There's not much to say here. Install apache and find where the content needs to go. 


On my system, this is /var/www, which I believe is the default.


这个没能什么好说的,直接安装一个apache,并使用它的默认目录/var/www

五、JWPlayer


The JWPlayer is a full-blown Flash video player. You can get it from here: 


JWPlayer是一个完整的Flash视频播放器,可以在这下载:


  http://www.longtailvideo.com/players/jw-flv-player/

Copy the file player.swf in a directory which can be reached by the web server 


(e.g. a subdirectory of /var/www) and embed it into an html file as described 


on the longtailvideo website. Alternatively, just use my test_jwplayer.html and 


put it in the same directory as player.swf. When using it, you need to change this part:


  streamer:'rtmp://zeus/flvplayback',file:'ts_2_257_256'


“zeus” is the name of my server, you need to change it to the name of your server. 


If unsure or it does not work, just use 127.0.0.1. Apparently, it will only work locally then…


You might also need to change the stream name (ts_2_257_256) to the one from crtmpserver's output.


将文件player.swf复制到webserver的指定目录(如/var/www), 并将它嵌入到一个HTML页面中;


也可以简单地使用test_jwplayer.html并将它和player.swf放在同一个目录下,


然后修改流地址:


  streamer:'rtmp://zeus/flvplayback',file:'ts_2_257_256'


其中:


"zeus"是服务器域名,要改成你自己的域名或IP;

test_jwplayer.html


<html>                                                                                 


<head>                                                                                 


<script src="/jwplayer/jwplayer.js"></script>                                          


</head>                                                                                


<body>                                                                                 


<div id='my-video'></div> <script type='text/javascript'>                              


  jwplayer('my-video').setup({                                                         


  file:'rtmp://192.168.1.80/live/ts_2_257_256',                                          


  width: '624',                                                                        


  height: '352'     });                                                                


</script>                                                                              


</body>                                                                                


</html>

Now make sure that ffmpeg and crtmpserver are running. Open a browser and type an url like


    http://zeus/thorsten/jwplayer/test_jwplayer.html


Apparently, you need to change “zeus” to your machine's name or try 127.0.0.1. 


The rest is the path to the test_jwplayer.html file, which will also be different on your box.


After a few seconds of buffering, you should be able to watch the movie. 


It might not have the correct aspect ratio and it also might be a bit choppy, 


but it works in principle. 


(If it does not, restart ffmpeg and crtmpserver and reload the page.)


将ffmpeg和crtmpserver都启动后,打开浏览器并输入地址:


  http://zeus/thorsten/jwplayer/test_jwplayer.html


缓冲后,就可以观看电影了;


可能分辨率会有些不对或卡顿,但原则上已经能工作了;

六、haXe


It seems that it can do even more, but for me, haXe (http://haxe.org/) is a free 


(open source) alternative to “develop flash”. I.e. you can write actionscript-like 


programs and compile them to .swf format. (I sometimes need to do things myself to 


really understand them.) I like this especially because I could write my own little 


flash stream player which I could experiment with. In theory, this could also be done 


with JWPlayer as this is open source as well. However, JWPlayer source is a bit complicated 


and I am not sure if you can compile it without the commercial flash development kit.


实际上,haXe能做很多事,但对于我来说,haXe(http://haxe.org/) 是一个免费开源的选择来开发flash;


例如,可能编写类actionscript程序并编译生成.swf格式;


更有用的是,可能通过它来写一个很小的flash流播放器;

If you want to try the haXe player, install haxe (at least on debian, there is a package). 


Then create a file like Test.hx. Open it in an editor and change the appearances of “zeus” 


to your own server's name and change “ts_2_257_256” to the correct stream name. 


(I know that hardcoding these names is not a programming style which deserves 


to be called “style”, but again, it shows the principle.)


如果想试试haXe播放器,


需要先安装haxe,


然后创建一个文件,如Test.hx; 


打开一个编辑器并修改域名"zeus"和"ts_2_257_256"成正确值 ;

The file can then be compiled using the following command line from the directory 


where Test.hx sits in.


使用下面的命令进行编译;

> haxe -swf9 test.swf -main Test

This results in the file test.swf. This can then be embedded as any other flash player into a website, 


see e.g. test_haxe.html.


结果文件test.swf就可以嵌入到的页面中了;

Put test.swf and test_haxe.html in a directory accessible by the web server. 


Open a browser and point it to the test_haxe.html page. Again, the movie should come up 


after a few seconds. (…if crtmpserver and ffmpeg are still running)


将test.swf和test_haxe.html放在同一个目录并在浏览器打开网址,就可看到流了;

上一篇:基于索引的MySQL优化


下一篇:Android加载图片OOM错误解决方式