refactor: update dependencies and remove unused packages in package.json and pnpm-lock.yaml

This commit is contained in:
Elysia
2024-11-27 19:49:41 +07:00
parent 5f9ac34780
commit 30a714786f
5 changed files with 151 additions and 122 deletions

View File

@@ -55,13 +55,13 @@
"@discordjs/collection": "^1.5.3", "@discordjs/collection": "^1.5.3",
"@sapphire/async-queue": "^1.5.3", "@sapphire/async-queue": "^1.5.3",
"@sapphire/shapeshift": "^3.9.5", "@sapphire/shapeshift": "^3.9.5",
"deasync": "^0.1.30",
"discord-api-types": "^0.37.103", "discord-api-types": "^0.37.103",
"fetch-cookie": "^2.1.0", "fetch-cookie": "^2.1.0",
"find-process": "^1.4.7", "fluent-ffmpeg": "^2.1.3",
"prism-media": "^1.3.5", "prism-media": "^1.3.5",
"qrcode": "^1.5.4", "qrcode": "^1.5.4",
"tough-cookie": "^4.1.4", "tough-cookie": "^4.1.4",
"tree-kill": "^1.2.2",
"undici": "^6.21.0", "undici": "^6.21.0",
"ws": "^8.16.0" "ws": "^8.16.0"
}, },

76
pnpm-lock.yaml generated
View File

