做一个海康摄像头转hls然后使用h5方式播放的细节问题

jiechengyang
  • 5
新手上路,请多包涵

最近项目有个功能就是在一个android系统的大平板(专业名词忘记了)的Chrome浏览器上预览海康摄像头,大平板开机就会自动打开浏览器并打开我们的站点。

  • 从客户那里了解,这些摄像头并没有接入海康的萤石云等平台。
  • 根据我们工程的说法,海康早先提供了基于ActiveX的视频播放插件,插件是通过刻录机在播放摄像头。
  • 这样的方案和我们的浏览器不符合,无法使用。我们想到的第二个方案就是转成h5能播放的流媒体协议。
  • 项目的服务器是window,目前就在windows环境搭建的测试代码且使用nodejs开发。安装好FFmpeg后,借助了fluent-ffmpeg包来操作FFmpeg并转流,在用nginx搭建一个web服务器,并把根目录设置在生成m3u8的目录下,并配置下,让其生成一个可播放的url地址
            add_header Cache-Control no-cache;
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            add_header 'Access-Control-Allow-Headers' 'Range';
            types{
                    application/dash+xml mpd;
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
             }

然后播放插件我们用的是video.js和ckpplayer。通过我们写的测试代码基本论证这方案可行,满足了服务器是windows,且能使用h5方式播放

  • 项目运行在局域网,使用FFmpeg把rtsp转成hls播放,目前延时在10秒,能接受。

整个方案我们认为是可行的,然后就是整个方案细节的处理优化,对于流媒体,我只能说接触过,使用开源的流媒体服务器搭建,了解FFmpeg工具,但并不深入。因此在这样的一个方案想出来之后,我脑海里也是产生了很多的思考,但目前还没有完整的思路完成这个方案的代码。

    来到这里,就是为了得到广大网友,道友,大神的指点与帮助,请看到的朋友不吝您的指点。小弟我先把我想到的说出来

    * 第一点:首先整体需要一个http服务,一个tcp服务,http服务主要是用于客户端通过摄像头唯一编码来获取hls的播放地址,tcp服务主要是视频转码的操作。
    这个tcp服务是整个功能的中心点,我对这个tcp服务的想法是:首先服务启动便开始对局域网已知的摄像头(这些摄像头会通过http服务去录入到数据库,数量不多,我们直接写json文件)去转流,使用工具就是fluent-ffmpeg。
    假设有10个摄像头,那在tcp服务这里,会生成一个摄像头编码与输出m3u8的文件数组,这里的文件名都是以时间戳为名称的。且10个摄像头对应10个文件夹

    let cameras = [
        {
            code: 1001,
            livePath: '/1001/193920392031/193920392031.m3u8'
        }
    ]

    ??这里的问题就是出现转流失败的摄像头如何检测??---看fluent-ffmpeg

    fluent-ffmpeg启动后是一直阻塞的

    * 第二点:客户端请求http服务,http服务在请求tcp服务,返回播放地址

    * 第三点: 当所有客户端不在观看时,应当关闭某个或某多个摄像头的转流。如何处理,我想的时候在http服务里,客户端第一次访问播放文件,我就用一个数组存放该播放文件被那些客户端访问且访问时间是好久的数组,当客户端断开,我便又把某个客户端从这个数组里删掉,再用一个定时器去监听各播放文件数组的变化,当超过30分钟(临界值),某个播放文件里面没有客户端时,我便认为没人看了,没人看了,我就通过http服务发送给tcp服务一个关闭某个摄像头转流的命令,tcp那边就把该播放文件对应的url作废,在删除它的m3u8文件和ts文件和目录,然后使用fluent-ffmpeg重新对该播放文件对应的摄像头转流并生成写的文件路径(??? fluent-ffmpeg能否有这样的操作,没有该怎么办???)

    * 第四点: 客户端每次请求我想返回的播放url都是不一样的,这个时候tcp服务也许不应该一开始就把所有摄像头都转流,而是收到请求在转。返回新地址过后,旧地址仍然可以使用,仅当第三点才会清除
    * 第五点: 定时清理播放文件,当转流服务关闭,无论是正常还是异常,我在tcp设置一个定时器,去监听各个已有的m3u8的文件的文件更新时间,如果时间超过临界值就删除对应的文件目录

    疑问:
        1、tcp服务启动后就把所有转流开启?
        2、转流开启是一直阻塞的,需要使用子进程处理么,还是使用事件异步处理?
        3、不同客户端请求同一个摄像头生成的不同播放地址,到底什么时候才会清除这些文件?
        4、什么时候全部关闭转流服务(fluent-ffmpeg)

    相关代码:

// fluent-ffmpeng进程发信号
    const command = ffmpeg(__dirname + '/test.mp4', {timeout: 432000}).addOptions([
'-profile:v baseline', // baseline profile (level 3.0) for H264 video codec
'-level 3.0',
'-s 640x360',          // 640px width, 360px height output video dimensions
'-start_number 0',     // start the first .ts segment at index 0
'-hls_time 10',        // 10 second segment duration
'-hls_list_size 0',    // Maxmimum number of playlist entries (0 means all entries/infinite)
'-f hls'
    ])
.output(tspath + '/output.test.m3u8')
// .on('start', function () {
//     // Send SIGSTOP to suspend ffmpeg
//     command.kill('SIGSTOP');
//
//     // doSomething(function () {
//     //     // Send SIGCONT to resume ffmpeg
//     //     command.kill('SIGCONT');
//     // });
// })
.on('error', function (err) {
    console.log('An error occurred: ' + err.message);
})
.on('end', function () {
    console.log('Finished processing');
}).run();
    
    setTimeout(function () {
command.on('error', function () {
    console.log('Ffmpeg has been killed');
});
    
command.kill();
    }, 60000);

整个效果就是达到播放文件顺利的生成和删除,不影响客户端的观看,服务端顺利的清除播放文件,合理的关闭转流服务,合理的开启转流服务

回复
阅读 7.2k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