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
48 changes: 28 additions & 20 deletions src/audio/audio_encoder.zig
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ pub const EncodedAudioPacketNode = struct {
pub const AudioEncoder = struct {
const Self = @This();

allocator: Allocator,
audio_codec_ctx: [*c]ffmpeg.AVCodecContext,
channels: u32,
// A rolling buffer of raw audio waiting to be encoded. We only encode
Expand Down Expand Up @@ -87,15 +86,14 @@ pub const AudioEncoder = struct {
try checkErr(ret);

return .{
.allocator = allocator,
.audio_codec_ctx = audio_codec_ctx,
.channels = channels,
.pending_samples = try .initCapacity(allocator, 0),
};
}

pub fn deinit(self: *Self) void {
self.pending_samples.deinit(self.allocator);
pub fn deinit(self: *Self, allocator: Allocator) void {
self.pending_samples.deinit(allocator);
ffmpeg.avcodec_free_context(&self.audio_codec_ctx);
}

Expand All @@ -104,6 +102,7 @@ pub const AudioEncoder = struct {
/// the encoder.
pub fn encode_chunk(
self: *Self,
allocator: Allocator,
start_sample: i64,
pcm: []const f32,
) !?std.DoublyLinkedList {
Expand All @@ -127,14 +126,14 @@ pub const AudioEncoder = struct {
}
}

try self.pending_samples.appendSlice(self.allocator, pcm);
try self.pending_samples.appendSlice(allocator, pcm);

return try self.encode_buffered_frames(false);
return try self.encode_buffered_frames(allocator, false);
}

/// Encode buffered samples if there are enough to fill the codec frame size.
/// allow_partial - Set to true to ignore this check and encode anyway.
fn encode_buffered_frames(self: *Self, allow_partial: bool) !std.DoublyLinkedList {
fn encode_buffered_frames(self: *Self, allocator: Allocator, allow_partial: bool) !std.DoublyLinkedList {
var audio_packets: std.DoublyLinkedList = .{};
errdefer deinit_packet_list(&audio_packets);

Expand Down Expand Up @@ -162,7 +161,14 @@ pub const AudioEncoder = struct {
// `sendFrame` reads from the front of `pending_samples`, so after it
// returns we compact the remaining PCM to keep the rolling buffer
// contiguous for the next capture chunk.
try self.send_frame(&audio_packets, frame, self.pending_start_sample.?, codec_samples_per_packet, submitted_samples);
try self.send_frame(
allocator,
&audio_packets,
frame,
self.pending_start_sample.?,
codec_samples_per_packet,
submitted_samples,
);

const consumed_samples = submitted_samples * self.channels;
const remaining_samples = self.pending_samples.items.len - consumed_samples;
Expand All @@ -171,7 +177,7 @@ pub const AudioEncoder = struct {
self.pending_samples.items[0..remaining_samples],
self.pending_samples.items[consumed_samples..],
);
try self.pending_samples.resize(self.allocator, remaining_samples);
try self.pending_samples.resize(allocator, remaining_samples);

self.pending_start_sample.? += @intCast(submitted_samples);
if (remaining_samples == 0) {
Expand All @@ -183,21 +189,22 @@ pub const AudioEncoder = struct {
return audio_packets;
}

pub fn flush(self: *Self) !std.DoublyLinkedList {
pub fn flush(self: *Self, allocator: Allocator) !std.DoublyLinkedList {
assert(!self.is_flushed);

var audio_packets = try self.encode_buffered_frames(true);
var audio_packets = try self.encode_buffered_frames(allocator, true);
errdefer deinit_packet_list(&audio_packets);

self.is_flushed = true;
const ret = ffmpeg.avcodec_send_frame(self.audio_codec_ctx, null);
try checkErr(ret);
try self.collect_ready_packets(&audio_packets);
try self.collect_ready_packets(allocator, &audio_packets);
return audio_packets;
}

fn send_frame(
self: *Self,
allocator: Allocator,
audio_packets: *std.DoublyLinkedList,
frame: [*c]ffmpeg.AVFrame,
start_sample: i64,
Expand Down Expand Up @@ -240,11 +247,12 @@ pub const AudioEncoder = struct {
try checkErr(ret);
// A single submitted frame can produce zero, one, or multiple packets
// depending on encoder delay, so always drain after each send.
try self.collect_ready_packets(audio_packets);
try self.collect_ready_packets(allocator, audio_packets);
}

fn collect_ready_packets(
self: *Self,
allocator: Allocator,
audio_packets: *std.DoublyLinkedList,
) !void {
var audio_pkt = ffmpeg.av_packet_alloc() orelse return error.FFmpegError;
Expand All @@ -259,7 +267,7 @@ pub const AudioEncoder = struct {
var owned_pkt = ffmpeg.av_packet_alloc() orelse return error.FFmpegError;
errdefer ffmpeg.av_packet_free(&owned_pkt);
ffmpeg.av_packet_move_ref(owned_pkt, audio_pkt);
const node = try EncodedAudioPacketNode.init(self.allocator, owned_pkt);
const node = try EncodedAudioPacketNode.init(allocator, owned_pkt);
audio_packets.append(&node.node);
}
}
Expand All @@ -276,13 +284,13 @@ test "encodeChunk rejects non-contiguous sample input" {
const allocator = std.testing.allocator;

var encoder = try AudioEncoder.init(allocator, 48_000, 2);
defer encoder.deinit();
defer encoder.deinit(allocator);

const pcm = [_]f32{ 0.0, 0.0, 0.0, 0.0 };
var first_result = (try encoder.encode_chunk(0, &pcm)).?;
var first_result = (try encoder.encode_chunk(allocator, 0, &pcm)).?;
defer deinit_packet_list(&first_result);
try std.testing.expect(first_result.first == null);
try std.testing.expectError(error.NonContiguousAudioPts, encoder.encode_chunk(3, &pcm));
try std.testing.expectError(error.NonContiguousAudioPts, encoder.encode_chunk(allocator, 3, &pcm));
}

test "encodeChunk plus flush produces encoded audio packets" {
Expand All @@ -293,7 +301,7 @@ test "encodeChunk plus flush produces encoded audio packets" {
const sample_positions: usize = 2_048;

var encoder = try AudioEncoder.init(allocator, sample_rate, channels);
defer encoder.deinit();
defer encoder.deinit(allocator);

const pcm = try allocator.alloc(f32, sample_positions * channels);
defer allocator.free(pcm);
Expand All @@ -308,12 +316,12 @@ test "encodeChunk plus flush produces encoded audio packets" {
var all_packets: std.DoublyLinkedList = .{};
defer deinit_packet_list(&all_packets);

var encoded_packets = (try encoder.encode_chunk(start_sample, pcm)).?;
var encoded_packets = (try encoder.encode_chunk(allocator, start_sample, pcm)).?;
while (encoded_packets.popFirst()) |node| {
all_packets.append(node);
}

var flushed_packets = try encoder.flush();
var flushed_packets = try encoder.flush(allocator);
while (flushed_packets.popFirst()) |node| {
all_packets.append(node);
}
Expand Down
8 changes: 4 additions & 4 deletions src/audio/audio_timeline.zig
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub const AudioTimeline = struct {
channels: u32,
) !Self {
var encoder = try AudioEncoder.init(allocator, sample_rate, channels);
errdefer encoder.deinit();
errdefer encoder.deinit(allocator);

return .{
.allocator = allocator,
Expand All @@ -109,7 +109,7 @@ pub const AudioTimeline = struct {
self.device_map.deinit();

deinitPacketList(&self.ready_packets);
self.encoder.deinit();
self.encoder.deinit(self.allocator);
}

pub fn add_data(self: *Self, data: *AudioCaptureData) !void {
Expand Down Expand Up @@ -164,7 +164,7 @@ pub const AudioTimeline = struct {

try self.process_ready_timeline(true);

var flush_result = try self.encoder.flush();
var flush_result = try self.encoder.flush(self.allocator);
errdefer deinitPacketList(&flush_result);
self.append_ready_packets(&flush_result);
}
Expand Down Expand Up @@ -227,7 +227,7 @@ pub const AudioTimeline = struct {
);
defer mixed_pcm.deinit(self.allocator);

var packets = try self.encoder.encode_chunk(self.encoded_until_sample, mixed_pcm.items);
var packets = try self.encoder.encode_chunk(self.allocator, self.encoded_until_sample, mixed_pcm.items);
if (packets) |*owned_packets| {
errdefer deinitPacketList(owned_packets);
self.append_ready_packets(owned_packets);
Expand Down
2 changes: 1 addition & 1 deletion src/capture/video/linux/pipewire/pipewire_video.zig
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ pub const PipewireVideo = struct {
var params = try std.ArrayList(*pw.spa_pod).initCapacity(allocator, 0);
errdefer params.deinit(allocator);
for (formats) |format| {
var modifiers = try self.vulkan.query_format_modifiers(pipewire_util.spa_to_vk_format(format));
var modifiers = try self.vulkan.query_format_modifiers(self.allocator, pipewire_util.spa_to_vk_format(format));
defer modifiers.deinit(self.allocator);
if (modifiers.items.len == 0) {
continue;
Expand Down
16 changes: 8 additions & 8 deletions src/file_picker/file_picker.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const Allocator = std.mem.Allocator;

pub const FilePickerError = error{
PickerCancelled,
Expand All @@ -12,18 +13,17 @@ pub const FilePicker = struct {
vtable: *const VTable,

const VTable = struct {
open_directory_picker: *const fn (*anyopaque, ?[]const u8) anyerror![]u8,
deinit: *const fn (*anyopaque) void,
open_directory_picker: *const fn (*anyopaque, Allocator, ?[]const u8) anyerror![]u8,
};

/// Open a directory picker and return the selected directory path.
/// The returned path is owned by the caller.
/// initial_directory - Open in this directory if provided.
pub fn open_directory_picker(self: *Self, initial_directory: ?[]const u8) (FilePickerError || anyerror)![]u8 {
return self.vtable.open_directory_picker(self.ptr, initial_directory);
}

pub fn deinit(self: *Self) void {
return self.vtable.deinit(self.ptr);
pub fn open_directory_picker(
self: *Self,
allocator: Allocator,
initial_directory: ?[]const u8,
) (FilePickerError || anyerror)![]u8 {
return self.vtable.open_directory_picker(self.ptr, allocator, initial_directory);
}
};
39 changes: 18 additions & 21 deletions src/file_picker/linux/xdg_desktop_portal_file_picker.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const TokenManager = @import("../../common/linux/token_manager.zig");
const FilePicker = @import("../file_picker.zig").FilePicker;
const FilePickerError = @import("../file_picker.zig").FilePickerError;
Expand Down Expand Up @@ -35,10 +36,9 @@ const OpenDirectoryPickerContext = struct {
pub const XdgDesktopPortalFilePicker = struct {
const Self = @This();

allocator: std.mem.Allocator,
dbus: *gio.DBusConnection,

pub fn init(allocator: std.mem.Allocator) !*Self {
pub fn init() !Self {
var err: ?*glib.Error = null;
defer if (err) |e| e.free();

Expand All @@ -51,13 +51,9 @@ pub const XdgDesktopPortalFilePicker = struct {
return error.Dbus;
};

const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
return .{
.dbus = dbus,
};
return self;
}

fn open_directory_picker_response(
Expand Down Expand Up @@ -92,7 +88,7 @@ pub const XdgDesktopPortalFilePicker = struct {
);
}

fn selected_directory_from_result(self: *Self, result: *glib.Variant) ![]u8 {
fn selected_directory_from_result(allocator: Allocator, result: *glib.Variant) ![]u8 {
var result_dict: glib.VariantDict = undefined;
glib.VariantDict.init(&result_dict, result);
defer result_dict.clear();
Expand All @@ -114,24 +110,28 @@ pub const XdgDesktopPortalFilePicker = struct {
const file_path = glib.filenameFromUri(first_uri, null, null) orelse return error.FileUriToPathFailed;
defer glib.free(file_path);

return self.allocator.dupe(u8, std.mem.span(file_path));
return allocator.dupe(u8, std.mem.span(file_path));
}

pub fn open_directory_picker(context: *anyopaque, initial_directory: ?[]const u8) ![]u8 {
pub fn open_directory_picker(
context: *anyopaque,
allocator: Allocator,
initial_directory: ?[]const u8,
) ![]u8 {
const self: *Self = @ptrCast(@alignCast(context));

const request_token = try TokenManager.generate_token(self.allocator);
defer self.allocator.free(request_token);
const request_token = try TokenManager.generate_token(allocator);
defer allocator.free(request_token);

const initial_directory_z = if (initial_directory) |directory|
try self.allocator.dupeZ(u8, directory)
try allocator.dupeZ(u8, directory)
else
null;
defer if (initial_directory_z) |directory| self.allocator.free(directory);
defer if (initial_directory_z) |directory| allocator.free(directory);

const unique_name = std.mem.span(self.dbus.getUniqueName().?);
const request_path = try TokenManager.get_request_path(self.allocator, unique_name[1..], request_token);
defer self.allocator.free(request_path);
const request_path = try TokenManager.get_request_path(allocator, unique_name[1..], request_token);
defer allocator.free(request_path);

const loop = glib.MainLoop.new(null, 0);
defer loop.unref();
Expand Down Expand Up @@ -219,21 +219,18 @@ pub const XdgDesktopPortalFilePicker = struct {
const result = ctx.response_data orelse return error.OpenDirectoryPickerFailed;
defer result.unref();

return self.selected_directory_from_result(result);
return selected_directory_from_result(allocator, result);
}

pub fn deinit(context: *anyopaque) void {
const self: *Self = @ptrCast(@alignCast(context));
pub fn deinit(self: *Self) void {
self.dbus.unref();
self.allocator.destroy(self);
}

pub fn file_picker(self: *Self) FilePicker {
return .{
.ptr = self,
.vtable = &.{
.open_directory_picker = open_directory_picker,
.deinit = deinit,
},
};
}
Expand Down
22 changes: 6 additions & 16 deletions src/file_picker/windows/windows_file_picker.zig
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const FilePicker = @import("../file_picker.zig").FilePicker;

pub const WindowsFilePicker = struct {
const Self = @This();

allocator: std.mem.Allocator,

pub fn init(allocator: std.mem.Allocator) !*Self {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);

self.* = .{
.allocator = allocator,
};
return self;
pub fn init() !Self {
return .{};
}

pub fn open_directory_picker(context: *anyopaque, initial_directory: ?[]const u8) ![]u8 {
// TODO: Take an allocator for the returned owned memory.
pub fn open_directory_picker(context: *anyopaque, _: Allocator, initial_directory: ?[]const u8) ![]u8 {
const self: *Self = @ptrCast(@alignCast(context));
_ = self;
_ = initial_directory;
return error.NotImplemented;
}

pub fn deinit(context: *anyopaque) void {
const self: *Self = @ptrCast(@alignCast(context));
self.allocator.destroy(self);
}
pub fn deinit(_: *Self) void {}

pub fn file_picker(self: *Self) FilePicker {
return .{
.ptr = self,
.vtable = &.{
.open_directory_picker = open_directory_picker,
.deinit = deinit,
},
};
}
Expand Down
Loading
Loading