@@ -20,15 +20,18 @@ importers:
'@sapphire/shapeshift': '@sapphire/shapeshift':
specifier: ^3.9.5 specifier: ^3.9.5
version: 3.9.7 version: 3.9.7
deasync:
specifier: ^0.1.30
version: 0.1.30
discord-api-types: discord-api-types:
specifier: ^0.37.103 specifier: ^0.37.103
version: 0.37.103 version: 0.37.103
fetch-cookie: fetch-cookie:
specifier: ^2.1.0 specifier: ^2.1.0
version: 2.2.0 version: 2.2.0
find-process: fluent-ffmpeg:
specifier: ^1.4.7 specifier: ^2.1.3
version: 1.4.7 version: 2.1.3
prism-media: prism-media:
specifier: ^1.3.5 specifier: ^1.3.5
version: 1.3.5 version: 1.3.5
@@ -38,9 +41,6 @@ importers:
tough-cookie: tough-cookie:
specifier: ^4.1.4 specifier: ^4.1.4
version: 4.1.4 version: 4.1.4
tree-kill:
specifier: ^1.2.2
version: 1.2.2
undici: undici:
specifier: ^6.21.0 specifier: ^6.21.0
version: 6.21.0 version: 6.21.0
@@ -848,6 +848,9 @@ packages:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
async@0.2.10:
resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
asynckit@0.4.0: asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -901,6 +904,9 @@ packages:
bcrypt-pbkdf@1.0.2: bcrypt-pbkdf@1.0.2:
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
bluebird@3.7.2: bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
@@ -1093,10 +1099,6 @@ packages:
commander@2.20.3: commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
commander@5.1.0:
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
engines: {node: '>= 6'}
commander@9.5.0: commander@9.5.0:
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
engines: {node: ^12.20.0 || >=14} engines: {node: ^12.20.0 || >=14}
@@ -1249,6 +1251,10 @@ packages:
dateformat@3.0.3: dateformat@3.0.3:
resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
deasync@0.1.30:
resolution: {integrity: sha512-OaAjvEQuQ9tJsKG4oHO9nV1UHTwb2Qc2+fadB0VeVtD0Z9wiG1XPGLJ4W3aLhAoQSYTaLROFRbd5X20Dkzf7MQ==}
engines: {node: '>=0.11.0'}
debug@3.2.7: debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies: peerDependencies:
@@ -1633,14 +1639,13 @@ packages:
resolution: {integrity: sha512-B/SdeSIeRv7VlOgIjtH3dkxMI+tEy5m+OeCXfAUsirBoVoY+bGtsmvmmTFPm/G23TBY4RiTtjpcgePCfwXRjqA==} resolution: {integrity: sha512-B/SdeSIeRv7VlOgIjtH3dkxMI+tEy5m+OeCXfAUsirBoVoY+bGtsmvmmTFPm/G23TBY4RiTtjpcgePCfwXRjqA==}
engines: {node: '>=8'} engines: {node: '>=8'}
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
fill-range@7.1.1: fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'} engines: {node: '>=8'}
find-process@1.4.7:
resolution: {integrity: sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==}
hasBin: true
find-replace@3.0.0: find-replace@3.0.0:
resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
@@ -1675,6 +1680,10 @@ packages:
flatted@3.3.1: flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
fluent-ffmpeg@2.1.3:
resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==}
engines: {node: '>=18'}
for-each@0.3.3: for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -2670,6 +2679,9 @@ packages:
nice-try@1.0.5: nice-try@1.0.5:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
node-addon-api@1.7.2:
resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
node-fetch@2.7.0: node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0} engines: {node: 4.x || >=6.0.0}
@@ -3530,10 +3542,6 @@ packages:
tr46@0.0.3: tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
trim-newlines@3.0.1: trim-newlines@3.0.1:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -4871,6 +4879,8 @@ snapshots:
astral-regex@2.0.0: {} astral-regex@2.0.0: {}
async@0.2.10: {}
asynckit@0.4.0: {} asynckit@0.4.0: {}
available-typed-arrays@1.0.7: available-typed-arrays@1.0.7:
@@ -4950,6 +4960,10 @@ snapshots:
dependencies: dependencies:
tweetnacl: 0.14.5 tweetnacl: 0.14.5
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
bluebird@3.7.2: {} bluebird@3.7.2: {}
brace-expansion@1.1.11: brace-expansion@1.1.11:
@@ -5164,8 +5178,6 @@ snapshots:
commander@2.20.3: {} commander@2.20.3: {}
commander@5.1.0: {}
commander@9.5.0: {} commander@9.5.0: {}
common-sequence@2.0.2: {} common-sequence@2.0.2: {}
@@ -5372,6 +5384,11 @@ snapshots:
dateformat@3.0.3: {} dateformat@3.0.3: {}
deasync@0.1.30:
dependencies:
bindings: 1.5.0
node-addon-api: 1.7.2
debug@3.2.7: debug@3.2.7:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@@ -5881,18 +5898,12 @@ snapshots:
array-back: 4.0.2 array-back: 4.0.2
glob: 7.2.3 glob: 7.2.3
file-uri-to-path@1.0.0: {}
fill-range@7.1.1: fill-range@7.1.1:
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
find-process@1.4.7:
dependencies:
chalk: 4.1.2
commander: 5.1.0
debug: 4.3.5(supports-color@9.4.0)
transitivePeerDependencies:
- supports-color
find-replace@3.0.0: find-replace@3.0.0:
dependencies: dependencies:
array-back: 3.1.0 array-back: 3.1.0
@@ -5931,6 +5942,11 @@ snapshots:
flatted@3.3.1: {} flatted@3.3.1: {}
fluent-ffmpeg@2.1.3:
dependencies:
async: 0.2.10
which: 1.3.1
for-each@0.3.3: for-each@0.3.3:
dependencies: dependencies:
is-callable: 1.2.7 is-callable: 1.2.7
@@ -7165,6 +7181,8 @@ snapshots:
nice-try@1.0.5: {} nice-try@1.0.5: {}
node-addon-api@1.7.2: {}
node-fetch@2.7.0(encoding@0.1.13): node-fetch@2.7.0(encoding@0.1.13):
dependencies: dependencies:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
@@ -8039,8 +8057,6 @@ snapshots:
tr46@0.0.3: {} tr46@0.0.3: {}
tree-kill@1.2.2: {}
trim-newlines@3.0.1: {} trim-newlines@3.0.1: {}
ts-mixer@6.0.4: {} ts-mixer@6.0.4: {}

View File

