zoukankan      html  css  js  c++  java
  • c# 基于RTMP推流 PC+移动端 拉流播放

    网上关于直播相关的文章很多,但是讲解还是不够系统,对于刚刚接触直播开发的朋友实施起来会浪费不少时间。下面结合我自己的经验,

    介绍一下直播方面的实战经验。

    分成两个部分

    第一部分是标题中介绍的基于RTMP推送文件流与视频流,PC端拉流RTMP,移动端拉流m3u8也就是hls

    下一篇介绍基于websocket+canvas,进行拉流播放。

    一 准备工作

    1.准备RTMP服务器,我是在win10下开发,我是安装了docker for windows,然后下载镜像nginx-rtmp-server,(使用linux的朋友就更方便了,docker pull antongulenko/rtmp-nginx-server),点击Create后自动安装

     安装完成后,保存当前的端口号,为了防止每次重启容器端口号自动分配,点击保存按钮 如图:

     1935是本机RTMP对应的端口,外部映射的是 32781,稍候我们会用到这个端口号进行推流。

    此时nginx还没有进行配置,我们需要配置,首先找到nginx.conf,

    首先进入容器,具体的操作我只记录docker for windows的,linux就更简洁了,docker exec 容器id。

     可以查看容器的目录结构

     nginx的路径是etc/nginx/nginx.conf

    首先拷贝下来,修改后,再覆盖回去,覆盖后要重启nginx,才能生效。

    下面的指令是分别从容器上把配置文件拷贝到D盘,修改后 将文件覆盖回容器内

     具体conf内容如下:

    worker_processes auto;
    rtmp_auto_push on;
    events {}
    
    rtmp {
        server {
            listen 1935;
            listen [::]:1935 ipv6only=on;
    
            application vod {
                play /opt/rtmp/vod;
            }
            application mirror_cache {
                play /opt/rtmp/vod_mirror;
            }
            
            application live{
                # enable live streaming
                live on;
    
                max_connections 1024;
    
                
            }
    
    		application hls{
    		  live on;
    		  hls on;
    		  hls_path /usr/local/hls;
    		  hls_fragment 5s;
    		}
    
            # Application names cannot contain patterns, and play_local_path fails for cached files
            # that contain slashes (error dir not found). Therefore, list every path of interest as a separate
            # application, so that only files without directory prefix are cached.
            application mirror/720 {
                play /opt/rtmp/vod_mirror http://www.sample-videos.com/video/flv/720/;
                play_local_path /opt/rtmp/vod_mirror;
            }
            application mirror/480 {
                play /opt/rtmp/vod_mirror http://www.sample-videos.com/video/flv/480/;
                play_local_path /opt/rtmp/vod_mirror;
            }
            application mirror/360 {
                play /opt/rtmp/vod_mirror http://www.sample-videos.com/video/flv/360/;
                play_local_path /opt/rtmp/vod_mirror;
            }
            application mirror/240 {
                play /opt/rtmp/vod_mirror http://www.sample-videos.com/video/flv/240/;
                play_local_path /opt/rtmp/vod_mirror;
            }
    
        }
    }
    
    http {
        server {
            listen 8080;
    
            # This URL provides RTMP statistics in XML
            location /stat {
                rtmp_stat all;
                rtmp_stat_stylesheet stat.xsl;
            }
    
            location /stat.xsl {
                root /opt/rtmp/http/;
            }
    
    		 location /hls{
              types{
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
              }
               alias /usr/local/hls;
              add_header Cache-Control no-cache;
            }
    
            location /vod {
                autoindex on;
                alias /opt/rtmp/vod;
            }
    
            location /mirror_cache {
                autoindex on;
                alias /opt/rtmp/vod_mirror;
            }
    
            location /mirror/ {
                proxy_pass http://www.sample-videos.com/video/;
            }
        }
    }
    

      

    配置文件中的 application live 与 application hls就是分别推送rtmp与hls协议的路由地址
    而http节点就是用于手机端使用m3u8播放的时候(http://ip+port/hls/秘钥.m3u8)的配置。
    然后重启容器就可以了。

    2.github下载https://github.com/BoonyaCSharp-ASP/VedioFFmpegPushRTMP 
    基于c#封装的FFMPEG的推流方法,使用的时候需要下载FFMPEG的相关文件,
    我这里提供一下连接,直接解压覆盖,注意link类型为shared
    https://ffmpeg.zeranoe.com/builds/ 

     

     这个c#工程可以直接运行,配置使用也是很难得,不过我为了测试方便还是直接用命令行的方式进行推流

    命令行进入x64文件夹下,直接使用ffmpeg.exe进行推流,ffplay.exe以直接进行播放。

    下面开始推流:

    1.推送文件流,我在x64下面放置了1.MP4的文件

    推流指令如下

    ffmpeg.exe -re -i 1.mp4   -f flv rtmp://192.168.1.253:32781/rtmp/test

    192.168.1.253是我的rtmp服务器ip   32781是docker中rtmp的外部端口 (如果不使用docker自然就是1935了)

    rtmp 是nginx.conf 配置的rtmp的路由节点名称  test类似于房间号的概念,拉流的时候也指定这个房间号,就可以对应到自己要看的直播流

    推流如下:

    如果有异常信息就是相关参数的配置,具体问题留言讨论。

    拉取文件流

    可以下载vlc播放器,然后配置拉流地址  rtmp://192.168.1.253:32781/rtmp/test 就可以点击播放

    PC端播放rtmp代码如下,建议使用Chrome,并且设置flash允许

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>使用video.js实现rtmp流的直播播放</title>
        <!--引入播放器样式-->
        <link href="http://vjs.zencdn.net/5.19/video-js.min.css" rel="stylesheet">
        <!--引入播放器js-->
        <script src="http://vjs.zencdn.net/5.19/video.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/videojs-flash@2/dist/videojs-
    
    flash.min.js"></script>
    </head>
    <body>
    
    
    <!--vjs-big-play-centered 播放按钮居中-->
    <!--poster默认的显示界面,就是还没点播放,给你显示的界面-->
    <!--controls 规定浏览器应该为视频提供播放控件-->
    <!--preload="auto" 是否提前加载-->
    <!--autoplay 自动播放-->
    <!--loop=true 自动循环-->
    <!--data-setup='{"example_option":true}' 可以把一些属性写到这个里面来,如data-setup=
    
    {"autoplay":true}-->
    
    <video id="my-player" class="video-js vjs-default-skin vjs-big-play-centered" 
    
    controls preload="auto" autoplay="autoplay"
           poster="//vjs.zencdn.net/v/oceans.png" width="500" height="400" data-
    
    setup='{}'>
        <!--src: 规定媒体文件的 URL  type:规定媒体资源的类型-->
        <source src='rtmp://192.168.1.253:32781/live/test' type='rtmp/flv'/>
    </video>
    <script type="text/javascript">
        // 设置flash路径,用于在videojs发现浏览器不支持HTML5播放器的时候自动唤起flash播放器
        videojs.options.flash.swf = 'https://cdn.bootcss.com/videojs-swf/5.4.1/video-
    
    js.swf';
        var player = videojs('my-player'); //my-player为页面video元素的id
        player.play(); //播放
    //    1. 播放   player.play()
    //    2. 停止   player.pause()
    //    3. 暂停   player.pause()
    </script>
    </body>
    </html>

    2.推送视频流

    如果直接按照如下命令推送

    ffmpeg -f dshow -i video="Integrated Camera" -vcodec libx264 -acodec aac  -f flv rtmp://192.168.1.253:32781/live/test

    很有可能vlc ffplay可以正常拉流播放,但是网页播放不了,推荐一个网址测试对应的rtmp协议流是否能通过flash播放

    https://blog.csdn.net/liuzehn/article/details/81036195

    可用的RTMP源:http://www.mamicode.com/info-detail-2539819.html

    如果测试过程中能够接受到流,但是不能播放就是视频格式的问题,

    这时候使用如下的指令进行播放:

    ffmpeg.exe -f dshow -i video="Integrated Camera" -vcodec libx264 -pix_fmt yuv420p -f flv rtmp://192.168.1.253:32781/live/test

    其中 Integrated Camera 是摄像头的名字,如果是USB的则填写对应的名字

    具体的获得摄像头名称的操作方式参考:

    https://www.jianshu.com/p/c141fc7881e7

    3.推送视频流,hls播放

    推流指令如下:

    ffmpeg.exe -f dshow -i video="Integrated Camera" -vcodec libx264 -pix_fmt yuv420p -f flv rtmp://192.168.1.253:32781/hls/test

    移动端拉流代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    
        <title>Video.js | HTML5 Video Player</title>
        <!-- <link href="video-js-6.2.0/video-js.css" rel="stylesheet">
        <script src="video-js-6.2.0/videojs-ie8.min.js"></script> -->
    
        <link href="http://vjs.zencdn.net/5.20.1/video-js.css" rel="stylesheet">
        <script src="http://vjs.zencdn.net/5.20.1/videojs-ie8.min.js"></script>
        
    </head>
    <body>
    
    
      <video id="example_video_1" class="video-js vjs-default-skin" controls 
    
    preload="auto" width="1280" height="720" poster="http://vjs.zencdn.net/v/oceans.png" 
    
    data-setup="{}">
        <!-- <source src="1.mp4" type="video/mp4">  rtmp://192.168.1.253:32781/live/test 
    
    -->
        <source src="http://192.168.1.253:32780/hls/test.m3u8" type="application/x-
    
    mpegURL" >
        
        <p class="vjs-no-js">To view this video please enable JavaScript, and consider 
    
    upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" 
    
    target="_blank">supports HTML5 video</a></p>
      </video>
      <object height="900px" width="100%" classid="clsid:D27CDB6E-AE6D-11cf-96B8-
    
    444553540000" 
    
    codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#versio
    
    n=9,0,28,0" id="abcdef">
      <param value="index.swf(flash路径)" name="movie">
      <param value="high" name="quality">
      <param value="transparent" name="wmode">
      <embed height="900px" width="100%" name="abcdef" wmode="transparent" 
    
    type="application/x-shockwave-flash" 
    
    pluginspage="http://www.adobe.com/shockwave/download/download.cgi?
    
    P1_Prod_Version=ShockwaveFlash" quality="high" 
    
    src="rtmp://192.168.1.253:32781/live/test">
    </object>
      <script src="http://vjs.zencdn.net/5.20.1/video.js"></script>
    </body>
    
    </html>

    rtmp如果有vlc会有延迟,是vlc本身的缓存原因,ffplay几乎0延迟,PC版本的一秒左右延迟,m3u8分片的方式处理,所以延迟会比较明显。

    flv的直播 可参考连接https://hub.docker.com/r/mugennsou/nginx-http-flv ,但是需要注意的是

    如果要推送摄像头到服务器并在手机端显示,要参考下面的指令和代码:

    推送指令:

     ffmpeg -f dshow -i video="Integrated Camera" -vcodec libx264 -pix_fmt yuv420p  -f flv rtmp://192.168.1.253:32782/demo/stream-1 
    -pix_fmt yuv420p 这个参数很关键,是把摄像头或者是桌面的RGB编码转成H264转成YUV格式,最终转化成H264编码
     
    Html界面代码:
    <!DOCTYPE html>
    <html lang="en">
     
    <head>
        <title>video</title>
        <!-- Video.js -->
        <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
        <script src="https://unpkg.com/video.js/dist/video.min.js"></script>
        <script src="https://unpkg.com/flv.js/dist/flv.min.js"></script>
        <script src="https://unpkg.com/videojs-flvjs/dist/videojs-flvjs.min.js"></script>
    </head>
     
    <body>qwer
        <div>
            <video id="videojs-flvjs-player" class="video-js vjs-default-skin vjs-big-play-centered"  width="1024" height="768"> </video>
        </div>
    </body>
     
    </html>
    <script>
    var flvUrl = "http://192.168.1.253:32783/live?app=demo&stream=stream-1";
     //flvUrl="https://mister-ben.github.io/videojs-flvjs/bbb.flv"
    var player = videojs('videojs-flvjs-player', {
        techOrder: ['html5', 'flvjs'],
        flvjs: {
            mediaDataSource: {
                isLive: true,
                cors: true,
                withCredentials: false,
            },
        },
        sources: [{
            src: flvUrl,
            type: 'video/mp4'
        }],
        controls: true,
        preload: "none"
    }, function onPlayerReady() {
        console.log('player ready')
     
        player.on('error', (err) => {
            console.log('first source load fail')
     
            player.src({
                src: flvUrl,
                type: 'video/x-flv'
            });
     
            player.ready(function() {
                console.log('player ready')
                player.load();
                player.play();
            });
        })
    });
    </script>
    

    html文件最好是放到服务器中运行,本地打开的html页可能无法正常显示。

    下一篇再介绍基于websocket的移动端直播

  • 相关阅读:
    php编程规范整理
    约瑟夫环问题的实现
    MYSQL中SHOW的使用整理收藏
    mysql使用存储过程&函数实现批量插入
    浅谈select for update 和select lock in share mode的区别
    jQuery对象扩展方法(Extend)深度解析
    WCF系列教程之WCF操作协定
    WCF系列教程之WCF实例化
    WCF系列教程之WCF中的会话
    WCF系列教程之WCF服务协定
  • 原文地址:https://www.cnblogs.com/wanglg/p/11511468.html
Copyright © 2011-2022 走看看