孚优阁

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1235|回复: 4

node.js实现ffmpeg动态切换输入源推流

[复制链接]

16

主题

16

帖子

100

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
100
发表于 2022-8-18 18:40:50 | 显示全部楼层 |阅读模式

node.js自己已经封装了ffmpeg了,但是依然没有解决动态改变输入源的方法,因为ffmpeg同一个进程只接受一个输入源,这个输入源可以是文件路径,也可以是一个可读的流数据。起初的想法是用开启一个进程的方法

const spawn = require('child_process').spawn
  • 1

我们来操作命令去不断结束上一次操作然后重新操作指令,但是我们推流到服务器的话,发现服务器要重新接受数据,而且如果操作频繁的话,对于关闭开启的子进程比较麻烦,在用进程命令调用ffmpeg时,因为,ffmpeg也是一个进程,所以一旦执行命令,就说额外开启了两个进程,关闭进程很麻烦。

const Ffmpegs = require('fluent-ffmpeg')
  • 1

后来发现node.js本身是有封装的对ffmpeg。用法如下

        playsure = new Ffmpegs()    playsure.input('E://KuGou//08.mp3')    playsure.inputOption('-re')    playsure.outputOptions([      '-rtsp_transport',          'tcp',          '-f',          'rtsp'   ])    playsure.output('rtsp://47.103.130.92:554')    playsure.run()    playsure.on('end', () => {      console.log('结束end')    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

进行向特定服务器推流。我们指定了一帧一帧的推,且是tcp方式推送rtsp流。
这样也实现了推流的效果,但是当你重新指定输入源的时候是不允许的,需要先结束之前的ffmpeg在指定ffmpeg输入源,这样还是要先断开一次连接,服务器那边还要重新接受数据才行。
后来想到用管道来传输,想的只用改变输入端的数据,将管道的输出端放到ffmpeg的输入端,只要不关闭管道,因该就可以实现输入源的切换,进行了多方搜索,发现在node.js中只能有

var fs = require('fs')var rs = fs.createReadStream('E://KuGou//08.mp3', { highWaterMark: 4608 })var ws = fs.createWriteStream('E://KuGou//')fs.pipe(ws)
  • 1
  • 2
  • 3
  • 4

这两个数据流进行管道操作,也有双工流,是有读写功能的,但是没有研究出来同时读写操作。
显然我们操作ffmpeg需要的是能读能写的管道,而且不能关闭。后来想到了我们本来就是用的tcp协议的,tcp的socket也可以充当管道作用,它也是用来分发数据的。于是乎我又写了tcp客户端和服务器接收端专门用socket来充当管道。

server:

var net = require('net')var  TcpServer = net.createServer()    TcpServer.listen(3000, function () {      console.log('tcp_server listening 3000')    })       TcpServer.on('connection', (Socket) => {              if (trsocket) {               var playsure1 = new Ffmpegs()                playsure1.input(Socket)                playsure1.inputOption('-re')                playsure1.outputOptions([                  '-rtsp_transport',                  'tcp',                  '-f',                  'rtsp'                ])                playsure1.pipe('rtsp://47.103.130.92:554')              }      Socket.on('data', (data) => {        console.log('接受到数据:')        // console.log('read data ', data)      })        .on('close', () => {          console.log('close server')        })        .on('error', (error) => {          console.log('error :' + error)        })    })
  • 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

client

var options = {  host: '127.0.0.1',  port: 3000}var Tcpclient = new net.Socket()         Tcpclient.connect(options, () => {         var playsure = new Ffmpegs()     var rs = fs.ReadStream('E://KuGou//08.mp3')        rs.pipe(Tcpclient)      console.log('开始发送数据:')    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这个可以实现tcp传输了,但是当一首歌传完,socket尽然也自动断开连接了。无语。。。。
还是server主动断开的。
后来尝试去找ffmpeg传输结束发出的信号,发现它就是会自动断开连接。于是我将它的设置更改一下

playsure1.pipe('rtsp://47.103.130.92:554', { end: false, autoClose: false })//不让它结束后断开连接
  • 1

对ffmpeg的输出进行了设置。但是发现还是会断开socket,于是想是不是和输入端有关
对输入端进行更改

rs.pipe(Tcpclient, { end: false, autoClose: false })
  • 1

是的它不断开连接,感觉接近成功了。
但是我去操作输入文件的时候发现不行,还是改不了输入源(可能方法不对,后面没有直接更改文件)
考虑到我们要控制输入源,还要实现随时停止等操作,要对输入传输速度有要求。想到ffmpeg本身就可以设置输出格式,于是干脆在客户端直接在创建一个ffmpeg来控制传输速度和格式客户端的代码改变如下

        var Tcpclient = null    Tcpclient = new net.Socket()   var playsure = new Ffmpegs()    Tcpclient.connect(options, () => {      playsure.input('E://KuGou//08.mp3')      playsure.inputOption('-re')      playsure.outputOptions([        '-rtsp_transport',        'tcp',        '-f',        'mp3'      ])      playsure.output(Tcpclient, { end: false, autoClose: false })      playsure.run()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

因为现在socket已经不会断开了,所以我们可以更改输入源的数据了,client里面的ffmpeg只是用来控制数据格式的,我们只用记录好当前连接的socket只向它里面传输数据就可以了。client中的ffmpeg我们可以随意断开,进行切换传到socket中的数据进而实现动态切换ffmpeg的输入数据的,当ffmpeg传输结束会抛出end信号

playsure.on('end', () => {       console.log('数据传输结束')      })
  • 1
  • 2
  • 3

关闭ffmpeg在node.js中我使用kill()来结束的,但是ffmpeg结束是结束了,就是会跑出来一个错误

Error: ffmpeg was killed with signal SIGKILL
  • 1

目前还没有对它进行研究,我是直接把它try掉了,没有管,下次重新调用的时候也没有问题。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|源码|孚优阁

GMT+8, 2024-5-14 14:39 , Processed in 0.113714 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表