Skip to content
Merged
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
52 changes: 28 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Spacecap

A hardware accelerated replay capture tool focused on performance. Currently
only supports Linux.
only supports Linux. Still in early development (see roadmap below).

![screenshot2](./screenshots/screenshot_3.png)

Expand All @@ -13,18 +13,33 @@ only supports Linux.

## Features

- Desktop/window capture
- Save last n seconds of video
- Global keybinds
- Desktop/window/region capture.
- Save last n seconds of video (video buffered in memory).
- Global keybinds.

## Why you might want to use this?
## Roadmap

You play games on Linux and are looking for a lightweight and performant
alternative to OBS for capturing video replays.
- Screenshots.
- Toggle recording (currently only replays are supported).
- Video player/editor.
- Simple video editor (trim start/end).
- File browser to select videos to edit.
- Additional video output formats (mp4, mov, mkv, gif, etc.).
- Windows capture.

## Why would you want to use this?

You're looking for a lightweight and performant way to capture video replays.
The goal of Spacecap is to be as fast and resource efficient as possible. To do
this, frame buffers stay on the GPU (via dma-buff) for the entire duration of
the encoding pipeline.

## Requirements

- GPU that supports Vulkan Video
- A GPU that supports Vulkan Video.

**NOTE:** Only tested on an Nvidia GPU so far. AMD will be supported, I just
have no way of testing at this time.

### Linux

Expand All @@ -34,8 +49,9 @@ alternative to OBS for capturing video replays.

#### Global Keybinds

If your version of Linux supports [xdg-desktop-portal global shortcuts](https://wiki.archlinux.org/title/XDG_Desktop_Portal#List_of_backends_and_interfaces) then you can configure it that way.
Otherwise, the Spacecap CLI can be used to send commands to the IPC server.
If your version of Linux supports [xdg-desktop-portal global shortcuts](https://wiki.archlinux.org/title/XDG_Desktop_Portal#List_of_backends_and_interfaces)
then they can be configured that way. Alternatively, Spacecap runs an IPC
server, which can be communicated with via Spacecap CLI.

For example, here is what a config in [niri](https://github.com/YaLTeR/niri) would look like:

Expand All @@ -51,7 +67,8 @@ Use `spacecap -h` to see available commands.

Windows is not yet supported. This application was architected in such a way
that it can be cross platform. For Windows support, the audio/video capture
interfaces need to be implemented.
interfaces need to be implemented. It's on the roadmap, but is not currently
a priority.

## Development

Expand All @@ -69,16 +86,3 @@ nix develop -c zig build run -Dnix
# Test
nix develop -c zig build test -Dnix
```

## Roadmap

- ~~Set up pipeline to build and distribute binaries (appimage).~~
- ~~Audio recording.~~
- ~~Global keybinds~~
- Screenshots.
- ~~Show video preview on UI~~ - #9
- Video Player.
- Simple video editor (trim start/end).
- Convert video output (mp4, gif, etc.).
- ~~Linux capture.~~
- Windows capture.
7 changes: 2 additions & 5 deletions src/video/vulkan_video_encoder.zig
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
const vk = @import("vulkan");
const std = @import("std");
const Device = @import("../vulkan/vulkan.zig").Device;
const Instance = @import("../vulkan/vulkan.zig").Instance;
const Vulkan = @import("../vulkan/vulkan.zig").Vulkan;
const Queue = @import("../vulkan/vulkan.zig").Queue;
const VideoReplayBuffer = @import("./video_replay_buffer.zig").VideoReplayBuffer;
const vulkan_h264_parameters = @import("./vulkan_h264_parameters.zig");
const types = @import("../types.zig");

const Display = u32;
const REFERENCE_IMAGE_COUNT = 2;

pub const EncodeResult = struct {
Expand All @@ -22,6 +18,7 @@ const PushConstants = extern struct {

pub const VulkanVideoEncoder = struct {
const Self = @This();
const log = std.log.scoped(.vulkan_video_encoder);

allocator: std.mem.Allocator,
vulkan: *Vulkan,
Expand Down Expand Up @@ -172,7 +169,7 @@ pub const VulkanVideoEncoder = struct {

try self.allocate_intermediate_image();
errdefer self.destroy_intermediate_images();
std.debug.print("^^^^^ nvidia validation issue here ^^^^^\n", .{});
log.debug("^^^^^ nvidia validation issue here ^^^^^\n", .{});

try self.create_output_query_pool();
errdefer self.vulkan.device.destroyQueryPool(self.query_pool.?, null);
Expand Down
23 changes: 23 additions & 0 deletions zlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://raw.githubusercontent.com/DonIsaac/zlint/refs/heads/main/zlint.schema.json",
"ignore": ["vendor", "zig-out"],
"rules": {
"avoid-as": "warn",
"case-convention": "off",
"allocator-first-param": "off",
"useless-error-return": "off",
"unused-decls": "warn",
"homeless-try": "error",
"no-catch-return": "warn",
"empty-file": "warn",
"line-length": "off",
"no-print": "warn",
"returned-stack-reference": "off",
"duplicate-case": "off",
"no-unresolved": "error",
"unsafe-undefined": "allow",
"suppressed-errors": "warn",
"no-return-try": "off",
"must-return-ref": "warn"
}
}
Loading