Skip to content

Commit

Permalink
feat:  add support live 
Browse files Browse the repository at this point in the history
  • Loading branch information
hejianglin committed Mar 30, 2023
1 parent b8519ba commit 47fb82f
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 77 deletions.
Binary file modified .DS_Store
Binary file not shown.
Binary file added .gitignore.swp
Binary file not shown.
32 changes: 32 additions & 0 deletions 1.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
server {
listen 80;
listen 443 ssl http2;
# listen [::]:80;
server_name cn.oimi.space;
#root /usr/share/nginx/html;
ssl_certificate /home/cn.oimi.space.pem; # 证书
ssl_certificate_key /home/cn.oimi.space.key; # 证书秘钥
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #协议
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# sessions时长
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000"; # 配置之后只能通过https访问网站
# Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://127.0.0.1:3008/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
}
error_page 404 /404.html;
location = /404.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
48 changes: 41 additions & 7 deletions bin/m3u8.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @version 1.0.0
*/

let ffmpeg = require('fluent-ffmpeg')
const ffmpeg = require('fluent-ffmpeg')
/**
* A class to convert M3U8 to MP4
* @class
Expand All @@ -18,7 +18,7 @@ class m3u8ToMp4Converter {
setInputFile (filename) {
if (!filename) throw new Error('You must specify the M3U8 file address')
this.M3U8_FILE = filename

this.PROTOCOL_TYPE = this.getProtocol(this.M3U8_FILE)
return this
}

Expand All @@ -45,16 +45,52 @@ class m3u8ToMp4Converter {
}
return this
}

/**
* 获取地址协议
* @date 3/30/2023 - 11:50:14 AM
* @author hejianglin
* @param {*} url
* @returns {("live" | "m3u8" | "mp4" | "unknown")}
*/
getProtocol (url) {
switch (true) {
case url.startsWith('rtmp://'):
case url.startsWith('rtsp://'):
return 'live'
case url.endsWith('m3u8'):
return 'm3u8'
default:
return 'unknown'
}
}

setOutputOption (ffmpegCmd) {
const liveProtocol = this.PROTOCOL_TYPE
if (liveProtocol === 'live') {
ffmpegCmd.outputOptions('-c:v copy')
.outputOptions('-c:a aac')
.outputOptions('-b:a 128k')
.output(this.OUTPUT_FILE)
} else if (liveProtocol === 'm3u8') {
ffmpegCmd.outputOptions('-c:v copy')
.outputOptions('-bsf:a aac_adtstoasc')
.output(this.OUTPUT_FILE)
}
}

