Cononico

2018年4月16日

ffmpeg 学习笔记>

ffmpeg+nginx(rtmp)+ffplayer实现远程监控

实现方案:
本地使用ffmpeg对摄像头和麦克风设备进行采集和编码并向远程rtmp服务器推流;
服务器端安装nginx并使用rtmp模块作为流媒体服务器;
本地使用ffplayer播放视频流。
实验环境:
本地使用Mac系统
服务器端使用Ubuntu系统

具体步骤:

  • rtmp流媒体服务器搭建和配置

参考资料:https://blog.csdn.net/kingroc/article/details/50839994

安装nginx的依赖库


1
2
3
sudo apt-get update
sudo apt-get install libpcre3 libpcre3-dev
sudo apt-get install openssl libssl-dev

下载nginx和nginx的rtmp模块
nginx-1.8.1
nginx-rtmp-module
配置并编译nginx
使用nginx的默认配置,添加nginx的rtmp模块。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#user  nobody;

worker_processes  1;

#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {

    worker_connections  1024;

}

http {

    include       mime.types;

    default_type  application/octet-stream;

    #access_log  logs/access.log  main;

    sendfile        on;

    #tcp_nopush     on;

    #keepalive_timeout  0;

    keepalive_timeout  65;

    #gzip  on;

    server {

        listen       80;

        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {

            root   html;

            index  index.html index.htm;

        }

location /stat {#添加的location字段

rtmp_stat all;

rtmp_stat_stylesheet stat.xsl;

}

location /stat.xsl {#添加的location字段

root /usr/local/nginx/html;

}


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

            root   html;

        }

    }

    }

rtmp {#rtmp服务
 server {
 listen 1935;#监听端口
 chunk_size 4096;#数据传输块的大小

 application vod {#点播服务对于的目录
 play /opt/video/vod;
 }

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

}

1
2
3
./configure --add-module=../nginx-rtmp-module-master
make
sudo make install
到这里nginx和rtmp模块就安装完成了,接下来要对流媒体服务器进行配置,rtmp服务器可以配置成点播服务器和直播服务器,这里我们实现监控功能的其实是直播功能,下面是配置: 打开nginx.conf在最后添加rtmp配置项,并且在原来的htpp字段中添加两个location字段

重启nginx,rtmp就搭建完成了

sudo ./sbin/nginx -s reload


 
  • ffmpeg安装和推流

安装ffmpeg和ffplayer

参考资料:https://blog.csdn.net/charleslei/article/details/72462791

其实ffplayer就是基于ffmpeg的库写的一个播放器

mac下的安装方法:


brew install ffmpeg --with-ffplay
使用ffmpeg获取摄像头并推流推流 参考资料:https://blog.csdn.net/arctan90/article/details/50828771 https://blog.csdn.net/chenyefei/article/details/53869396 ffmpeg相关的命令请自行学习,使用一下命令就可以将mac本地摄像头采集的数据推流到刚刚的rtmp服务器:

ffmpeg -f avfoundation -framerate 30  -i "0"  -vcodec libx264 -acodec aac -f flv -y rtmp://easy.lbbit.com/live/test
  • 视频流的播放

使用ffplay播放视频流(也可以使用其他的工具):

ffplay rtmp://easy.lbbit.com/live/test

到这里一个简单的监控逻辑就打通了,使用ffmpeg推流的时候还可以同时获取本地麦克风的数据,和摄像头数据同时编码推流,这样可以同时监控视频和声音了。

还可以在nginx的html目录下新建一个stat.xsl文件,用于显示当前rtmp服务器状态,该文件内容如下:

 


<?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><xsl:value-of select="/rtmp/nginx_rtmp_version"/>,
            <a href="http://nginx.org">nginx</a><xsl:value-of select="/rtmp/nginx_version"/>,
            pid <xsl:value-of select="/rtmp/pid"/>,
            built <xsl:value-of select="/rtmp/built"/><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"/><xsl:value-of select="meta/video/profile"/><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"/><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?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>


来一发吐槽