moved files from gstreamer minimal example

This commit is contained in:
Nicholas Young 2024-10-02 17:52:41 -07:00
parent 972fd2eeb8
commit 304e065762
5 changed files with 339 additions and 2 deletions

4
.gitignore vendored
View file

@ -1,6 +1,6 @@
# ---> Zig
zig-cache/
zig-out/
.zig-cache/*
zig-out/*
build/
build-*/
docgen_tmp/

81
build.zig Normal file
View file

@ -0,0 +1,81 @@
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "zig-gst",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// These environment vars are set with the `nix develop` command
const gst_dev_path = b.graph.env_map.get("GST_DEV_PATH");
const glib_dev_path = b.graph.env_map.get("GLIB_DEV_PATH");
const glib_path = b.graph.env_map.get("GLIB_PATH");
if (gst_dev_path == null) {
std.debug.panic("GST_DEV_PATH environment variable was not set. Has the nix flake been updated? This should point at the gstreamer.XXX-dev folder", .{});
}
if (glib_dev_path == null) {
std.debug.panic("GLIB_DEV_PATH environment variable was not set. Has the nix flake been updated? This should point at the glib.XXX-dev folder", .{});
}
if (glib_path == null) {
std.debug.panic("GLIB_PATH environment variable was not set. Has the nix flake been updated? This should point at the glib.XXX folder", .{});
}
exe.linkSystemLibrary("c");
exe.addIncludePath(.{ .cwd_relative = b.fmt("{s}/include/gstreamer-1.0", .{gst_dev_path.?}) }); // not sure why both are needed, but
exe.addIncludePath(.{ .cwd_relative = b.fmt("{s}/include/gstreamer-1.0/gst", .{gst_dev_path.?}) }); // it won't compile without them
exe.addIncludePath(.{ .cwd_relative = b.fmt("{s}/include/glib-2.0", .{glib_dev_path.?}) });
exe.addIncludePath(.{ .cwd_relative = b.fmt("{s}/lib/glib-2.0/include", .{glib_path.?}) });
exe.linkSystemLibrary("gstreamer-1.0");
exe.linkSystemLibrary("glib-2.0");
exe.linkSystemLibrary("gobject-2.0");
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

147
flake.lock Normal file
View file

@ -0,0 +1,147 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1727802920,
"narHash": "sha256-HP89HZOT0ReIbI7IJZJQoJgxvB2Tn28V6XS3MNKnfLs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "27e30d177e57d912d614c88c622dcfdb2e6e6515",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1708161998,
"narHash": "sha256-6KnemmUorCvlcAvGziFosAVkrlWZGIc6UNT9GUYr0jQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "84d981bae8b5e783b3b548de505b22880559515f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"zig": "zig"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"zig": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1727656237,
"narHash": "sha256-qfZ7nYqYmzPc3Ei9hvWRrFu3Mn3WJ2akyYvaoPOOHcM=",
"owner": "mitchellh",
"repo": "zig-overlay",
"rev": "5bdd678ad99cd0069dfa6a5822c1d82d45d34ad2",
"type": "github"
},
"original": {
"owner": "mitchellh",
"repo": "zig-overlay",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

34
flake.nix Normal file
View file

@ -0,0 +1,34 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
zig.url = "github:mitchellh/zig-overlay";
flake-utils = { url = "github:numtide/flake-utils"; };
};
outputs = { self, nixpkgs, zig, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem(system:
let
pkgs = import nixpkgs {
inherit system;
};
zig_exe = zig.packages.${system}.master;
in
{
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
zig_exe
glib
glib.dev
gst_all_1.gstreamer
gst_all_1.gstreamer.dev
gst_all_1.gst-plugins-base
gst_all_1.gst-plugins-good
];
GST_DEV_PATH = pkgs.gst_all_1.gstreamer.dev;
GLIB_DEV_PATH = pkgs.glib.dev;
GLIB_PATH = pkgs.glib.out;
};
}
);
}

75
src/main.zig Normal file
View file

@ -0,0 +1,75 @@
const std = @import("std");
const gst = @cImport({ // glib-object for g_object_* functions
@cInclude("glib-object.h");
@cInclude("gst.h");
@cInclude("glib.h"); // and glib for other g_* functions
});
pub fn main() void {
// This allows me to utilize the same command line args and gstreamer
gst.gst_init(@ptrCast(&std.os.argv.len), @ptrCast(&std.os.argv.ptr));
const source: ?*gst.GstElement = gst.gst_element_factory_make("videotestsrc", "source");
const sink: ?*gst.GstElement = gst.gst_element_factory_make("autovideosink", "sink");
const pipeline: ?*gst.GstElement = gst.gst_pipeline_new("test-pipeline");
if (source == null or sink == null or pipeline == null) {
std.debug.panic("Not all elements could be created!", .{});
}
// When you look into the GST_BIN macro that zig can't compile,
// it really is just this pointer cast with extra steps of verification
const bin: *gst.GstBin = @ptrCast(pipeline);
// Gstreamer gives a critical warning when using gst.gst_bin_add_many, but doesn't
// when calling each individually
_ = gst.gst_bin_add(bin, source);
_ = gst.gst_bin_add(bin, sink);
// the failure return code is -1 I believe
if (gst.gst_element_link(source, sink) < 0) {
gst.gst_object_unref(pipeline);
std.debug.panic("Elements could not be linked\n", .{});
}
// g_int is just i32. You can
gst.g_object_set(source, "pattern", @as(i16, 0));
const ret = gst.gst_element_set_state(pipeline, gst.GST_STATE_PLAYING);
if (ret == gst.GST_STATE_CHANGE_FAILURE) {
gst.gst_object_unref(pipeline);
std.debug.panic("Could not start pipeline", .{});
}
const bus: *gst.GstBus = gst.gst_element_get_bus(pipeline);
const msg: *gst.GstMessage = gst.gst_bus_timed_pop_filtered( // This call holds until there is a valid message
bus,
gst.GST_CLOCK_TIME_NONE,
gst.GST_MESSAGE_ERROR | gst.GST_MESSAGE_EOS,
);
if (gst.GST_MESSAGE_TYPE(msg) == gst.GST_MESSAGE_ERROR) {
const err: [*c][*c]gst.GError = null;
var debug_info: ?*gst.gchar = null;
switch (gst.GST_MESSAGE_TYPE(msg)) {
gst.GST_MESSAGE_ERROR => {
gst.gst_message_parse_error(msg, err, &debug_info);
std.debug.print("Error received from element {s}: {s}", .{ gst.GST_OBJECT_NAME(msg.src), err.*.*.message });
if (debug_info != null) { // I couldn't figure out how to do a orelse statement for this unwrap.
std.debug.print("Debugging information: {s}", .{debug_info.?});
}
gst.g_clear_error(err);
gst.g_free(debug_info);
},
else => {},
}
gst.gst_message_unref(msg);
}
gst.gst_object_unref(bus);
_ = gst.gst_element_set_state(pipeline, gst.GST_STATE_NULL);
gst.gst_object_unref(pipeline);
}