使用nginx搭建音視頻點播服務器


1 音視頻技術

1.1 流媒體

  在網絡上傳輸音、視頻等多媒體信息,主要有下載和流式傳輸兩種方案。下載的方式對於體積較大的音、視頻數據而言,在使用前下載整個媒體文件耗時很大;流媒體(streaming media)傳輸提供了一種低延時的方式來避免這個問題,流媒體技術是指將多媒體數據壓縮后,經過網絡分段發送,在網上即時傳輸音、視頻數據供用戶播放的一種技術。

1.2 點播與直播

  點播(VOD,video on demand)即根據用戶需求播放,音視頻內容一般已經存放在服務器上了,不同於先下載再播放,點播要求即點即播,各大音視頻網站(喜馬拉雅、優酷、愛奇藝等)提供的服務就是VOD服務。
  直播(Live)需要對音視頻內容實時錄制,在錄制同時以“流”的形式推送到服務器,服務器在收到用戶的播放請求后,會將媒體流傳輸到用戶的播放器進行播放,並對延遲有較高的要求,各大直播平台(斗魚、虎牙等)提供的服務就是直播服務。

1.3 HLS流媒體協議

  HLS(HTTP Live Streaming)自適應碼率流媒體傳輸協議,來自Apple公司,該協議基於Http協議,HLS誕生之初旨在能夠從iPhone中刪除flash,如今已成為使用最廣泛的協議。HLS的優缺點也比較明顯。

HLS的優點:
  Html5能夠直接支持HLS,有瀏覽器就能播放,不需要安裝額外的app,不用考慮防火牆或者代理問題;HLS也支持最新的H.265編解碼器,H.265編碼的質量要比H.264高很多。
HLS的缺點:
  因為HLS基本是采用了點播切片的方式實現的直播,在直播上相對於其它協議有較高的延遲(5~8秒延遲)。

除了HLS協議之外,相關的協議還有RTP/RTCP、RTSP、RTMP、MSS、DASH、HDS、WEBRTC、RIST、SRT等……它們都有各自的優缺點。

HLS的原理:
  首先將一個完整音視頻分成多個ts格式音視頻文件切片,並生成m3u8索引文件,用戶下載m3u8索引文件,通過m3u8文件中每段ts切片的索引地址來播放具體的ts切片,在m3u8中可以指定播放相關的參數。

1.4 CDN

  CDN(Content Delivery Network)內容分發網絡,是為了改善網絡服務質量而產生的,它是構建在現有網絡基礎之上的智能虛擬網絡,通過負載均衡、內容分發、調度等完成資源就近獲取的目標。
  CDN的基本原理是采用各種緩存服務器,將這些緩存服務器分布到用戶訪問相對集中的地區或網絡中,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的工作正常的緩存服務器上,由緩存服務器直接響應用戶請求,使用戶就近獲取所需內容,降低網絡擁塞,提高用戶訪問響應速度和命中率,CDN網絡的誕生大大地改善了互聯網的服務質量。
  在互聯網上的流媒體服務為了實現更優質的用戶體驗,一般都需要經過CDN節點進行內容分發。點播、直播技術的選擇需要考慮大環境下主流CDN服務供應商能夠提供的服務支持,各家對協議的支持也不一樣(像阿里雲CDN支持RTMP輸入,RTMP、FLV、HLS輸出),點播需要考慮輸出,直播需要考慮輸入與輸出兩端。

2 搭建點播服務(音視頻同理)

2.1 nginx服務器

nginx是一個代理服務器,首先需要在Linux上搭建nginx服務,具體的流程可以參考nginx的安裝流程[1],搭建視頻點播服務器會用到nginx-vod-module模塊,按照安裝流程添加該模塊到nginx中,搭建點播服務使用的具體環境如下:

系統版本:CentOS Linux release 7.9 2009(Core)
nginx版本:1.20.1
nginx-vod-module版本:1.28

2.2 nginx-vod-module模塊

