本文使用node.js和ffmpeg实现了rtsp/rtmp直播流转m3u8

核心代码

const ffmpegPath = require('@ffmpeg-installer/ffmpeg')
const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const path = require('path')
const http = require('http')

ffmpeg.setFfmpegPath(ffmpegPath.path)

main()

function main () {
  const rtsp = 'rtmp://192.168.31.249:1935/live/test'
  const m3u8 = './m3u8/live.m3u8'
  transcoding(rtsp, m3u8)
  createServer(7777)
}

function transcoding (rtsp, m3u8) {
  ffmpeg(rtsp)
  .outputOptions([
    '-fflags flush_packets',
    '-max_delay 1',
    '-an',
    '-flags',
    '-global_header',
    '-hls_time 1',
    '-hls_list_size 3',
    '-hls_wrap 3',
    '-vcodec copy'
  ])
  .on('start', function(e) {
    console.log('---开始转码---')
    console.log(e);
  })
  .on('end', function() {
    console.log('file has been converted succesfully');
  })
  .on('error', function(err) {
    console.log('an error happened: ' + err.message);
    fun('error')
  })
  .save(m3u8)
}

function createServer (port) {
  const mimes = {
    'ts': 'video/MP2T',
    'm3u8': 'application/x-mpegURL'
  }
  const liveServer = http.createServer((request, response) => {
    const urlArrs = request.url.split('.')
    const extension = urlArrs[urlArrs.length - 1]
    if (extension === 'ts') {
      try {
        response.setHeader('Content-Type', mimes['ts'])
        fs.createReadStream(path.join('./m3u8', request.url)).pipe(response)
      } catch (error) {
        response.end('hello world')
      }
    } else if (extension === 'm3u8') {
      try {
        response.setHeader('Content-Type', mimes['m3u8'])
        fs.createReadStream(path.join('./m3u8', request.url)).setEncoding('utf8').pipe(response)
      } catch (error) {
        response.end('hello world')
      }
    } else if (extension === 'html') {
      try {
        fs.createReadStream(path.join('./', request.url)).setEncoding('utf8').pipe(response)
      } catch (error) {
        response.end('hello world')
      }
    } else {
      response.end('hello world')
    }
  })
  
  liveServer.listen(port, err => {
    console.log(err)
    console.log(`liveServer run ${port}`)
  })
}
  • fluent-ffmpeg是ffmpeg的nodejs实现。你也可以使用child_process直接调用ffmpeg命令,原理是一样的。
  • @ffmpeg-installer/ffmpeg是一个ffmpeg安装器,可以根据当前系统安装对应的可执行文件。这里指定了ffmpeg的路径使用项目中下载好的。如果不指定会使用系统安装好的ffmpeg
  • fluent-ffmpeg会把参数转化为ffmpeg命令,ffmpeg -i rtmp://192.168.31.249:1935/live/test -y -fflags flush_packets -max_delay 1 -an -flags -global_header -hls_time 1 -hls_list_size 3 -hls_wrap 3 -vcodec copy ./m3u8/live.m3u8

demo源码:https://github.com/blogwy/personal-practice/tree/master/rtsp-to-m3u8