@@ -4,8 +4,6 @@ const { Buffer } = require('node:buffer');
const crypto = require('node:crypto'); const crypto = require('node:crypto');
const { Writable } = require('node:stream'); const { Writable } = require('node:stream');
const { setTimeout } = require('node:timers'); const { setTimeout } = require('node:timers');
const find = require('find-process');
const kill = require('tree-kill');
const secretbox = require('../util/Secretbox'); const secretbox = require('../util/Secretbox');
const CHANNELS = 2; const CHANNELS = 2;
@@ -144,21 +142,17 @@ class BaseDispatcher extends Writable {
} }
_cleanup() { _cleanup() {
if (this.player.dispatcher === this) this.player.dispatcher = null; if (this.player.dispatcher === this) {
if (this.player.videoDispatcher === this) this.player.videoDispatcher = null; this.player.dispatcher.destroy();
this.player.dispatcher = null;
}
if (this.player.videoDispatcher === this) {
this.player.videoDispatcher.destroy();
this.player.videoDispatcher = null;
}
const { streams } = this; const { streams } = this;
if (streams.opus) streams.opus.destroy(); if (streams.opus) streams.opus.destroy();
if (streams.ffmpeg?.process) { streams.ffmpeg?.destroy();
const ffmpegPid = streams.ffmpeg.process.pid; // But it is ppid ;-;
const args = streams.ffmpeg.process.spawnargs.slice(1).join(' '); // Skip ffmpeg
find('name', 'ffmpeg', true).then(list => {
let process = list.find(o => o.pid === ffmpegPid || o.ppid === ffmpegPid || o.cmd.includes(args));
if (process) {
kill(process.pid);
}
});
streams.ffmpeg.destroy();
}
} }
/** /**

View File

@@ -19,6 +19,8 @@ Please use the @dank074/discord-video-stream library for the best support.
const EventEmitter = require('events'); const EventEmitter = require('events');
const { Readable: ReadableStream } = require('stream'); const { Readable: ReadableStream } = require('stream');
const deasync = require('deasync');
const fluent = require('fluent-ffmpeg');
const prism = require('prism-media'); const prism = require('prism-media');
const { H264NalSplitter } = require('./processing/AnnexBNalSplitter'); const { H264NalSplitter } = require('./processing/AnnexBNalSplitter');
const { IvfTransformer } = require('./processing/IvfSplitter'); const { IvfTransformer } = require('./processing/IvfSplitter');
@@ -26,20 +28,40 @@ const { H264Dispatcher } = require('../dispatcher/AnnexBDispatcher');
const AudioDispatcher = require('../dispatcher/AudioDispatcher'); const AudioDispatcher = require('../dispatcher/AudioDispatcher');
const { VP8Dispatcher } = require('../dispatcher/VPxDispatcher'); const { VP8Dispatcher } = require('../dispatcher/VPxDispatcher');
const FFMPEG_ARGUMENTS = [ const FFMPEG_OUTPUT_PREFIX = ['-use_wallclock_as_timestamps', '1', '-copyts', '-analyzeduration', '0'];
'-use_wallclock_as_timestamps', const FFMPEG_INPUT_PREFIX = [
'-reconnect',
'1', '1',
'-copyts', '-reconnect_at_eof',
'-analyzeduration', '1',
'0', '-reconnect_streamed',
'-loglevel', '1',
'0', '-reconnect_delay_max',
'4294',
];
const FFMPEG_PCM_ARGUMENTS = ['-f', 's16le', '-ar', '48000', '-ac', '2'];
const FFMPEG_VP8_ARGUMENTS = ['-f', 'ivf', '-deadline', 'realtime', '-c:v', 'libvpx'];
const FFMPEG_H264_ARGUMENTS = options => [
'-c:v',
'libx264',
'-f', '-f',
's16le', 'h264',
'-ar', '-tune',
'48000', 'zerolatency',
'-ac', // '-pix_fmt',
'2', // 'yuv420p',
'-preset',
options?.presetH26x || 'faster',
'-profile:v',
'baseline',
// '-g',
// `${options?.fps}`,
// '-x264-params',
// `keyint=${options?.fps}:min-keyint=${options?.fps}`,
'-bf',
'0',
'-bsf:v',
'h264_metadata=aud=insert',
]; ];
/** /**
@@ -84,27 +106,22 @@ class MediaPlayer extends EventEmitter {
playUnknown(input, options, streams = {}) { playUnknown(input, options, streams = {}) {
this.destroyDispatcher(); this.destroyDispatcher();
const isStream = input instanceof ReadableStream; const isStream = input instanceof ReadableStream;
const args = [...FFMPEG_OUTPUT_PREFIX, ...FFMPEG_PCM_ARGUMENTS];
const args = isStream ? FFMPEG_ARGUMENTS.slice() : ['-i', input, ...FFMPEG_ARGUMENTS]; if (!isStream) args.unshift('-i', input);
if (options.seek) args.unshift('-ss', String(options.seek)); if (options.seek) args.unshift('-ss', String(options.seek));
// Check input // Check input
if (typeof input == 'string' && input.startsWith('http')) { if (typeof input == 'string' && input.startsWith('http')) {
args.unshift( args.unshift(...FFMPEG_INPUT_PREFIX);
'-reconnect',
'1',
'-reconnect_at_eof',
'1',
'-reconnect_streamed',
'1',
'-reconnect_delay_max',
'4294',
);
} }
const ffmpeg = new prism.FFmpeg({ args }); const ffmpeg = new prism.FFmpeg({ args });
this.emit('debug', `[ffmpeg-audio_process] Spawn process with args:\n${args.join(' ')}`);
ffmpeg.process.stderr.on('data', data => {
this.emit('debug', `[ffmpeg-audio_process]: ${data.toString()}`);
});
streams.ffmpeg = ffmpeg; streams.ffmpeg = ffmpeg;
if (isStream) { if (isStream) {
streams.input = input; streams.input = input;
@@ -144,19 +161,51 @@ class MediaPlayer extends EventEmitter {
playUnknownVideo(input, options = {}) { playUnknownVideo(input, options = {}) {
this.destroyVideoDispatcher(); this.destroyVideoDispatcher();
const isStream = input instanceof ReadableStream; const isStream = input instanceof ReadableStream;
// Get video info
let isDone = false;
let data = null;
if (!options?.fps) {
fluent.ffprobe(input, (err, metadata) => {
if (err) {
this.emit('error', err);
isDone = true;
return;
}
let hasAudio = false;
let hasVideo = false;
let fps = 0;
metadata.streams.forEach(stream => {
if (stream.codec_type === 'audio') {
hasAudio = true;
}
if (stream.codec_type === 'video') {
hasVideo = true;
if (stream.avg_frame_rate) {
const frameRate = stream.avg_frame_rate.split('/');
fps = parseFloat(frameRate[0]) / parseFloat(frameRate[1]);
} else if (stream.r_frame_rate) {
const frameRate = stream.r_frame_rate.split('/');
fps = parseFloat(frameRate[0]) / parseFloat(frameRate[1]);
}
}
});
data = {
audio: hasAudio,
video: hasVideo,
fps: hasVideo ? fps : null,
};
isDone = true;
});
deasync.loopWhile(() => !isDone);
}
if (!options?.fps) options.fps = 30; if (!options?.fps) options.fps = data?.fps || 30;
const args = [ const args = [
'-i', '-i',
'-', isStream ? '-' : input,
'-use_wallclock_as_timestamps', ...FFMPEG_OUTPUT_PREFIX,
'1',
'-copyts',
'-analyzeduration',
'0',
'-flags', '-flags',
'low_delay', 'low_delay',
'-r', '-r',
@@ -167,10 +216,6 @@ class MediaPlayer extends EventEmitter {
args.push('-b:v', `${options?.bitrate}K`); args.push('-b:v', `${options?.bitrate}K`);
} }
if (!isStream) {
args[1] = input;
}
if (options?.hwAccel === true) { if (options?.hwAccel === true) {
args.unshift('-hwaccel', 'auto'); args.unshift('-hwaccel', 'auto');
} }
@@ -179,47 +224,17 @@ class MediaPlayer extends EventEmitter {
// Check input // Check input
if (typeof input == 'string' && input.startsWith('http')) { if (typeof input == 'string' && input.startsWith('http')) {
args.unshift( args.unshift(...FFMPEG_INPUT_PREFIX);
'-reconnect',
'1',
'-reconnect_at_eof',
'1',
'-reconnect_streamed',
'1',
'-reconnect_delay_max',
'4294',
);
} }
// Get stream type // Get stream type
if (this.voiceConnection.videoCodec == 'VP8') { if (this.voiceConnection.videoCodec == 'VP8') {
args.push('-f', 'ivf', '-deadline', 'realtime', '-c:v', 'libvpx'); args.push(...FFMPEG_VP8_ARGUMENTS);
// Remove '-speed', '5' bc bad quality // Remove '-speed', '5' bc bad quality
} }
if (this.voiceConnection.videoCodec == 'H264') { if (this.voiceConnection.videoCodec == 'H264') {
args.push( args.push(...FFMPEG_H264_ARGUMENTS(options));
'-c:v',
'libx264',
'-f',
'h264',
'-tune',
'zerolatency',
// '-pix_fmt',
// 'yuv420p',
'-preset',
options?.presetH26x || 'faster',
'-profile:v',
'baseline',
// '-g',
// `${options?.fps}`,
// '-x264-params',
// `keyint=${options?.fps}:min-keyint=${options?.fps}`,
'-bf',
'0',
'-bsf:v',
'h264_metadata=aud=insert',
);
} }
args.push('-force_key_frames', '00:02'); args.push('-force_key_frames', '00:02');
@@ -240,12 +255,16 @@ class MediaPlayer extends EventEmitter {
input.pipe(ffmpeg); input.pipe(ffmpeg);
} }
this.emit('debug', `[ffmpeg] Spawn process with args:\n${args.join(' ')}`); this.emit('debug', `[ffmpeg-video_process] Spawn process with args:\n${args.join(' ')}`);
ffmpeg.process.stderr.on('data', data => { ffmpeg.process.stderr.on('data', data => {
this.emit('debug', `[ffmpeg]: ${data.toString()}`); this.emit('debug', `[ffmpeg-video_process]: ${data.toString()}`);
}); });
if (data?.audio && options?.includeAudio) {
this.playUnknown(input, options?.audioOptions || {});
}
switch (this.voiceConnection.videoCodec) { switch (this.voiceConnection.videoCodec) {
case 'VP8': { case 'VP8': {
return this.playIvfVideo(ffmpeg, options, streams); return this.playIvfVideo(ffmpeg, options, streams);
@@ -254,7 +273,7 @@ class MediaPlayer extends EventEmitter {
return this.playAnnexBVideo(ffmpeg, options, streams, 'H264'); return this.playAnnexBVideo(ffmpeg, options, streams, 'H264');
} }
default: { default: {
throw new Error('Invalid codec'); throw new Error('Invalid codec (Supported: VP8, H264)');
} }
} }
} }

View File

@@ -78,7 +78,7 @@ class PlayInterface {
* Options that can be passed to stream-playing methods: * Options that can be passed to stream-playing methods:
* @typedef {Object} VideoOptions * @typedef {Object} VideoOptions
* @property {number} [seek=0] The time to seek to * @property {number} [seek=0] The time to seek to
* @property {number} [fps=30] Video fps * @property {number} [fps] Video fps
* @property {number} [highWaterMark=12] The maximum number of opus packets to make and store before they are * @property {number} [highWaterMark=12] The maximum number of opus packets to make and store before they are
* actually needed. See https://nodejs.org/en/docs/guides/backpressuring-in-streams/. Setting this value to * actually needed. See https://nodejs.org/en/docs/guides/backpressuring-in-streams/. Setting this value to
* 1 means that changes in volume will be more instant. * 1 means that changes in volume will be more instant.