nginx-vod-module模塊是基於nginx來提供VOD(video on demand)服務的第三方模塊,它支持基於DASH、HDS、HLS、MSS的點播服務搭建。

nginx-vod-module下載地址:https://github.com/kaltura/nginx-vod-module/archive/refs/tags/1.28.tar.gz

在nginx進行安裝配置的過程中,需要使用--add-module=選項來添加第三方模塊一起進行編譯,相關的步驟可以參考模塊的github網址:

nginx-vod-module的github網址:https://github.com/kaltura/nginx-vod-module

在配置nginx進行編譯的時候使用的配置參數如下:

./configure --prefix=/web/webserver/nginx-vod-hls --with-http_stub_status_module --with-http_gzip_static_module --with-http_gunzip_module --with-file-aio --with-threads --with-cc-opt="-O3" --with-http_ssl_module --with-openssl-opt=enable --with-http_mp4_module --with-stream --add-module=../nginx-vod-module-master

配置中主要是附加了一些常規模塊,打開了一些配置開關,其中:

--with-file-aio 異步io支持,強烈推薦,只在local、mapped模式下
--with-threads (nginx 1.7.11+) 支持使用線程池異步打開文件(要求在nginx.conf中配置vod_open_file_thread_pool),只在local、mapped模式下
--with-cc-opt="-O3" 附加編譯器優化,減少視頻解析和幀處理的耗時

配置、編譯、安裝都完成之后,即可在nginx的配置文件中使用nginx-vod-module模塊提供的關鍵字了。

2.3 配置nginx點播服務

2.3.1 local模式

2.3.1.1 常規配置

在nginx的配置文件中,添加對應的location配置:

location /vod {
    vod hls; # 協議使用hls模式
    vod_mode local; # 訪問模式指定為local模式
    
    vod_align_segments_to_key_frames on; # 每個切片以關鍵幀開頭
    vod_manifest_segment_durations_mode accurate; # 精確顯示每個切片的長度
    
    # 解決瀏覽器跨域問題
    add_header Access-Control-Allow-Headers '*';
    add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
    add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
    add_header Access-Control-Allow-Origin '*';

    alias /media; # 視頻文件路徑
}

nginx.conf文件修改后,nginx需要reload才能生效配置。

在服務器上對應的視頻文件目錄結構:

/media/example0001.mp4

URL播放地址(假設nginx配置在ip為192.168.192.128的地址上):

http://192.168.192.128/vod/example0001.mp4/index.m3u8

使用相應的html5播放器或者本地播放器打開,即可觀看該地址的視頻點播。若使用本地播放器,推薦使用VLC media player

nginx-vod-module會根據URL動態生成對應的m3u8文件,其內容如下:

#EXTM3U
#EXT-X-TARGETDURATION:17
#EXT-X-ALLOW-CACHE:YES
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:10.000,
http://192.168.192.128/vod/example0001.mp4/seg-1-v1-a1.ts
#EXTINF:10.000,
http://192.168.192.128/vod/example0001.mp4/seg-2-v1-a1.ts
#EXTINF:10.000,
http://192.168.192.128/vod/example0001.mp4/seg-3-v1-a1.ts
……
……
……
#EXTINF:7.760,
http://192.168.192.128/vod/example0001.mp4/seg-347-v1-a1.ts
#EXT-X-ENDLIST

通過對nginx進行配置可以控制m3u8文件的生成規則,以此來控制切片的大小、狀態等播放相關的屬性,具體可以查看nginx-vod-module模塊的文檔[2]

2.3.1.2 local模式下的多碼率自適應

使用常規配置,僅更改訪問的URL播放地址即可支持多碼率自適應功能,HLS根據用戶當前可用帶寬的大小自適應匹配對應碼率的視頻。

在服務器上對應的視頻文件目錄結構(后綴low表示同一視頻的低清晰度版本):

/media/example0001.mp4
/media/example0001_low.mp4

URL播放地址:

