ffmpeg,rtmpdump和nginx rtmp實現錄屏,直播和錄製

ffmpeg,rtmpdump和nginx rtmp實現錄屏,直播和錄製

2014年 四月 19日 週六 | tags: ffmpegrtmprtmpdumpnginx, -- (permalink)html

公司最近在作視頻直播的項目,我這裏分配到對直播的視頻進行錄製,錄製的方式是經過rtmpdump對rtmp的視頻流進行錄製python

置的知識

  • ffmpeg: 用於實現把錄屏工具發出的視頻和音頻流,轉換成咱們須要的格式,而後發送到rtmp中轉服務器上。
  • rtmpdump: 用於實現視頻的錄製,從rtmp的中轉服務器接受到視頻流,並把視頻流保存成flv文件
  • nginx-rtmp-module: 用戶rtmp中轉服務,雖然他能夠作不少功能,可是我這裏只是使用了這一個
  • screen capture: windows下的開源屏幕錄製工具

首先,咱們安裝ffmpeg, rtmpdump和nginx-rtmp-module:linux

這裏我使用的ffmpegrtmpdump都是windows版的,雖然和linux下的有所區別,可是在這裏並無使用到這些區別。nginx

nginx是在windows下的虛擬機中的linux下編譯的,由於windows編譯這玩意是在太麻煩了,我實在不想編譯第二次。git

ffmpeg 的簡單使用

首先咱們須要查看如下咱們的本身上的設備信息,在安裝了screen capture recorder以後就可使用下面的命令:github

ffmpeg -list_devices true -f dshow -i dummy 

輸出以下結果:shell

ffmpeg version N-63013-g4cdea92 Copyright (c) 2000-2014 the FFmpeg developers
 built on May 6 2014 22:09:20 with gcc 4.8.2 (GCC)  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-decklink --enable-zlib  libavutil 52. 81.100 / 52. 81.100  libavcodec 55. 60.103 / 55. 60.103  libavformat 55. 37.102 / 55. 37.102  libavdevice 55. 13.101 / 55. 13.101  libavfilter 4. 5.100 / 4. 5.100  libswscale 2. 6.100 / 2. 6.100  libswresample 0. 18.100 / 0. 18.100  libpostproc 52. 3.100 / 52. 3.100 [dshow @ 00000000029f0e20] DirectShow video devices [dshow @ 00000000029f0e20] "screen-capture-recorder" [dshow @ 00000000029f0e20] DirectShow audio devices [dshow @ 00000000029f0e20] "FrontMic (Realtek High Definiti" [dshow @ 00000000029f0e20] "virtual-audio-capturer" [dshow @ 00000000029f0e20] "Realtek Digital Input (Realtek " dummy: Immediate exit requested 

DirectShow video devices下面的是視頻設備,DirectShow audio devices是音頻設備,ffmpeg錄製就須要從這些設備上獲得視頻和音頻的流.ubuntu

下面咱們看如下ffmpeg若是從這些設備中錄製視頻。windows

ffmpeg -f dshow -i video="screen-capture-recorder":audio="FrontMic (Realtek High Definiti" test.avi 

這楊就能夠把錄屏和經過麥克風說話的聲音都錄下來,保存成avii,固然這裏也可使用更加豐富的參數來調整視頻,使視頻更清醒,聲音也更響亮,不過這些都不在本文的討論範圍,因此就不在這裏多少,有興趣的華能夠去http://ffmpeg.org/documentation.html上詳細的查看。服務器

固然咱們是要使用rtmp協議的,因此這裏就須要把視頻流發送到rtmp服務端去,以下命令:

ffmpeg -f dshow -i video="screen-capture-recorder":audio="FrontMic (Realtek High Definiti" -f flv rtmp://192.168.56.101/live/test 

這裏只說明一點,若是是發送到rtmp協議的話是須要加上-f flv這個參數的,若是不加會報錯,這樣就算是把錄製的視頻流發送到了rtmp服務端,固然我這裏的nginx服務器要配置好而且啓動了,不然仍是會報錯的。

nginx rtmp module

安裝

在編譯安裝模塊的時候須要說明一點,若是在 configure的時候出現了openssl的錯誤,請安裝libssl-dev.

