diff --git a/build.zig b/build.zig index 4204311..e5ec658 100644 --- a/build.zig +++ b/build.zig @@ -26,6 +26,17 @@ pub fn build(b: *std.Build) void { .install_subdir = "pipewire-0.3", }); + // Compile our dl stub + const dlfcn = b.addLibrary(.{ + .name = "dlfcn", + .linkage = .static, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/dlfcn.zig"), + .target = target, + .optimize = optimize, + }), + }); + // Build and install the configuration { const generate_conf = b.addExecutable(.{ @@ -107,76 +118,68 @@ pub fn build(b: *std.Build) void { }); // Build libpipewire - { - // Build the library - const libpipewire = b.addLibrary(.{ - .name = "pipewire-0.3", - // Pipewire needs to be build as a dynamic library for its symbols to be available to the - // dynamic libraries it dlopens. Alternatively, you can link it statically, but you'll need - // to set rdynamic on the executable to make these symbols available. - .linkage = .static, - .root_module = b.createModule(.{ - .target = target, - .optimize = optimize, - }), - }); - libpipewire.addCSourceFiles(.{ - .root = upstream.path("src/pipewire"), - .files = &.{ - "buffers.c", - "conf.c", - "context.c", - "control.c", - "core.c", - "data-loop.c", - "filter.c", - "global.c", - "impl-client.c", - "impl-core.c", - "impl-device.c", - "impl-factory.c", - "impl-link.c", - "impl-metadata.c", - "impl-module.c", - "impl-node.c", - "impl-port.c", - "introspect.c", - "log.c", - "loop.c", - "main-loop.c", - "mem.c", - "pipewire.c", - "properties.c", - "protocol.c", - "proxy.c", - "resource.c", - "settings.c", - "stream.c", - "thread-loop.c", - "thread.c", - "timer-queue.c", - "utils.c", - "work-queue.c", - }, - .flags = flags, - }); - libpipewire.linkLibC(); - - // Add include paths - libpipewire.addIncludePath(b.dependency("valgrind_h", .{}).path("")); - libpipewire.addIncludePath(upstream.path("spa/include")); - libpipewire.addIncludePath(upstream.path("src")); - libpipewire.addConfigHeader(version_h); - libpipewire.addConfigHeader(config_h); - - // Install public headers - libpipewire.installHeadersDirectory(upstream.path("src/pipewire"), "pipewire", .{}); - libpipewire.installHeadersDirectory(upstream.path("spa/include/spa"), "spa", .{}); - libpipewire.installConfigHeader(version_h); - - // Install the library - b.installArtifact(libpipewire); - } + const libpipewire = b.addLibrary(.{ + .name = "pipewire-0.3", + .linkage = .static, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + }), + }); + libpipewire.linkLibrary(dlfcn); + libpipewire.addCSourceFiles(.{ + .root = upstream.path("src/pipewire"), + .files = &.{ + "buffers.c", + "conf.c", + "context.c", + "control.c", + "core.c", + "data-loop.c", + "filter.c", + "global.c", + "impl-client.c", + "impl-core.c", + "impl-device.c", + "impl-factory.c", + "impl-link.c", + "impl-metadata.c", + "impl-module.c", + "impl-node.c", + "impl-port.c", + "introspect.c", + "log.c", + "loop.c", + "main-loop.c", + "mem.c", + "pipewire.c", + "properties.c", + "protocol.c", + "proxy.c", + "resource.c", + "settings.c", + "stream.c", + "thread-loop.c", + "thread.c", + "timer-queue.c", + "utils.c", + "work-queue.c", + }, + .flags = flags, + }); + libpipewire.linkLibC(); + + libpipewire.addIncludePath(b.dependency("valgrind_h", .{}).path("")); + libpipewire.addIncludePath(upstream.path("spa/include")); + libpipewire.addIncludePath(upstream.path("src")); + libpipewire.addConfigHeader(version_h); + libpipewire.addConfigHeader(config_h); + + libpipewire.installHeadersDirectory(upstream.path("src/pipewire"), "pipewire", .{}); + libpipewire.installHeadersDirectory(upstream.path("spa/include/spa"), "spa", .{}); + libpipewire.installConfigHeader(version_h); + + b.installArtifact(libpipewire); // Build the plugins and modules { @@ -187,6 +190,8 @@ pub fn build(b: *std.Build) void { .version = version_h, .config = config_h, .install_dir = install_dir, + .libpipewire = libpipewire, + .dlfcn = dlfcn, }; // Build and install the plugins @@ -328,12 +333,6 @@ pub fn linkAndInstall( // Statically link libpipewire exe.linkLibrary(dep.artifact("pipewire-0.3")); - // Necessary for SPA to load symbols from the statically linked libpipewire - exe.rdynamic = true; - - // Note that the cache rpath will still be present: https://github.com/ziglang/zig/issues/24349 - exe.root_module.addRPathSpecial("$ORIGIN/pipewire-0.3"); - // Install Pipewire's dependencies b.installDirectory(.{ .install_dir = .bin, @@ -359,6 +358,8 @@ pub const PluginAndModuleCtx = struct { target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, install_dir: *std.Build.Step.WriteFile, + libpipewire: *std.Build.Step.Compile, + dlfcn: *std.Build.Step.Compile, }; pub const PipewireModule = struct { @@ -372,7 +373,7 @@ pub const PipewireModule = struct { ) *std.Build.Step.Compile { const lib = b.addLibrary(.{ .name = b.fmt("pipewire-module-{s}", .{self.name}), - .linkage = .dynamic, + .linkage = .static, .root_module = b.createModule(.{ .target = ctx.target, .optimize = ctx.optimize, @@ -389,10 +390,11 @@ pub const PipewireModule = struct { lib.addConfigHeader(ctx.config); lib.linkLibC(); - _ = ctx.install_dir.addCopyFile(lib.getEmittedBin(), b.pathJoin(&.{ - "modules", - b.fmt("libpipewire-module-{s}.so", .{self.name}), - })); + namespace(lib, "pipewire__module_init"); + namespace(lib, "mod_topic"); + + ctx.dlfcn.linkLibrary(lib); + ctx.dlfcn.addIncludePath(ctx.upstream.path("spa/include")); return lib; } @@ -409,7 +411,7 @@ pub const PipewirePlugin = struct { ) *std.Build.Step.Compile { const lib = b.addLibrary(.{ .name = b.fmt("spa-{s}", .{self.name}), - .linkage = .dynamic, + .linkage = .static, .root_module = b.createModule(.{ .target = ctx.target, .optimize = ctx.optimize, @@ -428,12 +430,43 @@ pub const PipewirePlugin = struct { lib.addConfigHeader(ctx.config); lib.linkLibC(); - _ = ctx.install_dir.addCopyFile(lib.getEmittedBin(), b.pathJoin(&.{ - "plugins", - self.name, - b.fmt("libspa-{s}.so", .{self.name}), - })); + namespace(lib, "spa_handle_factory_enum"); + namespace(lib, "spa_log_topic_enum"); + + ctx.dlfcn.linkLibrary(lib); + ctx.dlfcn.addIncludePath(ctx.upstream.path("spa/include")); return lib; } }; + +pub fn namespace(library: *std.Build.Step.Compile, symbol: []const u8) void { + const b = library.root_module.owner; + library.root_module.addCMacro( + symbol, + b.fmt("{f}", .{Namespaced.init(library.name, symbol)}), + ); +} + +pub const Namespaced = struct { + prefix: []const u8, + symbol: []const u8, + + pub fn init(prefix: []const u8, symbol: []const u8) Namespaced { + return .{ + .prefix = prefix, + .symbol = symbol, + }; + } + + pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + for (self.prefix) |c| { + switch (c) { + '-' => try writer.writeByte('_'), + else => try writer.writeByte(c), + } + } + try writer.writeAll("__"); + try writer.writeAll(self.symbol); + } +}; diff --git a/src/dlfcn.zig b/src/dlfcn.zig new file mode 100644 index 0000000..f4ea479 --- /dev/null +++ b/src/dlfcn.zig @@ -0,0 +1,324 @@ +const std = @import("std"); + +const log = std.log.scoped(.dl); +const assert = std.debug.assert; + +pub const c = @cImport({ + @cInclude("spa/support/plugin.h"); + @cInclude("spa/support/log.h"); + @cInclude("dlfcn.h"); +}); + +const plugins = struct { + const SpaHandleFactoryEnum = @TypeOf(c.spa_handle_factory_enum); + + pub extern const spa_support__spa_handle_factory_enum: SpaHandleFactoryEnum; + pub extern const spa_videoconvert__spa_handle_factory_enum: SpaHandleFactoryEnum; + + pub extern const spa_support__spa_log_topic_enum: c.spa_log_topic_enum; + pub extern const spa_videoconvert__spa_log_topic_enum: c.spa_log_topic_enum; +}; + +const modules = struct { + const PipewireModuleInit = fn (_: *anyopaque, _: *anyopaque) callconv(.c) void; + + pub extern const pipewire_module_protocol_native__pipewire__module_init: PipewireModuleInit; + pub extern const pipewire_module_client_node__pipewire__module_init: PipewireModuleInit; + pub extern const pipewire_module_client_device__pipewire__module_init: PipewireModuleInit; + pub extern const pipewire_module_adapter__pipewire__module_init: PipewireModuleInit; + pub extern const pipewire_module_metadata__pipewire__module_init: PipewireModuleInit; + pub extern const pipewire_module_session_manager__pipewire__module_init: PipewireModuleInit; +}; + +const fops = struct { + pub fn OPENAT64( + dirfd: c_int, + path: [*:0]const u8, + oflag: c_int, + mode: std.c.mode_t, + ) callconv(.c) c_int { + return @intCast(std.os.linux.openat(dirfd, path, @bitCast(oflag), mode)); + } + + pub fn dup(oldfd: c_int) callconv(.c) c_int { + return @intCast(std.os.linux.dup(oldfd)); + } + + pub fn close(fd: c_int) callconv(.c) c_int { + return @intCast(std.os.linux.close(fd)); + } + + pub fn ioctl(fd: c_int, request: c_ulong, arg: *anyopaque) callconv(.c) c_int { + return @intCast(std.os.linux.ioctl(fd, @intCast(request), @intFromPtr(arg))); + } + + pub fn mmap64( + addr: ?[*]u8, + length: usize, + prot: c_int, + flags: c_int, + fd: c_int, + offset: i64, + ) callconv(.c) *anyopaque { + return @ptrFromInt(std.os.linux.mmap( + addr, + length, + @intCast(prot), + @bitCast(flags), + fd, + offset, + )); + } + + pub fn munmap(addr: [*]const u8, length: usize) callconv(.c) c_int { + return @intCast(std.os.linux.munmap(addr, length)); + } +}; + +const libs: std.StaticStringMap(Lib) = .initComptime(.{ + .{ + Lib.main_program_name, + Lib{ + .name = Lib.main_program_name, + .symbols = .initComptime(.{}), + }, + }, + .{ + Lib.rtld_next_name, + Lib{ + .name = Lib.rtld_next_name, + .symbols = .initComptime(.{ + .{ + "OPENAT64", + Lib.sym(&fops.OPENAT64), + }, + .{ + "dup", + Lib.sym(&fops.dup), + }, + .{ + "close", + Lib.sym(&fops.close), + }, + .{ + "ioctl", + Lib.sym(&fops.ioctl), + }, + .{ + "mmap64", + Lib.sym(&fops.mmap64), + }, + .{ + "munmap", + Lib.sym(&fops.munmap), + }, + }), + }, + }, + .{ + "pipewire-0.3/plugins/support/libspa-support.so", + Lib{ + .name = "spa-support", + .symbols = .initComptime(.{ + .{ + "spa_handle_factory_enum", + Lib.sym(&plugins.spa_support__spa_handle_factory_enum), + }, + .{ + "spa_log_topic_enum", + Lib.sym(&plugins.spa_support__spa_log_topic_enum), + }, + }), + }, + }, + .{ + "pipewire-0.3/plugins/videoconvert/libspa-videoconvert.so", + Lib{ + .name = "libspa-videoconvert", + .symbols = .initComptime(.{ + .{ + "spa_handle_factory_enum", + Lib.sym(&plugins.spa_videoconvert__spa_handle_factory_enum), + }, + .{ + "spa_log_topic_enum", + Lib.sym(&plugins.spa_videoconvert__spa_log_topic_enum), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-protocol-native.so", + Lib{ + .name = "libpipewire-module-protocol-native", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_protocol_native__pipewire__module_init), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-client-node.so", + Lib{ + .name = "libpipewire-module-client-node", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_client_node__pipewire__module_init), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-client-device.so", + Lib{ + .name = "libpipewire-module-client-device", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_client_device__pipewire__module_init), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-adapter.so", + Lib{ + .name = "libpipewire-module-adapter", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_adapter__pipewire__module_init), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-metadata.so", + Lib{ + .name = "libpipewire-module-metadata", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_metadata__pipewire__module_init), + }, + }), + }, + }, + .{ + "pipewire-0.3/modules/libpipewire-module-session-manager.so", + Lib{ + .name = "libpipewire-module-session-manager", + .symbols = .initComptime(.{ + .{ + "pipewire__module_init", + Lib.sym(&modules.pipewire_module_session_manager__pipewire__module_init), + }, + }), + }, + }, +}); + +export fn dlopen(path: ?[*:0]const u8, mode: std.c.RTLD) callconv(.c) ?*anyopaque { + const span = if (path) |p| std.mem.span(p) else Lib.main_program_name; + const lib = if (libs.getIndex(span)) |index| &libs.kvs.values[index] else null; + log.info("dlopen(\"{f}\", {f}) -> {?f}", .{ std.zig.fmtString(span), FmtMode.init(mode), lib }); + return @ptrCast(@constCast(lib)); +} + +export fn dlclose(handle: ?*anyopaque) callconv(.c) c_int { + const lib: *const Lib = @ptrCast(@alignCast(handle.?)); + log.info("dlclose({f})", .{lib}); + return 0; +} + +export fn dlsym(noalias handle: ?*anyopaque, noalias name: [*:0]u8) ?*anyopaque { + const lib: *const Lib = @ptrCast(@alignCast(handle.?)); + const span = std.mem.span(name); + var msg: ?[:0]const u8 = null; + const symbol = b: { + if (handle == c.RTLD_NEXT) { + break :b lib.symbols.get(Lib.rtld_next_name).?; + } + const symbol = lib.symbols.get(span) orelse { + msg = "symbol not found"; + break :b null; + }; + break :b symbol; + }; + log.info("dlsym({f}, \"{f}\") -> 0x{x} ({s})", .{ + lib, + std.zig.fmtString(span), + @intFromPtr(symbol), + if (msg) |m| m else "success", + }); + if (msg) |m| err = m; + return symbol; +} + +var err: ?[*:0]const u8 = null; +export fn dlerror() ?[*:0]const u8 { + const result = err; + err = null; + return result; +} + +export fn dlinfo(noalias handle: ?*anyopaque, request: c_int, noalias info: ?*anyopaque) c_int { + const lib: *const Lib = @ptrCast(@alignCast(handle.?)); + log.info("dlinfo({f}, {}, {x})", .{ lib, request, @intFromPtr(info) }); + @panic("unimplemented"); +} + +pub const Lib = struct { + const main_program_name = "@SELF"; + const rtld_next_name = "@RTLD_NEXT"; + + name: []const u8, + symbols: std.StaticStringMap(*anyopaque), + + pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + try writer.print("@\"{f}\"", .{std.zig.fmtString(self.name)}); + } + + pub fn sym(val: anytype) *anyopaque { + return @ptrCast(@constCast(val)); + } +}; + +pub const FmtMode = struct { + val: std.c.RTLD, + + pub fn init(val: std.c.RTLD) @This() { + return .{ .val = val }; + } + + pub fn format(self: anytype, writer: *std.Io.Writer) std.Io.Writer.Error!void { + try writer.writeAll(".{"); + var first = true; + inline for (@typeInfo(@TypeOf(self.val)).@"struct".fields) |field| { + const val = @field(self.val, field.name); + switch (@typeInfo(field.type)) { + .bool => if (val) { + if (!first) { + try writer.writeAll(","); + } + first = false; + try writer.writeAll(" "); + try writer.print(".{s} = true", .{field.name}); + }, + .int => if (val != 0) { + if (!first) { + try writer.writeAll(", "); + first = false; + } + try writer.print(".{s} = {x}", .{ field.name, val }); + }, + else => comptime unreachable, + } + } + if (!first) try writer.writeAll(" "); + try writer.writeAll("}"); + } +}; diff --git a/src/screen-play.c b/src/screen-play.c index f13af81..3d1dcfe 100644 --- a/src/screen-play.c +++ b/src/screen-play.c @@ -61,14 +61,14 @@ struct data { static void handle_events(struct data *data) { - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_EVENT_QUIT: - pw_main_loop_quit(data->loop); - break; - } - } + // SDL_Event event; + // while (SDL_PollEvent(&event)) { + // switch (event.type) { + // case SDL_EVENT_QUIT: + // pw_main_loop_quit(data->loop); + // break; + // } + // } } /* our data processing function is in general: @@ -147,19 +147,19 @@ on_process(void *_data) data->cursor_rect.w = mb->size.width; data->cursor_rect.h = mb->size.height; - if (data->cursor == NULL) { - data->cursor = SDL_CreateTexture(data->renderer, - id_to_sdl_format(mb->format), - SDL_TEXTUREACCESS_STREAMING, - mb->size.width, mb->size.height); - SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); - } + // if (data->cursor == NULL) { + // data->cursor = SDL_CreateTexture(data->renderer, + // id_to_sdl_format(mb->format), + // SDL_TEXTUREACCESS_STREAMING, + // mb->size.width, mb->size.height); + // SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); + // } - if (!SDL_LockTexture(data->cursor, NULL, &cdata, &cstride)) { - fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError()); - goto done; - } + // if (!SDL_LockTexture(data->cursor, NULL, &cdata, &cstride)) { + // fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError()); + // goto done; + // } /* copy the cursor bitmap into the texture */ src = SPA_PTROFF(mb, mb->offset, uint8_t); @@ -171,7 +171,7 @@ on_process(void *_data) dst += cstride; src += mb->stride; } - SDL_UnlockTexture(data->cursor); + // SDL_UnlockTexture(data->cursor); render_cursor = true; } @@ -181,22 +181,22 @@ on_process(void *_data) void *datas[4]; sstride = data->stride; if (buf->n_datas == 1) { - SDL_UpdateTexture(data->texture, NULL, - sdata, sstride); + // SDL_UpdateTexture(data->texture, NULL, + // sdata, sstride); } else { datas[0] = sdata; datas[1] = buf->datas[1].data; datas[2] = buf->datas[2].data; - SDL_UpdateYUVTexture(data->texture, NULL, - datas[0], sstride, - datas[1], sstride / 2, - datas[2], sstride / 2); + // SDL_UpdateYUVTexture(data->texture, NULL, + // datas[0], sstride, + // datas[1], sstride / 2, + // datas[2], sstride / 2); } } else { - if (!SDL_LockTexture(data->texture, NULL, &ddata, &dstride)) { - fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); - } + // if (!SDL_LockTexture(data->texture, NULL, &ddata, &dstride)) { + // fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); + // } sstride = buf->datas[0].chunk->stride; if (sstride == 0) @@ -225,16 +225,16 @@ on_process(void *_data) dst += dstride; } } - SDL_UnlockTexture(data->texture); + // SDL_UnlockTexture(data->texture); } - SDL_RenderClear(data->renderer); - /* now render the video and then the cursor if any */ - SDL_RenderTexture(data->renderer, data->texture, &data->rect, NULL); - if (render_cursor) { - SDL_RenderTexture(data->renderer, data->cursor, NULL, &data->cursor_rect); - } - SDL_RenderPresent(data->renderer); + // SDL_RenderClear(data->renderer); + // /* now render the video and then the cursor if any */ + // SDL_RenderTexture(data->renderer, data->texture, &data->rect, NULL); + // if (render_cursor) { + // SDL_RenderTexture(data->renderer, data->cursor, NULL, &data->cursor_rect); + // } + // SDL_RenderPresent(data->renderer); done: pw_stream_queue_buffer(stream, b); @@ -498,15 +498,15 @@ int main(int argc, char *argv[]) &stream_events, &data); - if (!SDL_Init(SDL_INIT_VIDEO)) { - fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError()); - return -1; - } + // if (!SDL_Init(SDL_INIT_VIDEO)) { + // fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError()); + // return -1; + // } - if (!SDL_CreateWindowAndRenderer("Demo", WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) { - fprintf(stderr, "can't create window: %s\n", SDL_GetError()); - return -1; - } + // if (!SDL_CreateWindowAndRenderer("Demo", WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) { + // fprintf(stderr, "can't create window: %s\n", SDL_GetError()); + // return -1; + // } /* build the extra parameters to connect with. To connect, we can provide * a list of supported formats. We use a builder that writes the param @@ -543,11 +543,11 @@ int main(int argc, char *argv[]) pw_stream_destroy(data.stream); pw_main_loop_destroy(data.loop); - SDL_DestroyTexture(data.texture); - if (data.cursor) - SDL_DestroyTexture(data.cursor); - SDL_DestroyRenderer(data.renderer); - SDL_DestroyWindow(data.window); + // SDL_DestroyTexture(data.texture); + // if (data.cursor) + // SDL_DestroyTexture(data.cursor); + // SDL_DestroyRenderer(data.renderer); + // SDL_DestroyWindow(data.window); pw_deinit(); return 0; diff --git a/src/sdl.h b/src/sdl.h index 002d134..b066476 100644 --- a/src/sdl.h +++ b/src/sdl.h @@ -148,21 +148,22 @@ static inline struct spa_pod *sdl_build_formats(SDL_Renderer * renderer, struct SDL_PropertiesID props = SDL_GetRendererProperties(renderer); - const SDL_PixelFormat *texture_formats = SDL_GetPointerProperty( - props, - SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, - NULL - ); + // const SDL_PixelFormat *texture_formats = nullptr; + // SDL_GetPointerProperty( + // props, + // SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, + // NULL + // ); /* first the formats supported by the textures */ - for (i = 0, c = 0; texture_formats[i] != SDL_PIXELFORMAT_UNKNOWN; i++) { - uint32_t id = sdl_format_to_id(texture_formats[i]); - if (id == 0) - continue; - if (c++ == 0) - spa_pod_builder_id(b, SPA_VIDEO_FORMAT_UNKNOWN); - spa_pod_builder_id(b, id); - } + // for (i = 0, c = 0; texture_formats[i] != SDL_PIXELFORMAT_UNKNOWN; i++) { + // uint32_t id = sdl_format_to_id(texture_formats[i]); + // if (id == 0) + // continue; + // if (c++ == 0) + // spa_pod_builder_id(b, SPA_VIDEO_FORMAT_UNKNOWN); + // spa_pod_builder_id(b, id); + // } /* then all the other ones SDL can convert from/to */ SPA_FOR_EACH_ELEMENT_VAR(sdl_video_formats, f) { uint32_t id = f->id; @@ -172,11 +173,12 @@ static inline struct spa_pod *sdl_build_formats(SDL_Renderer * renderer, struct spa_pod_builder_id(b, SPA_VIDEO_FORMAT_RGBA_F32); spa_pod_builder_pop(b, &f[1]); /* add size and framerate ranges */ - uint64_t max_texture_size = SDL_GetNumberProperty( - props, - SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, - 0 - ); + // uint64_t max_texture_size = SDL_GetNumberProperty( + // props, + // SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, + // 0 + // ); + uint64_t max_texture_size = 4096; spa_pod_builder_add(b, SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle( &SPA_RECTANGLE(WIDTH, HEIGHT),