Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions screen_recorder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Replay controls are available only when `replay_enabled` is true.
| `replay_duration` | `int` | `30` | Replay buffer duration in seconds. |
| `replay_storage` | `select` | `ram` | Stores replay data in RAM or on disk. |
| `restore_portal` | `bool` | `false` | Asks GPU Screen Recorder to restore the portal session. |
| `encoder` | `select` | `gpu` | `gpu` uses hardware encoding with a CPU fallback if it fails at runtime; `cpu` skips the hardware probe entirely, for GPUs with no video encoder at all (e.g. Asahi/Apple Silicon, some VMs). |

## IPC

Expand Down
14 changes: 13 additions & 1 deletion screen_recorder/plugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

id = "noctalia/screen_recorder"
name = "Screen Recorder"
version = "1.2.2"
version = "1.3.0"
plugin_api = 3
author = "noctalia"
license = "MIT"
Expand Down Expand Up @@ -185,6 +185,18 @@ label_key = "settings.restore_portal.label"
default = false
advanced = true

[[setting]]
key = "encoder"
type = "select"
label_key = "settings.encoder.label"
description_key = "settings.encoder.description"
default = "gpu"
advanced = true
options = [
{ value = "gpu", label_key = "settings.encoder.options.gpu" },
{ value = "cpu", label_key = "settings.encoder.options.cpu" },
]

# Headless background service: owns the recording / replay logic, runs for the
# whole session, and bridges the "command" / "status" state channels.
[[service]]
Expand Down
17 changes: 15 additions & 2 deletions screen_recorder/recorder_service.luau
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,17 @@ local function buildResolutionFlag()
return if res ~= "original" then `-s {res}` else ""
end

-- "-fallback-cpu-encoding yes" is always included so a hardware encoder that
-- fails at runtime (e.g. unsupported codec, driver bug) degrades to software
-- encoding instead of aborting the recording. "-encoder cpu" additionally
-- skips the hardware probe entirely, which is required on GPUs with no VAAPI/
-- NVENC encoder at all (Asahi/Apple Silicon, some VMs) — probing there always
-- fails and just delays startup.
local function buildEncoderFlags()
local forceCpu = if cfg("encoder") == "cpu" then " -encoder cpu" else ""
return `-fallback-cpu-encoding yes{forceCpu}`
end

-- Capture modes a caller may request. An IPC override outside this set is
-- discarded so an arbitrary payload can never reach the gpu-screen-recorder
-- command line.
Expand Down Expand Up @@ -270,8 +281,9 @@ local function buildRecordCommand(focusedOutputName, sourceOverride)
local restore = if cfg("restore_portal") then "-restore-portal-session yes" else ""
local audioFlags = buildAudioFlags()
local resFlag = buildResolutionFlag()
local encoderFlags = buildEncoderFlags()

local flags = `-w {source} -f {fps} -k {codec} {audioFlags} -bm qp -ffmpeg-video-opts qp={qp} -cursor {cursor} -cr {cr} {resFlag} {restore} -v no -o "{outputPath}"`
local flags = `-w {source} -f {fps} -k {codec} {audioFlags} -bm qp -ffmpeg-video-opts qp={qp} -cursor {cursor} -cr {cr} {resFlag} {restore} {encoderFlags} -v no -o "{outputPath}"`

log(`starting recording: mode={selectedVideoSource(sourceOverride)} target={source} output={outputPath} flags=[{flags}]`)

Expand All @@ -297,8 +309,9 @@ local function buildReplayCommand(focusedOutputName, sourceOverride)
local restore = if cfg("restore_portal") then "-restore-portal-session yes" else ""
local audioFlags = buildAudioFlags()
local resFlag = buildResolutionFlag()
local encoderFlags = buildEncoderFlags()

local flags = `-w {source} -c mp4 -f {fps} -k {codec} {audioFlags} -bm qp -ffmpeg-video-opts qp={qp} -cursor {cursor} -cr {cr} {resFlag} -r {duration} -replay-storage {storage} {restore} -v no -o "{dir}"`
local flags = `-w {source} -c mp4 -f {fps} -k {codec} {audioFlags} -bm qp -ffmpeg-video-opts qp={qp} -cursor {cursor} -cr {cr} {resFlag} -r {duration} -replay-storage {storage} {restore} {encoderFlags} -v no -o "{dir}"`

log(`starting replay buffer: mode={selectedVideoSource(sourceOverride)} target={source} dir={dir} flags=[{flags}]`)

Expand Down
8 changes: 8 additions & 0 deletions screen_recorder/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@
"description": "Defaults to ~/Videos/Recordings when empty",
"label": "Output Directory"
},
"encoder": {
"description": "CPU encoding always works but uses more power; GPU encoding requires a working hardware video encoder (VAAPI/NVENC) and isn't available on some systems (e.g. Asahi/Apple Silicon GPUs, some VMs)",
"label": "Encoder",
"options": {
"cpu": "CPU (software)",
"gpu": "GPU (hardware)"
}
},
"filename_pattern": {
"description": "Date-format pattern without extension; use %s for Unix timestamp",
"label": "Filename Pattern"
Expand Down