ubuntu下: sudo apt-get install libssl-dev

./configure --prefix=/usr/local/rtmp-nginx --without-http_rewrite_module make make install 

配置

下面是個人配置:

rtmp { server { listen 1935; chunk_size 4096; application live { live on; } } } http { server { listen 8080; location /stat { rtmp_stat all; rtmp_stat_stylesheet stat.xsl; } location /stat.xsl { root stat; } location / { root /publisher; } } } 

咱們只須要加入一個關於rtmp協議的塊和在http協議下加入一個server塊,用來配置統計星系等,這就是最簡單的配置,這樣已經快而已完成咱們例子中的功能,若是須要更詳細的,請查看NGINX-based Media Streaming Server

RTMPDump

RTMPDump 是一位匈牙利大神在Adobe未公開RTMP協議的條件下,寫出了針對RTMP協議的客戶端程序。

在這裏rtmpdump的使用是很簡單的,固然rtmpdump其實也是有一些問題的,咱們先來看看若是使用rtmpdump錄製視頻流

使用

rtmpdump -v -m 0 -r rtmp://192.168.56.101/live/test -o test.flv 

上面的命令就是錄製rtmp協議的視頻流的命令,下面簡單說明一下:

  • -v:是說明視頻流是一個直播流
  • -m:是超時時間,0表示不超時
  • -r:表示rtmp的url

rtmpdump的使用就是如此的簡單

問題

我在實際的使用過程當中遇到了一個疑問,就是當視頻的發送端崩潰或者死機,形成視頻流中斷,再次發送的時候會發送一個新的視頻流,可是rtmpdump沒法分辨這個新視頻流,他會把這個視頻流繼續添加在文件後面,保存成一個文件而不是一個新的視頻文件。相反對於網絡中斷而視頻的發送端沒有中斷這種問題是能夠處理的,不過中間可能會出現畫面定在網絡中斷的那個時間點上,知道網絡再次恢復。

不過這個問題是能夠經過程序的方式解決的,在python的庫中有一個flvlib的庫能夠處理這類問題,請看下面的代碼:

def split_flv(f): if isinstance(f, str): f = open(f, 'rb') flv = tags.FLV(f) path, ext = os.path.splitext(f.name) output_template = path + "_%d" + ext input_flv = open(f.name, 'rb') output_flv = None split_index = 0; filelist = [] for tag in flv.iter_tags(): if isinstance(tag, tags.ScriptTag) and tag.timestamp == 0: if output_flv: output_flv.close() output_flv = open(output_template % split_index, 'wb') filelist.append(output_flv.name) split_index += 1 output_flv.write(tags.create_flv_header(flv.has_audio, flv.has_video)) output_flv.write(tags.create_script_tag('onMetaData', tag.variable, tag.timestamp)) elif isinstance(tag, tags.VideoTag): input_flv.seek(tag.offset + 11) data = input_flv.read(tag.size) newtag = tags.create_flv_tag(9, data, tag.timestamp) output_flv.write(newtag) elif isinstance(tag, tags.AudioTag): input_flv.seek(tag.offset + 11) data = input_flv.read(tag.size) newtag = tags.create_flv_tag(8, data, tag.timestamp) output_flv.write(newtag) output_flv.close() input_flv.close() return filelist def concat_flv(filelist, src_file): tempf = tempfile.TemporaryFile('w+b', delete=False) tempf.writelines(["file '%s'\n" % f for f in filelist]) tempf.close() curdir = os.path.dirname(__file__) cmd = 'ffmpeg' if platform.system() == 'Windows': cmd = '"' + os.path.join(curdir, 'rtmpdump/ffmpeg.exe') + '"' src_file_name, src_file_ext = os.path.splitext(src_file) output_file = src_file_name + "_concat" + src_file_ext cmd += ' -f concat -i ' + tempf.name + ' -y -c copy ' + output_file p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = p.communicate() logger.info(output[0]) return (output_file, None) 

這兩段代碼就是先把視頻分割開,而後在鏈接到一塊兒生成一個新文件。

總結

這是我解決直播的一個測試方案,由於公司的直播系統尚未起來,因此我採用了這樣一中思路模擬直播測試個人錄製系統。

相關文章
相關標籤/搜索