From e302328628d287d98d374404c61103cbf457af48 Mon Sep 17 00:00:00 2001 From: Julek <dnjulek@hotmail.com> Date: Fri, 12 Apr 2024 22:23:50 -0300 Subject: [PATCH] add example for zigapi --- example/README.md | 21 ---- examples/README.md | 4 + examples/example-zigapi/README.md | 21 ++++ .../example-zigapi}/build.zig | 0 .../example-zigapi}/build.zig.zon | 4 +- .../example-zigapi/src/invert_example.zig | 107 ++++++++++++++++++ examples/example/README.md | 21 ++++ examples/example/build.zig | 53 +++++++++ examples/example/build.zig.zon | 11 ++ .../example}/src/invert_example.zig | 0 test/src/invert_example.zig | 56 +++++---- 11 files changed, 246 insertions(+), 52 deletions(-) delete mode 100644 example/README.md create mode 100644 examples/README.md create mode 100644 examples/example-zigapi/README.md rename {example => examples/example-zigapi}/build.zig (100%) rename {example => examples/example-zigapi}/build.zig.zon (58%) create mode 100644 examples/example-zigapi/src/invert_example.zig create mode 100644 examples/example/README.md create mode 100644 examples/example/build.zig create mode 100644 examples/example/build.zig.zon rename {example => examples/example}/src/invert_example.zig (100%) diff --git a/example/README.md b/example/README.md deleted file mode 100644 index 21f5570..0000000 --- a/example/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# invert_example - -To use this module in your project you will need: -1. A [build.zig.zon](/example/build.zig.zon) file like this. -2. These lines in your [build.zig](/example/build.zig): - -```zig -const vapoursynth_dep = b.dependency("vapoursynth", .{ - .target = target, - .optimize = optimize, -}); - -lib.root_module.addImport("vapoursynth", vapoursynth_dep.module("vapoursynth")); -``` - -The [invert_example.zig](/example/src/invert_example.zig) is based on [invert_example.c](https://github.com/vapoursynth/vapoursynth/blob/master/sdk/invert_example.c), from the VapourSynth SDK, I recommend checking it out first if you don't know the framework. - -## Building -Zig version should be the master, 0.11.0 not supported. - -``zig build -Doptimize=ReleaseFast`` diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..da73a35 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,4 @@ +# Examples + +[example](/example/) shows how to use the C binding only.\ +[example-zigapi](/example-zigapi/) shows how to use the C binding with extra Zig struct/methods. diff --git a/examples/example-zigapi/README.md b/examples/example-zigapi/README.md new file mode 100644 index 0000000..ebdd3bc --- /dev/null +++ b/examples/example-zigapi/README.md @@ -0,0 +1,21 @@ +# invert_example + +To use this module in your project you will need: +1. A [build.zig.zon](/examples/example-zigapi/build.zig.zon) file like this. +2. These lines in your [build.zig](/examples/example-zigapi/build.zig): + +```zig +const vapoursynth_dep = b.dependency("vapoursynth", .{ + .target = target, + .optimize = optimize, +}); + +lib.root_module.addImport("vapoursynth", vapoursynth_dep.module("vapoursynth")); +``` + +The [invert_example.zig](/examples/example-zigapi/src/invert_example.zig) is based on [invert_example.c](https://github.com/vapoursynth/vapoursynth/blob/master/sdk/invert_example.c), from the VapourSynth SDK, I recommend checking it out first if you don't know the framework. + +## Building +Zig version should be the master, 0.11.0 not supported. + +``zig build -Doptimize=ReleaseFast`` diff --git a/example/build.zig b/examples/example-zigapi/build.zig similarity index 100% rename from example/build.zig rename to examples/example-zigapi/build.zig diff --git a/example/build.zig.zon b/examples/example-zigapi/build.zig.zon similarity index 58% rename from example/build.zig.zon rename to examples/example-zigapi/build.zig.zon index 7167ff7..e2cdd0c 100644 --- a/example/build.zig.zon +++ b/examples/example-zigapi/build.zig.zon @@ -4,8 +4,8 @@ .paths = .{""}, .dependencies = .{ .vapoursynth = .{ - .url = "https://github.com/dnjulek/vapoursynth-zig/archive/6b5dfc82c74fc81de502b3c01b6fe9893f8359e6.tar.gz", - .hash = "12205f58b4ccddbbccea25cae0e801030e3959885e980454a607e0015707758f1398", + .url = "https://github.com/dnjulek/vapoursynth-zig/archive/2f6a59a6cccf23cec7ca8a3abb3f316593c5ed7b.tar.gz", + .hash = "12201cb4befda1224caa03a57a2188d5d5e985a7fdd7a8b3277d385dba4cb0e272cb", }, }, } diff --git a/examples/example-zigapi/src/invert_example.zig b/examples/example-zigapi/src/invert_example.zig new file mode 100644 index 0000000..431a340 --- /dev/null +++ b/examples/example-zigapi/src/invert_example.zig @@ -0,0 +1,107 @@ +//! https://github.com/vapoursynth/vapoursynth/blob/master/sdk/invert_example.c + +const std = @import("std"); +const vapoursynth = @import("vapoursynth"); + +const math = std.math; +const vs = vapoursynth.vapoursynth4; +const vsh = vapoursynth.vshelper; +const zapi = vapoursynth.zigapi; + +// https://ziglang.org/documentation/master/#Choosing-an-Allocator +const allocator = std.heap.c_allocator; + +const InvertData = struct { + node: ?*vs.Node, + vi: *const vs.VideoInfo, + enabled: bool, +}; + +export fn invertGetFrame(n: c_int, activation_reason: vs.ActivationReason, instance_data: ?*anyopaque, frame_data: ?*?*anyopaque, frame_ctx: ?*vs.FrameContext, core: ?*vs.Core, vsapi: ?*const vs.API) callconv(.C) ?*const vs.Frame { + _ = frame_data; + const d: *InvertData = @ptrCast(@alignCast(instance_data)); + + if (activation_reason == .Initial) { + vsapi.?.requestFrameFilter.?(n, d.node, frame_ctx); + } else if (activation_reason == .AllFramesReady) { + var src = zapi.Frame.init(d.node, n, frame_ctx, core, vsapi); + defer src.deinit(); + var dst = src.newVideoFrame(); + + var plane: u32 = 0; + while (plane < d.vi.format.numPlanes) : (plane += 1) { + var srcp = src.getReadPtr(plane); + var dstp = dst.getWritePtr(plane); + + // getDimensions returns a tuple with [width, height, stride], + // use getDimensions2 if you want a struct. + const w, const h, const stride = src.getDimensions(plane); + + var y: u32 = 0; + while (y < h) : (y += 1) { + var x: u32 = 0; + while (x < w) : (x += 1) { + dstp[x] = if (d.enabled) ~(srcp[x]) else srcp[x]; + } + + dstp = dstp[stride..]; + srcp = srcp[stride..]; + } + } + + return dst.frame; + } + + return null; +} + +export fn invertFree(instance_data: ?*anyopaque, core: ?*vs.Core, vsapi: ?*const vs.API) callconv(.C) void { + _ = core; + const d: *InvertData = @ptrCast(@alignCast(instance_data)); + vsapi.?.freeNode.?(d.node); + allocator.destroy(d); +} + +export fn invertCreate(in: ?*const vs.Map, out: ?*vs.Map, user_data: ?*anyopaque, core: ?*vs.Core, vsapi: ?*const vs.API) callconv(.C) void { + _ = user_data; + var d: InvertData = undefined; + var map = zapi.Map.init(in, out, vsapi); + + // getNodeVi returns a tuple with [vs.Node, vs.VideoInfo], + // use getNodeVi2 if you want a struct. + d.node, d.vi = map.getNodeVi("clip"); + + if (!vsh.isConstantVideoFormat(d.vi) or (d.vi.format.sampleType != .Integer) or (d.vi.format.bitsPerSample != 8)) { + map.setError("Invert: only constant format 8bit integer input supported"); + vsapi.?.freeNode.?(d.node); + return; + } + + // https://ziglang.org/documentation/master/#Optionals + const enabled = map.getInt(i32, "enabled") orelse 1; + + if ((enabled < 0) or (enabled > 1)) { + map.setError("Invert: enabled must be 0 or 1"); + vsapi.?.freeNode.?(d.node); + return; + } + + d.enabled = enabled == 1; + + const data: *InvertData = allocator.create(InvertData) catch unreachable; + data.* = d; + + var deps = [_]vs.FilterDependency{ + vs.FilterDependency{ + .source = d.node, + .requestPattern = .StrictSpatial, + }, + }; + + vsapi.?.createVideoFilter.?(out, "Invert", d.vi, invertGetFrame, invertFree, .Parallel, &deps, deps.len, data, core); +} + +export fn VapourSynthPluginInit2(plugin: *vs.Plugin, vspapi: *const vs.PLUGINAPI) void { + _ = vspapi.configPlugin.?("com.example.zinvert", "zinvert", "VapourSynth Invert Example", vs.makeVersion(1, 0), vs.VAPOURSYNTH_API_VERSION, 0, plugin); + _ = vspapi.registerFunction.?("Filter", "clip:vnode;enabled:int:opt;", "clip:vnode;", invertCreate, null, plugin); +} diff --git a/examples/example/README.md b/examples/example/README.md new file mode 100644 index 0000000..35a7c08 --- /dev/null +++ b/examples/example/README.md @@ -0,0 +1,21 @@ +# invert_example + +To use this module in your project you will need: +1. A [build.zig.zon](/examples/example/build.zig.zon) file like this. +2. These lines in your [build.zig](/examples/example/build.zig): + +```zig +const vapoursynth_dep = b.dependency("vapoursynth", .{ + .target = target, + .optimize = optimize, +}); + +lib.root_module.addImport("vapoursynth", vapoursynth_dep.module("vapoursynth")); +``` + +The [invert_example.zig](/examples/example/src/invert_example.zig) is based on [invert_example.c](https://github.com/vapoursynth/vapoursynth/blob/master/sdk/invert_example.c), from the VapourSynth SDK, I recommend checking it out first if you don't know the framework. + +## Building +Zig version should be the master. + +``zig build -Doptimize=ReleaseFast`` diff --git a/examples/example/build.zig b/examples/example/build.zig new file mode 100644 index 0000000..24733a0 --- /dev/null +++ b/examples/example/build.zig @@ -0,0 +1,53 @@ +const std = @import("std"); + +pub const min_zig_version = std.SemanticVersion{ .major = 0, .minor = 12, .patch = 0, .pre = "dev.2158" }; + +pub fn build(b: *std.Build) void { + ensureZigVersion() catch return; + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const lib = b.addSharedLibrary(.{ + .name = "invert_example", + .root_source_file = .{ .path = "src/invert_example.zig" }, + .target = target, + .optimize = optimize, + }); + + const vapoursynth_dep = b.dependency("vapoursynth", .{ + .target = target, + .optimize = optimize, + }); + + lib.root_module.addImport("vapoursynth", vapoursynth_dep.module("vapoursynth")); + lib.linkLibC(); + + if (lib.root_module.optimize == .ReleaseFast) { + lib.root_module.strip = true; + } + + b.installArtifact(lib); +} + +fn ensureZigVersion() !void { + var installed_ver = @import("builtin").zig_version; + installed_ver.build = null; + + if (installed_ver.order(min_zig_version) == .lt) { + std.log.err("\n" ++ + \\--------------------------------------------------------------------------- + \\ + \\Installed Zig compiler version is too old. + \\ + \\Min. required version: {any} + \\Installed version: {any} + \\ + \\Please install newer version and try again. + \\Latest version can be found here: https://ziglang.org/download/ + \\ + \\--------------------------------------------------------------------------- + \\ + , .{ min_zig_version, installed_ver }); + return error.ZigIsTooOld; + } +} diff --git a/examples/example/build.zig.zon b/examples/example/build.zig.zon new file mode 100644 index 0000000..e2cdd0c --- /dev/null +++ b/examples/example/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = "invert_example", + .version = "1.0.0", + .paths = .{""}, + .dependencies = .{ + .vapoursynth = .{ + .url = "https://github.com/dnjulek/vapoursynth-zig/archive/2f6a59a6cccf23cec7ca8a3abb3f316593c5ed7b.tar.gz", + .hash = "12201cb4befda1224caa03a57a2188d5d5e985a7fdd7a8b3277d385dba4cb0e272cb", + }, + }, +} diff --git a/example/src/invert_example.zig b/examples/example/src/invert_example.zig similarity index 100% rename from example/src/invert_example.zig rename to examples/example/src/invert_example.zig diff --git a/test/src/invert_example.zig b/test/src/invert_example.zig index 888fcfc..431a340 100644 --- a/test/src/invert_example.zig +++ b/test/src/invert_example.zig @@ -6,12 +6,14 @@ const vapoursynth = @import("vapoursynth"); const math = std.math; const vs = vapoursynth.vapoursynth4; const vsh = vapoursynth.vshelper; +const zapi = vapoursynth.zigapi; // https://ziglang.org/documentation/master/#Choosing-an-Allocator const allocator = std.heap.c_allocator; const InvertData = struct { node: ?*vs.Node, + vi: *const vs.VideoInfo, enabled: bool, }; @@ -22,38 +24,32 @@ export fn invertGetFrame(n: c_int, activation_reason: vs.ActivationReason, insta if (activation_reason == .Initial) { vsapi.?.requestFrameFilter.?(n, d.node, frame_ctx); } else if (activation_reason == .AllFramesReady) { - const src = vsapi.?.getFrameFilter.?(n, d.node, frame_ctx); + var src = zapi.Frame.init(d.node, n, frame_ctx, core, vsapi); + defer src.deinit(); + var dst = src.newVideoFrame(); - // https://ziglang.org/documentation/master/#defer - defer vsapi.?.freeFrame.?(src); + var plane: u32 = 0; + while (plane < d.vi.format.numPlanes) : (plane += 1) { + var srcp = src.getReadPtr(plane); + var dstp = dst.getWritePtr(plane); - const fi = vsapi.?.getVideoFrameFormat.?(src); + // getDimensions returns a tuple with [width, height, stride], + // use getDimensions2 if you want a struct. + const w, const h, const stride = src.getDimensions(plane); - const height = vsapi.?.getFrameHeight.?(src, 0); - const width = vsapi.?.getFrameWidth.?(src, 0); - const dst = vsapi.?.newVideoFrame.?(fi, width, height, src, core); - - var plane: c_int = 0; - while (plane < fi.numPlanes) : (plane += 1) { - var srcp: [*]const u8 = vsapi.?.getReadPtr.?(src, plane); - var dstp: [*]u8 = vsapi.?.getWritePtr.?(dst, plane); - const stride: usize = @intCast(vsapi.?.getStride.?(src, plane)); - const h: usize = @intCast(vsapi.?.getFrameHeight.?(src, plane)); - const w: usize = @intCast(vsapi.?.getFrameWidth.?(src, plane)); - - var y: usize = 0; + var y: u32 = 0; while (y < h) : (y += 1) { - var x: usize = 0; + var x: u32 = 0; while (x < w) : (x += 1) { dstp[x] = if (d.enabled) ~(srcp[x]) else srcp[x]; } - dstp += stride; - srcp += stride; + dstp = dstp[stride..]; + srcp = srcp[stride..]; } } - return dst; + return dst.frame; } return null; @@ -69,21 +65,23 @@ export fn invertFree(instance_data: ?*anyopaque, core: ?*vs.Core, vsapi: ?*const export fn invertCreate(in: ?*const vs.Map, out: ?*vs.Map, user_data: ?*anyopaque, core: ?*vs.Core, vsapi: ?*const vs.API) callconv(.C) void { _ = user_data; var d: InvertData = undefined; + var map = zapi.Map.init(in, out, vsapi); - d.node = vsapi.?.mapGetNode.?(in, "clip", 0, null).?; - const vi: *const vs.VideoInfo = vsapi.?.getVideoInfo.?(d.node); + // getNodeVi returns a tuple with [vs.Node, vs.VideoInfo], + // use getNodeVi2 if you want a struct. + d.node, d.vi = map.getNodeVi("clip"); - if (!vsh.isConstantVideoFormat(vi) or (vi.format.sampleType != .Integer) or (vi.format.bitsPerSample != @as(c_int, 8))) { - vsapi.?.mapSetError.?(out, "Invert: only constant format 8bit integer input supported"); + if (!vsh.isConstantVideoFormat(d.vi) or (d.vi.format.sampleType != .Integer) or (d.vi.format.bitsPerSample != 8)) { + map.setError("Invert: only constant format 8bit integer input supported"); vsapi.?.freeNode.?(d.node); return; } // https://ziglang.org/documentation/master/#Optionals - const enabled = vsh.mapGetN(i32, in, "enabled", 0, vsapi) orelse 1; + const enabled = map.getInt(i32, "enabled") orelse 1; if ((enabled < 0) or (enabled > 1)) { - vsapi.?.mapSetError.?(out, "Invert: enabled must be 0 or 1"); + map.setError("Invert: enabled must be 0 or 1"); vsapi.?.freeNode.?(d.node); return; } @@ -100,10 +98,10 @@ export fn invertCreate(in: ?*const vs.Map, out: ?*vs.Map, user_data: ?*anyopaque }, }; - vsapi.?.createVideoFilter.?(out, "Invert", vi, invertGetFrame, invertFree, .Parallel, &deps, deps.len, data, core); + vsapi.?.createVideoFilter.?(out, "Invert", d.vi, invertGetFrame, invertFree, .Parallel, &deps, deps.len, data, core); } export fn VapourSynthPluginInit2(plugin: *vs.Plugin, vspapi: *const vs.PLUGINAPI) void { - _ = vspapi.configPlugin.?("com.example.invert", "invert", "VapourSynth Invert Example", vs.makeVersion(1, 0), vs.VAPOURSYNTH_API_VERSION, 0, plugin); + _ = vspapi.configPlugin.?("com.example.zinvert", "zinvert", "VapourSynth Invert Example", vs.makeVersion(1, 0), vs.VAPOURSYNTH_API_VERSION, 0, plugin); _ = vspapi.registerFunction.?("Filter", "clip:vnode;enabled:int:opt;", "clip:vnode;", invertCreate, null, plugin); }