http://192.168.192.128/vod/example,0001,0001_low,.mp4.urlset/master.m3u8

多碼率自適應其實是多個URL組合的結構,上述master.m3u8表示以下2個index.m3u8的組合:

http://192.168.192.128/vod/example0001.mp4/index.m3u8
http://192.168.192.128/vod/example0001_low.mp4/index.m3u8

nginx-vod-module會根據master指定的多個視頻自動計算配置適合的帶寬,master.m3u8文件的內容如下:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=613135,RESOLUTION=1280x720,FRAME-RATE=25.000,CODECS="avc1.640029,mp4a.40.2"
http://192.168.192.128/vod_json/mapped.json/index-f1-v1-a1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=226233,RESOLUTION=760x428,FRAME-RATE=25.000,CODECS="avc1.42c01e,mp4a.40.2"
http://192.168.192.128/vod_json/mapped.json/index-f2-v1-a1.m3u8

#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=193615,RESOLUTION=1280x720,CODECS="avc1.640029",URI="http://192.168.192.128/vod_json/mapped.json/iframes-f1-v1-a1.m3u8"
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=58630,RESOLUTION=760x428,CODECS="avc1.42c01e",URI="http://192.168.192.128/vod_json/mapped.json/iframes-f2-v1-a1.m3u8"

index后面跟隨的v1表示第一條視頻軌道,a1表示第一條音軌。

2.3.2 mapped模式

  mapped模式使用json文件來對視頻進行配置,可以把附加在URL中的各種參數放在對應的json文件里進行配置。

2.3.2.1 常規配置

在nginx的配置文件中,添加對應的location配置:

location /vod_json {
    vod hls; # 協議使用hls模
    vod_mode mapped; # 訪問模式指定為mapped模式

    vod_align_segments_to_key_frames on; # 每個切片以關鍵幀開頭
    #vod_manifest_segment_durations_mode accurate; # 精確顯示每個切片的長度
    
    # 解決瀏覽器跨域問
    add_header Access-Control-Allow-Headers '*';
    add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
    add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
    add_header Access-Control-Allow-Origin '*';

    alias /media/cjcwgl; # 視頻文件路徑
}

發現一個Bug:在mapped模式下配置vod_manifest_segment_durations_mode參數會導致m3u8的最后一個切片的#EXTINF時長異常地長。

在服務器上對應的視頻文件目錄結構:

/media/cjcwgl/hdh/cwgl0101.mp4

json文件路徑為:

/media/cjcwgl/simple.json

simple.json文件的內容:

{
    "sequences": [
        {
            "clips": [
                {
                    "type": "source",
                    "path": "/media/cjcwgl/hdh/cwgl0101.mp4"
                }
            ]
        }
    ]
}

URL播放地址:

http://192.168.192.128/vod_json/simple.json/index.m3u8

2.3.2.2 mapped模式下的多碼率自適應

在服務器上對應的視頻文件目錄結構(hdh目錄下為高清版本,hdk目錄下為普通版本):

/media/cjcwgl/hdh/cwgl0101.mp4
/media/cjcwgl/hdk/cwgl0101.mp4

json文件路徑為:

/media/cjcwgl/mapped.json

mapped.json文件的內容:

{
    "sequences": [
        {
            "clips": [
                {
                    "type": "source",
                    "path": "/media/cjcwgl/hdh/cwgl0101.mp4"
                }
            ]
        },
        {
            "clips": [
                {
                    "type": "source",
                    "path": "/media/cjcwgl/hdk/cwgl0101.mp4"
                }
            ]
        }
    ]
}

json文件修改后,重新訪問URL即可生效配置,不需要對nginx進行reload。

URL播放地址:

http://192.168.192.128/vod_json/mapped.json/master.m3u8

2.3.2.3 HLS協議的多碼率自適應邏輯

  HLS的多碼率自適應邏輯是依據前一個ts切片的下載速度來作為是否切換碼率的依據。

示例:

