feat: 1080p60 NVENC selfbot broadcast (8 Mbps default)
Bump the default broadcast to 1080p 60fps at 8 Mbps and route both encode stages through the GPU (RTX 5050, h264_nvenc) so 60fps stays smooth without loading the 4-core host. - selfbot.ts: capture ffmpeg uses h264_nvenc when streamHw is on (falls back to software x264 otherwise), and prepareStream now passes Encoders.nvenc() so the library's transcode runs on the GPU too. Guard loadLib for Encoders. - config.ts: VNC_FRAMERATE default 30 -> 60, VNC_BITRATE_KBPS 4000 -> 8000. - .env.example: document the new 1080p60/8 Mbps defaults and STREAM_HW. Verified locally: h264_nvenc x11grab holds a steady 60fps with headroom, Encoders.nvenc() returns valid h264_nvenc settings, and tsc --noEmit passes. Live Discord voice-channel verification pending a host reboot.
This commit is contained in:
@@ -58,13 +58,18 @@ STREAM_BACKEND=selfbot
|
|||||||
# The VNC desktop runs on X display :1 (see docs/vnc-xfce-setup.md)
|
# The VNC desktop runs on X display :1 (see docs/vnc-xfce-setup.md)
|
||||||
VNC_DISPLAY=:1
|
VNC_DISPLAY=:1
|
||||||
VNC_RESOLUTION=1920x1080
|
VNC_RESOLUTION=1920x1080
|
||||||
VNC_FRAMERATE=30
|
# 1080p60 broadcast. 8 Mbps suits 60fps (YouTube-style 1080p60 sits ~8-12 Mbps);
|
||||||
VNC_BITRATE_KBPS=4000
|
# drop to 30/4000 for a lighter stream. Max bitrate is 1.5x this value.
|
||||||
|
VNC_FRAMERATE=60
|
||||||
|
VNC_BITRATE_KBPS=8000
|
||||||
|
|
||||||
# --- selfbot backend ---
|
# --- selfbot backend ---
|
||||||
# A THROWAWAY/burner Discord user account token. NEVER your main account.
|
# A THROWAWAY/burner Discord user account token. NEVER your main account.
|
||||||
# Using a selfbot violates Discord ToS and can get the account banned.
|
# Using a selfbot violates Discord ToS and can get the account banned.
|
||||||
DISCORD_SELFBOT_TOKEN=
|
DISCORD_SELFBOT_TOKEN=
|
||||||
|
# Hardware (NVENC) encode for the stream. 1 = use the GPU (recommended for
|
||||||
|
# 1080p60), 0 = software x264. Requires an NVIDIA GPU + ffmpeg built with nvenc.
|
||||||
|
STREAM_HW=1
|
||||||
|
|
||||||
# --- novnc backend ---
|
# --- novnc backend ---
|
||||||
# e.g. http://192.168.10.9:6080/vnc.html (websockify --web=/usr/share/novnc 6080 localhost:5901)
|
# e.g. http://192.168.10.9:6080/vnc.html (websockify --web=/usr/share/novnc 6080 localhost:5901)
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export const config = {
|
|||||||
// x11grab source for the VNC display (TigerVNC runs the desktop on :1)
|
// x11grab source for the VNC display (TigerVNC runs the desktop on :1)
|
||||||
vncDisplay: opt("VNC_DISPLAY", ":1"),
|
vncDisplay: opt("VNC_DISPLAY", ":1"),
|
||||||
vncResolution: opt("VNC_RESOLUTION", "1920x1080"),
|
vncResolution: opt("VNC_RESOLUTION", "1920x1080"),
|
||||||
vncFramerate: parseInt(opt("VNC_FRAMERATE", "30"), 10),
|
vncFramerate: parseInt(opt("VNC_FRAMERATE", "60"), 10),
|
||||||
vncBitrateKbps: parseInt(opt("VNC_BITRATE_KBPS", "4000"), 10),
|
vncBitrateKbps: parseInt(opt("VNC_BITRATE_KBPS", "8000"), 10),
|
||||||
|
|
||||||
// selfbot backend (ToS-risk; use a throwaway account token, never your main)
|
// selfbot backend (ToS-risk; use a throwaway account token, never your main)
|
||||||
selfbotToken: opt("DISCORD_SELFBOT_TOKEN"),
|
selfbotToken: opt("DISCORD_SELFBOT_TOKEN"),
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
`원본 오류: ${(e as Error).message}`,
|
`원본 오류: ${(e as Error).message}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!vs.Streamer || !vs.prepareStream || !vs.playStream) {
|
if (!vs.Streamer || !vs.prepareStream || !vs.playStream || !vs.Encoders) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"@dank074/discord-video-stream v6 API(Streamer/prepareStream/playStream)를 찾지 못했습니다. " +
|
"@dank074/discord-video-stream v6 API(Streamer/prepareStream/playStream/Encoders)를 찾지 못했습니다. " +
|
||||||
"package.json 버전을 ^6.0.0으로 맞추세요.",
|
"package.json 버전을 ^6.0.0으로 맞추세요.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
return "셀프봇 송출은 음성 채널 안에서 호출해야 합니다.";
|
return "셀프봇 송출은 음성 채널 안에서 호출해야 합니다.";
|
||||||
}
|
}
|
||||||
const { selfbot, vs } = await this.loadLib();
|
const { selfbot, vs } = await this.loadLib();
|
||||||
const { Streamer, prepareStream, playStream } = vs;
|
const { Streamer, prepareStream, playStream, Encoders } = vs;
|
||||||
|
|
||||||
this.streamer = new Streamer(new selfbot.Client());
|
this.streamer = new Streamer(new selfbot.Client());
|
||||||
await this.streamer.client.login(this.config.selfbotToken);
|
await this.streamer.client.login(this.config.selfbotToken);
|
||||||
@@ -77,13 +77,22 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
// x11grab), then pipe that stream into the library. Relying on the lib's
|
// x11grab), then pipe that stream into the library. Relying on the lib's
|
||||||
// bundled libav for the x11grab input device is not portable; piping the
|
// bundled libav for the x11grab input device is not portable; piping the
|
||||||
// system ffmpeg is. (Verified live against a real voice channel.)
|
// system ffmpeg is. (Verified live against a real voice channel.)
|
||||||
|
//
|
||||||
|
// With streamHw on (default) the capture is encoded by the GPU
|
||||||
|
// (h264_nvenc, RTX 5050) so 1080p60 stays smooth without loading the CPU;
|
||||||
|
// the library then transcodes with NVENC too (see encoder below). Without
|
||||||
|
// hardware support we fall back to software x264.
|
||||||
|
const hw = this.config.streamHw;
|
||||||
|
const captureCodecArgs = hw
|
||||||
|
? ["-c:v", "h264_nvenc", "-preset", "p4", "-tune", "ll"]
|
||||||
|
: ["-c:v", "libx264", "-preset", "ultrafast", "-tune", "zerolatency"];
|
||||||
const capture = spawn("ffmpeg", [
|
const capture = spawn("ffmpeg", [
|
||||||
"-loglevel", "error",
|
"-loglevel", "error",
|
||||||
"-f", "x11grab",
|
"-f", "x11grab",
|
||||||
"-framerate", String(this.config.vncFramerate),
|
"-framerate", String(this.config.vncFramerate),
|
||||||
"-video_size", this.config.vncResolution,
|
"-video_size", this.config.vncResolution,
|
||||||
"-i", this.config.vncDisplay,
|
"-i", this.config.vncDisplay,
|
||||||
"-c:v", "libx264", "-preset", "ultrafast", "-tune", "zerolatency",
|
...captureCodecArgs,
|
||||||
"-pix_fmt", "yuv420p", "-g", String(this.config.vncFramerate),
|
"-pix_fmt", "yuv420p", "-g", String(this.config.vncFramerate),
|
||||||
"-f", "mpegts", "pipe:1",
|
"-f", "mpegts", "pipe:1",
|
||||||
]);
|
]);
|
||||||
@@ -101,6 +110,7 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
videoCodec: "H264",
|
videoCodec: "H264",
|
||||||
bitrateVideo: this.config.vncBitrateKbps,
|
bitrateVideo: this.config.vncBitrateKbps,
|
||||||
bitrateVideoMax: Math.round(this.config.vncBitrateKbps * 1.5),
|
bitrateVideoMax: Math.round(this.config.vncBitrateKbps * 1.5),
|
||||||
|
encoder: hw ? Encoders.nvenc() : Encoders.software(),
|
||||||
},
|
},
|
||||||
this.controller.signal,
|
this.controller.signal,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user