/**
* Starts the process
*/
* Starts the process
*/
start () {
return new Promise((resolve, reject) => {
if (!this.M3U8_FILE || !this.OUTPUT_FILE) {
reject(new Error('You must specify the input and the output files'))
return
}
if (this.PROTOCOL_TYPE === 'unknown') {
reject(new Error('the protocol is not supported, please specify the protocol type: m3u8 or rtmp、 rtsp'))
}
const ffmpegCmd = ffmpeg(this.M3U8_FILE)
.on('error', error => {
reject(new Error(error))
Expand All @@ -66,9 +102,7 @@ class m3u8ToMp4Converter {
ffmpegCmd.outputOptions(`-threads ${this.THREADS}`)
ffmpegCmd.outputOptions('-preset ultrafast')
}
ffmpegCmd.outputOptions('-c copy')
.outputOptions('-bsf:a aac_adtstoasc')
.output(this.OUTPUT_FILE)
this.setOutputOption(ffmpegCmd)
ffmpegCmd.run()
})
}
Expand Down
62 changes: 62 additions & 0 deletions bin/recorder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
let ffmpeg = require('fluent-ffmpeg')

class LiveRecorder {
/**
* Sets the input file
* @param {String} filename M3U8 file path. You can use remote URL
* @returns {Function}
*/
setInputFile (url) {
this.RECORDER_URl = url
return this
}

/**
* Sets the output file
* @param {String} filename Output file path. Has to be local :)
* @returns {Function}
*/
setOutputFile (filename) {
this.DOWNLOAD_FILENAME = filename
return this
}

/**
* Sets the thread
* @param {Number} number thread number
* @returns {Function}
*/
setThreads (number) {
if (number) {
this.THREADS = number
}
return this
}

start () {
return new Promise((resolve, reject) => {
if (!this.RECORDER_URl || !this.DOWNLOAD_FILENAME) {
reject(new Error('You must specify the input and the output files'))
return
}
const ffmpegCmd = ffmpeg(this.RECORDER_URl)
.on('error', error => {
reject(new Error(error))
})
.on('end', () => {
resolve()
})
if (this.THREADS) {
ffmpegCmd.outputOptions(`-threads ${this.THREADS}`)
ffmpegCmd.outputOptions('-preset ultrafast')
}
ffmpegCmd.outputOptions('-c:v copy')
.outputOptions('-c:a aac')
.outputOptions('-b:a 128k')
.output(this.DOWNLOAD_FILENAME)
ffmpegCmd.run()
})
}
}

module.exports = LiveRecorder
69 changes: 1 addition & 68 deletions bin/utils/core.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/** process operation、file download、cmd exec */
const childProcess = require('child_process')
const process = require('process')
const pidusage = require('pidusage')
const si = require('systeminformation')
const os = require('os')
const m3u8ToMp4 = require('../m3u8')
Expand All @@ -10,71 +8,6 @@ const { msg } = require('./message')
const converter = new m3u8ToMp4()
const cpuNum = os.cpus().length

const KILLPROCEETIMEOUT = 3000 // 300000
/**
* @description kill a process by pid
* @param {string} pid process pid
*/
const killPidAtLowusage = (pid) => {
pidusage(pid, function (err, result) {
if (err) {
console.log('get pid usage error:' + err)
} else if (result.cpu + '' === '0') {
console.log('CPU usage is too low, killing process:' + pid, result.cpu)
logger.warn('CPU usage is too low, killing process:' + pid, result.cpu)
process.kill(pid)
} else {
console.log('FFMPEG PID:' + pid + ', CPU:' + result.cpu)
}
})
}
/**
* @description query process pid by keywords
* @param {string} query
* @param {function} cb callback
*/
const getProcessPidByQuery = (query, cb) => {
let platform = process.platform
let cmd = ''
switch (platform) {
case 'win32':
cmd = 'tasklist'
break
case 'darwin':
cmd = `ps -ax | grep ${query}`
break
case 'linux':
cmd = 'ps -A'
break
default:
break
}
childProcess.exec(cmd, (err, stdout, stderr) => {
if (err) {
console.log('Exec findProcess error:' + err)
}
if (stdout) {
const list = stdout
.split(/[\r\n\t]/)
.filter((i) => i && i.indexOf('grep') === -1)
const queryList = list
.filter((i) => i.includes(query))
.map((string) => string.match(/\d+/)[0])
cb(queryList)
}
})
}
/**
* @description kill death ffmpeg process
*/
const killToDeathFfmeg = () => {
const ffmpegKill = () => getProcessPidByQuery('ffmpeg -i', list => list.forEach((i) => killPidAtLowusage(i)))
ffmpegKill()
setInterval(() => {
ffmpegKill()
}, KILLPROCEETIMEOUT)
}

/**
* @description exec command
* @date 3/16/2023 - 11:52:03 AM
Expand Down Expand Up @@ -156,4 +89,4 @@ const download = (url, name, filePath, { webhooks, webhookType, downloadThread }
})
}

module.exports = { killToDeathFfmeg, chmod, getNetwork, download }
module.exports = { chmod, getNetwork, download }
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"pkg": "pkg ./ --debug=true",
"auto": "npm run build && npm run rmi && npm run build:dockerimage",
"build": "npm run clean && npm run pkg",
"rmi": "docker rmi h55205l/ffandown:v3",
"build:dockerimage": "docker build . -t h55205l/ffandown:v3",
"rmi": "docker rmi h55205l/ffandown:latest",
"build:dockerimage": "docker build . -t h55205l/ffandown:latest",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
Expand Down

0 comments on commit 47fb82f

Please sign in to comment.