#EXTM3U
#EXT-X-STREAM-INF:……BANDWIDTH=700000
http://……/index-f1-v1-a1.m3u8
#EXT-X-STREAM-INF:……BANDWIDTH=1300000
http://……/index-f2-v1-a1.m3u8
#EXT-X-STREAM-INF:……BANDWIDTH=2300000
http://……/index-f3-v1-a1.m3u8

  上述master.m3u8包含三個碼率500K,900K和1400K相應的index.m3u8,在播放視頻的時候, 第一個切片取的是master.m3u8中排在首位的index.m3u8中的首個ts切片。
  當配置了碼率自適應之后, 在每次下載完一個ts切片的時候,會依據該切片的下載速度的80%來決定是否要切換碼率, 如果當前切片的下載速度分別為:
1M = 那么其80%速度為 800K, 低於1300K, 那么下一個切片會下載500K碼率;
2M = 其80%速度為 1600K, 高於1300K低於2300K, 下一個切片會下載1300K碼率;
3M = 其80%速度為 2400K, 高於2300K, 下一個切片會下載2300K碼率。

2.3.2.3 mapped模式下的倍速播放

在服務器上對應的視頻文件目錄結構:

/media/cjcwgl/hdh/cwgl0101.mp4

json文件路徑為:

/media/cjcwgl/mapped2.json

mapped2.json文件的內容:

{
    "sequences": [
        {
        "clips": [
            {
                "type": "rateFilter",
                "rate": 2.0,
                "source": {
                    "type": "source",
                    "path": "/media/cjcwgl/hdh/cwgl0101.mp4"
                    }
                }
            ]
        }
    ]
}

URL播放地址:

http://192.168.192.128/vod_json/mapped2.json/index.m3u8

如果倍速播放的各種配置都正確,但是無法播放,在./logs/error.log中顯示filter no supported的相關信息,則很有可能是缺少libavcodec與libavfilter庫的支持。

2.3.2.4 安裝libavcodec與libavfilter庫支持

如果在點播服務中需要支持倍速輸出、視頻與音軌的分離等操作,需要額外的庫libavcodec與libavfilter的支持,它們都基於ffmpeg,通過安裝ffmpeg可提供相關的庫支持,步驟如下:

安裝libfdk-aac:

安裝包獲取地址:https://github.com/mstorsjo/fdk-aac/releases
安裝包名:fdk-aac-2.0.1.tar.gz
解壓:tar -zxvf fdk-aac-2.0.1.tar.gz
進目錄:cd fdk-aac-2.0.1
生成配置:./autogen.sh

如果出現錯誤:“./autogen.sh:行2: autoreconf: 未找到命令”,需要先安裝autoconf、automake、libtool:
在centos7.9下可以使用yum安裝:
yum install autoconf automake libtool
在centos6.5下如果使用yum無法成功安裝,則需要進行手動安裝:

安裝autoconf
下載:wget http://mirrors.kernel.org/gnu/autoconf/autoconf-2.65.tar.gz
解壓:tar -xzvf autoconf-2.65.tar.gz
進目錄:cd autoconf-2.65
配置:./configure

可能在autocon的安裝過程中還需要perl,安裝perl:
下載:wget https://www.cpan.org/src/5.0/perl-5.34.0.tar.gz
解壓:tar -xzvf perl-5.34.0.tar.gz
進目錄:cd perl-5.34.0
配置:./Configure -des -Dprefix=/usr/local/perl
編譯:make
安裝:make install

重新進行配置:./configure
編譯:make
安裝:make install

安裝automake
下載:wget http://mirrors.kernel.org/gnu/automake/automake-1.11.tar.gz
解壓:tar -xzvf automake-1.11.tar.gz
進目錄:cd automake-1.11
配置:./configure
編譯:make
安裝:make install

安裝libtool
下載:wget http://mirrors.kernel.org/gnu/libtool/libtool-2.2.6b.tar.gz
解壓:tar -xzvf libtool-2.2.6b.tar.gz
進目錄:cd libtool-2.2.6b
配置:./configure
編譯:make
安裝:make install

