跳转至

源码编译nginx并添加RTMP模块

先决条件

本次编译使用的环境:

  • Windows 19042.662
  • Visual Studio 2019
  • Visual Studio Build Tools 2017
  • Windows 10 SDK 10.0.17763.0
  • nginx 1.19.5
  • openssl 1.1.1g
  • zlib 1.2.11
  • pcre 8.44
  • perl 5.32 (Strawberry)
  • nasm 2.15.05
  • nmake 14.27.29112.0
  • MSVC(cl) 19.27.29112

将包含perl.exenasm.exesed.exe的目录添加到PATH环境变量。

准备工作

启动MSYS,cd到nginx的源代码目录,切换到C盘根目录的代码如下:

cd /c/

执行auto/configure,根据nginx官网提供的参数进行,添加``参数,具体命令如下:

auto/configure \
    --with-cc=cl \
    --with-debug \
    --prefix=. \
    --conf-path=conf/nginx.conf \
    --pid-path=logs/nginx.pid \
    --http-log-path=logs/access.log \
    --error-log-path=logs/error.log \
    --sbin-path=nginx.exe \
    --http-client-body-temp-path=temp/client_body_temp \
    --http-proxy-temp-path=temp/proxy_temp \
    --http-fastcgi-temp-path=temp/fastcgi_temp \
    --http-scgi-temp-path=temp/scgi_temp \
    --http-uwsgi-temp-path=temp/uwsgi_temp \
    --with-cc-opt=-DFD_SETSIZE=1024 \
    --with-pcre=pcre-8.44 \
    --with-zlib=zlib \
    --with-openssl=openssl \
    --with-openssl-opt=no-asm \
    --with-http_ssl_module \
    --add-module=nginx-rtmp-module

注意此处--with-pcre--with-zlib--with-openssl参数中提供的路径需要与PCRE、zlib、openssl的源代码路径分别对应。

执行完毕后生成Makefile文件。32位环境下可以直接开始编译,64位环境下需要对auto\lib\openssl\makefile.msvc改为如下代码

# Copyright (C) Igor Sysoev
# Copyright (C) Nginx, Inc.


all:
    cd $(OPENSSL)

    perl Configure VC-WIN64A no-shared              \
        --prefix="%cd%/openssl"                     \
        --openssldir="%cd%/openssl/ssl"             \
        $(OPENSSL_OPT)

    if exist ms\do_win64a.bat (                     \
        ms\do_win64a                                \
        && $(MAKE) -f ms\nt.mak                     \
        && $(MAKE) -f ms\nt.mak install             \
    ) else (                                        \
        $(MAKE)                                     \
        && $(MAKE) install_sw                       \
    )

VC-WIN32替换为VC-WIN64A,所有的ms\do_ms.bat替换为ms\do_win64a.bat

MSVC编译

编辑如下源代码文件:

  • nginx-rtmp-module/ngx_rtmp_flv_module.c,定位到如下代码块:

509行:

ngx_rtmp_prepare_message(s, &h, ctx->msg_mask & (1 << h.type) ?
                           &lh : NULL, out);

521行:

ctx->msg_mask |= (1 << h.type);

将其中的(1 << h.type)改为(unsigned long)(1 << h.type)

  • nginx-rtmp-module/ngx_rtmp_core_module.c,定位到如下代码块:

611行:

struct sockaddr  *sa;

将此处的变量名sa改为sa2,并将此后所有的sa变量改为sa2

启动x64 Native Tools Command Prompt for VS 2019,切换到源代码目录,执行nmake启动编译。输出文件为objs/nginx.exe

nginx配置

objs/nginx.exe复制一份。在所在目录下创建如下文件结构:

.
├─ nginx.exe
├─ conf/
│  └─ nginx.conf
├─ html
│  └─ index.xsl
├─ logs
└─ temp

其中,html/index.xsl写入如下内容

html/index.xsl文件内容
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) Roman Arutyunyan
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <html>
        <head>
            <title>RTMP statistics</title>
        </head>
        <body>
            <xsl:apply-templates select="rtmp"/>
            <hr/>
            Generated by <a href='https://github.com/arut/nginx-rtmp-module'>
            nginx-rtmp-module</a>&#160;<xsl:value-of select="/rtmp/nginx_rtmp_version"/>,
            <a href="http://nginx.org">nginx</a>&#160;<xsl:value-of select="/rtmp/nginx_version"/>,
            pid <xsl:value-of select="/rtmp/pid"/>,
            built <xsl:value-of select="/rtmp/built"/>&#160;<xsl:value-of select="/rtmp/compiler"/>
        </body>
    </html>
</xsl:template>
<xsl:template match="rtmp">
    <table cellspacing="1" cellpadding="5">
        <tr bgcolor="#999999">
            <th>RTMP</th>
            <th>#clients</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">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="/rtmp/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: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="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="../../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>
            <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="../../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>
        </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="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>

conf/nginx.conf写入如下内容:

conf/nginx.conf文件内容

worker_processes  8;
error_log  logs/error.log info;
events {
    worker_connections  1024;
}

rtmp {
    server {
        listen 1935;

        application live {
            live on;
        }

        application hls {
            live on;
            hls on;  
            hls_path temp/hls;  
            hls_fragment 8s;  
        }
    }
}

http {
    server {
        listen      8080;
        root html;
        location / {
            rtmp_stat all;
            rtmp_stat_stylesheet index.xsl;
        }

        location /index.xsl {
            root html;
        }

        location /hls {  
            types{  
                application/vnd.apple.mpegurl m3u8;  
                video/mp2t ts;  
            }  
            alias temp/hls;  
            expires -1;  
        }  
    }
}

双击nginx.exe即可启动服务器,服务器同时监听1935端口与8080端口

  • 推流使用的RTMP服务器地址为:rtmp://localhost:1935/live
  • 访问http://localhost:8080可以查看服务器端的统计信息
  • 客户端(如VLC等)可以访问rtmp://localhost:1935/live接收流,localhost可以更改为本机的IP地址

使用命令.\nginx.exe -s stop关闭服务器

评论