利用nginx和VLC&FLV自建直播服务器并实现播放

服务器环境:Centos


nginx-rtmp-module项目地址:https://github.com/arut/nginx-rtmp-module

方法参考:https://www.nginx.org.cn/article/detail/259


此方法需要使用nginx插件,通过对nginx本体的编译安装实现。

编译安装命令

./configure --user=nginx --group=nginx 
--prefix=/home/nginx-rtmp/rtmp --add-module=/home/nginx-rtmp/nginx-rtmp-module-1.2.2 \
make && make install

注释:

--add-module=/home/nginx-rtmp/nginx-rtmp-module-1.2.2 是选择此项目编译入NGINX程序



服务端配置文件:

worker_processes  1;

events {
    worker_connections  1024;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        application vod {
                play /opt/video/vod;
        }

        application live{ #第一处添加的直播字段
                live on;
        }
    }

}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;

        location /stat {     #第二处添加的location字段。
            rtmp_stat all;
            rtmp_stat_stylesheet  html/stat.xsl;
        }

        location /stat.xsl { #第二处添加的location字段。
                root /home/nginx-rtmp/rtmp;
        }

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

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}


OBS推流地址:rtmp://127.0.0.1:1935/live

VLC网络播放地址:rtmp://127.0.0.1:1935/live



更新的技术方法:nginx-http-flv-module


可选择的:--add-module=/path/to/nginx-http-flv-module

项目地址:https://github.com/winshining/nginx-http-flv-module

中文README:https://github.com/winshining/nginx-http-flv-module/blob/master/README.CN.md

OBS推流地址:rtmp://127.0.0.1:1935/live/tdu

FLV观看拉流:http://127.0.0.1/live?app=live&stream=tdu

flv.js demo :http://bilibili.github.io/flv.js/demo/


nginx配置文件

worker_processes  1; #运行在 Windows 上时,设置为 1,因为 Windows 不支持 Unix domain socket
error_log logs/error.log error;

events {
    worker_connections  4096;
}

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

    keepalive_timeout  65;

    server {
        listen       80;

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

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location /live {
            flv_live on; #打开 HTTP 播放 FLV 直播流功能
            chunked_transfer_encoding on; #支持 'Transfer-Encoding: chunked' 方式回复

            add_header 'Access-Control-Allow-Origin' '*'; #添加额外的 HTTP 头
            add_header 'Access-Control-Allow-Credentials' 'true'; #添加额外的 HTTP 头
        }

        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }

            root /tmp;
            add_header 'Cache-Control' 'no-cache';
        }

        location /dash {
            root /tmp;
            add_header 'Cache-Control' 'no-cache';
        }

        location /stat {
            #推流播放和录制统计数据的配置

            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }

        location /stat.xsl {
            root html; #指定 stat.xsl 的位置
        }

        #如果需要 JSON 风格的 stat, 不用指定 stat.xsl
        #但是需要指定一个新的配置项 rtmp_stat_format

        #location /stat {
        #    rtmp_stat all;
        #    rtmp_stat_format json;
        #}

        location /control {
            rtmp_control all; #rtmp 控制模块的配置
        }
    }
}

rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;

rtmp {
    out_queue           4096;
    out_cork            8;
    max_streams         128;
    timeout             15s;
    drop_idle_publisher 15s;

    #log_interval 5s; #log 模块在 access.log 中记录日志的间隔时间,对调试非常有用
    log_size     1m; #log 模块用来记录日志的缓冲区大小

    server {
        listen 1935;

        application live {
            live on;
            gop_cache on; #打开 GOP 缓存,减少首屏等待时间
        }

        application hls {
            live on;
            hls on;
            hls_path /tmp/hls;
        }

        application dash {
            live on;
            dash on;
            dash_path /tmp/dash;
        }
    }

}



在访问http://127.0.0.1/stat统计页面时,如果出现stat.xsl报错404,则需要加入以下文件在html/html路径

来源:https://github.com/winshining/nginx-http-flv-module/blob/master/stat.xsl

stat.xsl:

<?xml version="1.0" encoding="utf-8" ?>


<!--
        Copyright (C) Roman Arutyunyan
   Copyright (C) Winshining
-->


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


<xsl:template match="/">
    <html>
        <head>
            <title>HTTP-FLV statistics</title>
        </head>
        <body>
            <xsl:apply-templates select="http-flv"/>
            <hr/>
            Generated by <a href='https://github.com/winshining/nginx-http-flv-module'>
            nginx-http-flv-module</a>&#160;<xsl:value-of select="/http-flv/nginx_http_flv_version"/>,
            <a href="http://nginx.org">nginx</a>&#160;<xsl:value-of select="/http-flv/nginx_version"/>,
            pid <xsl:value-of select="/http-flv/pid"/>,
            built <xsl:value-of select="/http-flv/built"/>&#160;<xsl:value-of select="/http-flv/compiler"/>
        </body>
    </html>
</xsl:template>

<xsl:template match="http-flv">
    <table cellspacing="1" cellpadding="5">
        <tr bgcolor="#999999">
            <th>HTTP-FLV</th>
            <th>#clients</th>
            <th colspan="2">Recorders</th>
            <th colspan="2">Server</th>
            <th colspan="4">Video</th>
            <th colspan="4">Audio</th>
            <th>In bytes</th>
            <th>Out bytes</th>
            <th>In bits/s</th>
            <th>Out bits/s</th>
            <th>State</th>
            <th>Time</th>
        </tr>
        <tr>
            <td colspan="2">Accepted: <xsl:value-of select="naccepted"/></td>
            <th bgcolor="#999999">lists</th>
            <th bgcolor="#999999">#count</th>
            <th bgcolor="#999999">port</th>
            <th bgcolor="#999999">index</th>
            <th bgcolor="#999999">codec</th>
            <th bgcolor="#999999">bits/s</th>
            <th bgcolor="#999999">size</th>
            <th bgcolor="#999999">fps</th>
            <th bgcolor="#999999">codec</th>
            <th bgcolor="#999999">bits/s</th>
            <th bgcolor="#999999">freq</th>
            <th bgcolor="#999999">chan</th>
            <td>
                <xsl:call-template name="showsize">
                    <xsl:with-param name="size" select="bytes_in"/>
                </xsl:call-template>
            </td>
            <td>
                <xsl:call-template name="showsize">
                    <xsl:with-param name="size" select="bytes_out"/>
                </xsl:call-template>
            </td>
            <td>
                <xsl:call-template name="showsize">
                    <xsl:with-param name="size" select="bw_in"/>
                    <xsl:with-param name="bits" select="1"/>
                    <xsl:with-param name="persec" select="1"/>
                </xsl:call-template>
            </td>
            <td>
                <xsl:call-template name="showsize">
                    <xsl:with-param name="size" select="bw_out"/>
                    <xsl:with-param name="bits" select="1"/>
                    <xsl:with-param name="persec" select="1"/>
                </xsl:call-template>
            </td>
            <td/>
            <td>
                <xsl:call-template name="showtime">
                    <xsl:with-param name="time" select="/http-flv/uptime * 1000"/>
                </xsl:call-template>
            </td>
        </tr>
        <xsl:apply-templates select="server"/>
    </table>
</xsl:template>

<xsl:template match="server">
    <xsl:apply-templates select="application"/>
</xsl:template>

<xsl:template match="application">
    <tr bgcolor="#999999">
        <td>
            <b><xsl:value-of select="name"/></b>
        </td>
    </tr>
    <xsl:apply-templates select="live"/>
    <xsl:apply-templates select="play"/>
    <xsl:apply-templates select="recorders"/>
</xsl:template>

<xsl:template match="live">
    <tr bgcolor="#aaaaaa">
        <td>
            <i>live streams</i>
        </td>
        <td align="middle">
            <xsl:value-of select="nclients"/>
        </td>
    </tr>
    <xsl:apply-templates select="stream"/>
</xsl:template>

<xsl:template match="play">
    <tr bgcolor="#aaaaaa">
        <td>
            <i>vod streams</i>
        </td>
        <td align="middle">
            <xsl:value-of select="nclients"/>
        </td>
    </tr>
    <xsl:apply-templates select="stream"/>
</xsl:template>

<xsl:template match="recorders">
    <tr bgcolor="#aaaaaa">
        <td colspan="2">Recorders</td>
        <td>
            <a href="">
                <xsl:attribute name="onclick">
                    var d=document.getElementById('<xsl:value-of select="../../port"/>-<xsl:value-of select="../../server_index"/>-<xsl:value-of select="../name"/>-recorders');
                    d.style.display=d.style.display=='none'?'':'none';
                    return false;
                </xsl:attribute>
                <i>config</i>
            </a>
        </td>
        <td align="middle">
            <xsl:value-of select="count"/>
        </td>
    </tr>
    <tr style="display:none">
        <xsl:attribute name="id"><xsl:value-of select="../../port"/>-<xsl:value-of select="../../server_index"/>-<xsl:value-of select="../name"/>-recorders</xsl:attribute>
        <td colspan="16">
            <table cellspacing="1" cellpadding="5">
                <tr>
                    <th>Id</th>
                    <th>Path</th>
                    <th>Suffix</th>
                    <th>Flags</th>
                    <th>Max Size</th>
                    <th>Max Frames</th>
                    <th>Interval</th>
                    <th>Unique</th>
                    <th>Append</th>
                    <th>Lock File</th>
                    <th>Notify</th>
                </tr>
                <xsl:apply-templates select="recorder"/>
            </table>
        </td>
    </tr>
</xsl:template>

<xsl:template match="recorder">
    <tr bgcolor="#cccccc">
        <td>
            <xsl:value-of select="id"/>
            <xsl:if test="string-length(id) = 0">
                [DEFAULT]
            </xsl:if>
        </td>
        <td><xsl:value-of select="path"/></td>
        <td><xsl:value-of select="suffix"/></td>
        <td>
            <xsl:if test="flags/video">video<br/></xsl:if>
            <xsl:if test="flags/audio">audio<br/></xsl:if>
            <xsl:if test="flags/manual">manual</xsl:if>
        </td>
        <td>
            <xsl:call-template name="showsize">
               <xsl:with-param name="size" select="max_size"/>
            </xsl:call-template>
        </td>
        <td><xsl:value-of select="max_frames"/></td>
        <td>
            <xsl:call-template name="showinterval">
               <xsl:with-param name="interval" select="interval"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="binarystate">
                <xsl:with-param name="value" select="unique"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="binarystate">
                <xsl:with-param name="value" select="append"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="binarystate">
                <xsl:with-param name="value" select="lock_file"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="binarystate">
                <xsl:with-param name="value" select="notify"/>
            </xsl:call-template>
        </td>
    </tr>
</xsl:template>

<xsl:template name="binarystate">
    <xsl:param name="value"/>
    <xsl:choose>
        <xsl:when test="$value">on</xsl:when>
        <xsl:otherwise>off</xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="stream">
    <tr valign="top">
        <xsl:attribute name="bgcolor">
            <xsl:choose>
                <xsl:when test="active">#cccccc</xsl:when>
                <xsl:otherwise>#dddddd</xsl:otherwise>
            </xsl:choose>
        </xsl:attribute>
        <td>
            <a href="">
                <xsl:attribute name="onclick">
                    var d=document.getElementById('<xsl:value-of select="../../../port"/>-<xsl:value-of select="../../../server_index"/>-<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/>');
                    d.style.display=d.style.display=='none'?'':'none';
                    return false
                </xsl:attribute>
                <xsl:value-of select="name"/>
                <xsl:if test="string-length(name) = 0">
                    [EMPTY]
                </xsl:if>
            </a>
        </td>
        <td align="middle"> <xsl:value-of select="nclients"/> </td>
        <td align="middle"> - </td>
        <td align="middle"> - </td>
        <td align="middle"> <xsl:value-of select="../../../port"/> </td>
        <td align="middle"> <xsl:value-of select="../../../server_index"/> </td>
        <td>
            <xsl:value-of select="meta/video/codec"/>&#160;<xsl:value-of select="meta/video/profile"/>&#160;<xsl:value-of select="meta/video/level"/>
        </td>
        <td>
            <xsl:call-template name="showsize">
                <xsl:with-param name="size" select="bw_video"/>
                <xsl:with-param name="bits" select="1"/>
                <xsl:with-param name="persec" select="1"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:apply-templates select="meta/video/width"/>
        </td>
        <td>
            <xsl:value-of select="meta/video/frame_rate"/>
        </td>
        <td>
            <xsl:value-of select="meta/audio/codec"/>&#160;<xsl:value-of select="meta/audio/profile"/>
        </td>
        <td>
            <xsl:call-template name="showsize">
                <xsl:with-param name="size" select="bw_audio"/>
                <xsl:with-param name="bits" select="1"/>
                <xsl:with-param name="persec" select="1"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:apply-templates select="meta/audio/sample_rate"/>
        </td>
        <td>
            <xsl:value-of select="meta/audio/channels"/>
        </td>
        <td>
            <xsl:call-template name="showsize">
               <xsl:with-param name="size" select="bytes_in"/>
           </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="showsize">
                <xsl:with-param name="size" select="bytes_out"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="showsize">
                <xsl:with-param name="size" select="bw_in"/>
                <xsl:with-param name="bits" select="1"/>
                <xsl:with-param name="persec" select="1"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="showsize">
                <xsl:with-param name="size" select="bw_out"/>
                <xsl:with-param name="bits" select="1"/>
                <xsl:with-param name="persec" select="1"/>
            </xsl:call-template>
        </td>
        <td><xsl:call-template name="streamstate"/></td>
        <td>
            <xsl:call-template name="showtime">
               <xsl:with-param name="time" select="time"/>
            </xsl:call-template>
        </td>
    </tr>
    <tr style="display:none">
        <xsl:attribute name="id">
            <xsl:value-of select="../../../port"/>-<xsl:value-of select="../../../server_index"/>-<xsl:value-of select="../../name"/>-<xsl:value-of select="name"/>
        </xsl:attribute>
        <td colspan="16" ngcolor="#eeeeee">
            <table cellspacing="1" cellpadding="5">
                <tr>
                    <th>Id</th>
                    <th>State</th>
                    <th>Address</th>
                    <th>Flash version</th>
                    <th>Page URL</th>
                    <th>SWF URL</th>
                    <th>Dropped</th>
                    <th>Timestamp</th>
                    <th>A-V</th>
                    <th>Time</th>
                </tr>
                <xsl:apply-templates select="client"/>
            </table>
            <xsl:apply-templates select="records"/>
        </td>
    </tr>
</xsl:template>

<xsl:template match="records">
    <table cellspacing="1" cellpadding="5">
        <tr>
            <th>Recorder</th>
            <th>State</th>
            <th>Epoch</th>
            <th>Time Shift</th>
            <th>File Name</th>
            <th>Time</th>
            <th>Size</th>
            <th>Frames</th>
        </tr>
        <xsl:apply-templates select="record"/>
    </table>
</xsl:template>

<xsl:template match="record">
    <tr>
        <xsl:attribute name="bgcolor">
            <xsl:choose>
                <xsl:when test="recording">#cccccc</xsl:when>
                <xsl:otherwise>#eeeeee</xsl:otherwise>
            </xsl:choose>
        </xsl:attribute>
        <td>
            <xsl:value-of select="recorder"/>
            <xsl:if test="string-length(recorder) = 0">
                [DEFAULT]
            </xsl:if>
        </td>
        <td>
            <xsl:choose>
                <xsl:when test="recording">recording</xsl:when>
                <xsl:otherwise>idle</xsl:otherwise>
            </xsl:choose>
        </td>
        <td><xsl:value-of select="epoch"/></td>
        <td><xsl:value-of select="time_shift"/></td>
        <td><xsl:value-of select="file"/></td>
        <td>
            <xsl:call-template name="showtime">
               <xsl:with-param name="time" select="time * 1000"/>
            </xsl:call-template>
        </td>
        <td>
            <xsl:call-template name="showsize">
               <xsl:with-param name="size" select="size"/>
            </xsl:call-template>
        </td>
        <td><xsl:value-of select="nframes"/></td>
    </tr>
</xsl:template>

<xsl:template name="showtime">
    <xsl:param name="time"/>

    <xsl:if test="$time &gt; 0">
        <xsl:variable name="sec">
            <xsl:value-of select="floor($time div 1000)"/>
        </xsl:variable>

        <xsl:if test="$sec &gt;= 86400">
            <xsl:value-of select="floor($sec div 86400)"/>d
        </xsl:if>

        <xsl:if test="$sec &gt;= 3600">
            <xsl:value-of select="(floor($sec div 3600)) mod 24"/>h
        </xsl:if>

        <xsl:if test="$sec &gt;= 60">
            <xsl:value-of select="(floor($sec div 60)) mod 60"/>m
        </xsl:if>

        <xsl:value-of select="$sec mod 60"/>s
    </xsl:if>
</xsl:template>

<xsl:template name="showsize">
    <xsl:param name="size"/>
    <xsl:param name="bits" select="0" />
    <xsl:param name="persec" select="0" />
    <xsl:variable name="sizen">
        <xsl:value-of select="floor($size div 1024)"/>
    </xsl:variable>
    <xsl:choose>
        <xsl:when test="$sizen &gt;= 1073741824">
            <xsl:value-of select="format-number($sizen div 1073741824,'#.###')"/> T</xsl:when>

        <xsl:when test="$sizen &gt;= 1048576">
            <xsl:value-of select="format-number($sizen div 1048576,'#.###')"/> G</xsl:when>

        <xsl:when test="$sizen &gt;= 1024">
            <xsl:value-of select="format-number($sizen div 1024,'#.##')"/> M</xsl:when>
        <xsl:when test="$sizen &gt;= 0">
            <xsl:value-of select="$sizen"/> K</xsl:when>
    </xsl:choose>
    <xsl:if test="string-length($size) &gt; 0">
        <xsl:choose>
            <xsl:when test="$bits = 1">b</xsl:when>
            <xsl:otherwise>B</xsl:otherwise>
        </xsl:choose>
        <xsl:if test="$persec = 1">/s</xsl:if>
    </xsl:if>
</xsl:template>

<xsl:template name="showinterval">
    <xsl:param name="interval"/>

    <xsl:if test="$interval &gt; 0">
        <xsl:variable name="sec">
            <xsl:value-of select="floor($interval div 1000)"/>
        </xsl:variable>

        <xsl:if test="$sec &gt;= 86400">
            <xsl:value-of select="floor($sec div 86400)"/>d
        </xsl:if>

        <xsl:if test="$sec &gt;= 3600">
            <xsl:value-of select="(floor($sec div 3600)) mod 24"/>h
        </xsl:if>

        <xsl:if test="$sec &gt;= 60">
            <xsl:value-of select="(floor($sec div 60)) mod 60"/>m
        </xsl:if>

        <xsl:if test="$sec &lt; 60">
            <xsl:value-of select="$sec mod 60"/>s
        </xsl:if>
    </xsl:if>

    <xsl:if test="$interval = -1">Unset</xsl:if>
</xsl:template>

<xsl:template name="streamstate">
    <xsl:choose>
        <xsl:when test="active">active</xsl:when>
        <xsl:otherwise>idle</xsl:otherwise>
    </xsl:choose>
</xsl:template>


<xsl:template name="clientstate">
    <xsl:choose>
        <xsl:when test="publishing">publishing</xsl:when>
        <xsl:otherwise>playing</xsl:otherwise>
    </xsl:choose>
</xsl:template>


<xsl:template match="client">
    <tr>
        <xsl:attribute name="bgcolor">
            <xsl:choose>
                <xsl:when test="publishing">#cccccc</xsl:when>
                <xsl:otherwise>#eeeeee</xsl:otherwise>
            </xsl:choose>
        </xsl:attribute>
        <td><xsl:value-of select="id"/></td>
        <td><xsl:call-template name="clientstate"/></td>
        <td>
            <a target="_blank">
                <xsl:attribute name="href">
                    http://apps.db.ripe.net/search/query.html&#63;searchtext=<xsl:value-of select="address"/>
                </xsl:attribute>
                <xsl:attribute name="title">whois</xsl:attribute>
                <xsl:value-of select="address"/>
            </a>
        </td>
        <td><xsl:value-of select="flashver"/></td>
        <td>
            <a target="_blank">
                <xsl:attribute name="href">
                    <xsl:value-of select="pageurl"/>
                </xsl:attribute>
                <xsl:value-of select="pageurl"/>
            </a>
        </td>
        <td><xsl:value-of select="swfurl"/></td>
        <td><xsl:value-of select="dropped"/></td>
        <td><xsl:value-of select="timestamp"/></td>
        <td><xsl:value-of select="avsync"/></td>
        <td>
            <xsl:call-template name="showtime">
               <xsl:with-param name="time" select="time"/>
            </xsl:call-template>
        </td>
    </tr>
</xsl:template>

<xsl:template match="publishing">
    publishing
</xsl:template>

<xsl:template match="active">
    active
</xsl:template>

<xsl:template match="width">
    <xsl:value-of select="."/>x<xsl:value-of select="../height"/>
</xsl:template>

</xsl:stylesheet>

(如果需要)

发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。