重新生成配置:./autogen.sh
配置:./configure --enable-shared
編譯:make
安裝:make install

安裝ffmpeg:

安裝包獲取地址:https://ffmpeg.org/download.html#releases
安裝包:ffmpeg-4.4.tar.gz
配置:./configure --enable-shared --enable-libfdk-aac

如果出現提示:“nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.”,則需要安裝nasm或者yasm其中之一:
在centos7.9下的可以使用yum進行安裝:
yum install nasm
在centos6.5下如果無法使用yum安裝,則需要手動安裝:
下載:wget https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/nasm-2.13.03.tar.gz
解壓:tar -xvf nasm-2.13.03.tar.gz
進目錄:cd nasm-2.13.03
配置:./configure
編譯:make
安裝:make install

如果出現警告:“WARNING: using libfdk without pkg-config”,則需要配置PKG_CONFIG_PATH如下:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
查看是否配置成功:
echo $PKG_CONFIG_PATH

然后重新配置:./configure --enable-shared --enable-libfdk-aac
編譯:make
安裝:make install

配置共享動態庫:

編輯配置文件命令:vi /etc/ld.so.conf
在末尾加入庫路徑:/usr/local/lib
使配置生效命令:ldconfig

配置環境變量:

編輯文件:vi /etc/profile
在末尾加入:export PATH="/usr/local/lib:$PATH"
使配置文件生效:source /etc/profile

測試ffmpeg是否安裝成功:

在命令行執行:ffmpeg
如果安裝成功,會出現如下信息:

ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-44)
  configuration: --enable-shared --enable-libfdk-aac
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

信息中顯示libavcodec與libavfilter庫的相關版本。

安裝成功ffmpeg之后,就有了libavcodec與libavfilter庫支持,此時需要重新編譯nginx,這樣才能把這兩個庫編譯進nginx,即重新執行nginx的configure->make->make install三個步驟。

./configure ……配置過程中,如果nginx能夠正確找到libavcodec與libavfilter庫,則會顯示如下信息片段:

……
checking for libavcodec ... found
checking for libswscale ... found
checking for libavfilter ... found
……

配置成功后,進行編譯make,最后安裝make install,至此已經成功在nginx中添加了libavcodec與libavfilter庫支持。

在安裝之前如果nginx已經在運行中,需要先./nginx -s stop,否則可能出現文件占用的問題。

2.3.3 完整的nginx.conf文件

nginx的完整配置文件,/nginx安裝路徑/conf/nginx.conf

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        autoindex on;

        location /vod {
            vod hls; # 開啟vod模塊
            vod_mode local; # 訪問模式指定為local
            
            vod_align_segments_to_key_frames on; # 每個切片以關鍵幀開頭
            vod_manifest_segment_durations_mode accurate; # 精確顯示每個切片的長度
            
            add_header Access-Control-Allow-Headers '*';
            add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
            add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
            add_header Access-Control-Allow-Origin '*';

            alias /media;
        }

        location /vod_json {
            vod hls;
            vod_mode mapped;

            vod_align_segments_to_key_frames on; # 每個切片以關鍵幀開頭
            
            add_header Access-Control-Allow-Headers '*';
            add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
            add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
            add_header Access-Control-Allow-Origin '*';

            alias /media/cjcwgl;
        }

        location /data {
            alias /media;
        }

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

3 關於nginx-vod-module模塊

  模塊里還有很多功能,比如加密傳輸、數據緩存、代理上游服務等,但文檔里只提供了幾個基本的例子,遇到問題的話可以在github的issues[3]里尋找相應的問題。


  1. nginx安裝流程: https://blog.csdn.net/SeeDoubleU/article/details/121727292 ↩︎

  2. nginx-vod-module文檔: https://github.com/kaltura/nginx-vod-module/blob/master/README.md ↩︎

  3. github issues: https://github.com/kaltura/nginx-vod-module/issues ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM