Mysterious Buggy Behaviour when trying to get parameters in OpenFX 1.4 API

41 Views Asked by At

I am trying to write a OpenFX 1.4 Plugin but I am having awful errors like that my Message of error "THE PARAMETER WAS NOT RETRIVED " being printed to stderr/stdout, and the frame not being printed, which would no happen anyway in this minimal reproducible example but in the project code I have some effect code that Is not being executed because is failing to retrive the parameter which is what indicates the error message that wrote. I have checked it multiple times against the examples in https://openfx.readthedocs.io but not idea of what is the mysterious error.

build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const openfxPlugin = b.addSharedLibrary(.{
        .name = "OpenFXPlugin",
        .root_source_file = .{ .path = "src/fxroot.zig" },
        .target = target,
        .optimize = optimize,
        .version = .{ .major = 0, .minor = 0, .patch = 0 },
    });

    openfxPlugin.addIncludePath(.{
        .path = "openfx/include",
    });

    openfxPlugin.addIncludePath(.{
        .path = "openfx/Support/include",
    });

    openfxPlugin.linkLibC();

    b.installArtifact(openfxPlugin);

    const unit_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/fxroot.zig" },
        .target = target,
        .optimize = optimize,
    });

    unit_tests.addIncludePath(.{
        .path = "openfx/include",
    });

    unit_tests.addIncludePath(.{
        .path = "openfx/Support/include",
    });

    unit_tests.linkLibC();

    const run_unit_tests = b.addRunArtifact(unit_tests);

    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_unit_tests.step);
}

src/fxroot.zig:

const std = @import("std");

const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");
    @cInclude("string.h");
});

const ofx = @cImport({
    @cInclude("ofxImageEffect.h");
});

const InstanceData = struct {
    testParameter: ofx.OfxParamHandle,
};

var gHost: ?*ofx.OfxHost = @ptrFromInt(0);
var gPropertySuite: ?*ofx.OfxPropertySuiteV1 = @ptrFromInt(0);
var gImageEffectSuite: ?*ofx.OfxImageEffectSuiteV1 = @ptrFromInt(0);
var gParameterSuite: ?*ofx.OfxParameterSuiteV1 = @ptrFromInt(0);

////////////////////////////////////////////////////////////////////////////////
// House keeper to make sure we are loaded and unloaded symetrically
var gInLoadedState: bool = false;
var gDescribeCalled: bool = false;
var gDescribeInContextCalled: bool = false;
var gNumInstancesLiving: i16 = 0;

fn error_abort(comptime msg: [*:0]const u8) void {
    _ = c.fprintf(c.stderr, "FATAL ERROR: %s", msg);
    c.abort();
}

fn LoadAction() ?ofx.OfxStatus {
    if (gHost == null) error_abort("The OfxHost pointer has not been set, it should have been set in 'setHostFunc' before any action is called.");
    if (gInLoadedState) error_abort("kOfxActionLoad called more than once without an intervening kOfxUnloadAction.");

    if (gHost) |gHostInner| {
        gPropertySuite = @constCast(@alignCast(@ptrCast(gHostInner.fetchSuite.?(gHostInner.host, ofx.kOfxPropertySuite, 1))));

        if (gPropertySuite == null) {
            _ = c.fprintf(c.stdout, "FATAL ERROR: Failed to fetch the %s verison 1 from the host.", ofx.kOfxPropertySuite);
            c.abort();
        }

        gImageEffectSuite = @constCast(@alignCast(@ptrCast(gHostInner.fetchSuite.?(gHostInner.host, ofx.kOfxImageEffectSuite, 1))));

        gParameterSuite = @constCast(@alignCast(@ptrCast(gHostInner.fetchSuite.?(gHostInner.host, ofx.kOfxParameterSuite, 1))));

        gInLoadedState = true;
    }

    return ofx.kOfxStatOK;
}

////////////////////////////////////////////////////////////////////////////////
// last action called before a plugin binary is unloaded.
fn UnloadAction() ofx.OfxStatus {
    // make sure no instances have been left alive
    if (gNumInstancesLiving != 0) {
        _ = c.fprintf(c.stdout, "kOfxActionUnload called while there are still %d instances of the plugin extant.", gNumInstancesLiving);
    }

    // check that we had a load called first
    if (gInLoadedState) _ = c.fprintf(c.stdout, "kOfxActionUnload callewd without preceding kOfxAcrtionLoad%s", ".");
    gInLoadedState = false;

    return ofx.kOfxStatOK;
}

////////////////////////////////////////////////////////////////////////////////
// the plugin's basic description routine
fn DescribeAction(descriptor: ofx.OfxImageEffectHandle) ofx.OfxStatus {
    // check stuff
    if (!gInLoadedState) error_abort("kOfxActionLoad has not been called");
    gDescribeCalled = true;

    // get the property set handle for the plugin
    var effectProps: ofx.OfxPropertySetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.getPropertySet.?(descriptor, &effectProps);

    // set some labels and the group it belongs to
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxPropLabel, 0, "Test");
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxImageEffectPluginPropGrouping, 0, "TV Tools");

    // define the image effects contexts we can be used in, in this case a simple filter
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxImageEffectPropSupportedContexts, 0, ofx.kOfxImageEffectContextFilter);

    // Set supported pixel depths
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxImageEffectPropSupportedPixelDepths, 0, ofx.kOfxBitDepthFloat);

    // say that a single instance of this plugin can be rendered in multiple threads
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxImageEffectPluginRenderThreadSafety, 0, ofx.kOfxImageEffectRenderFullySafe);

    // say that the host should manage SMP threading over a single frame
    _ = gPropertySuite.?.propSetString.?(effectProps, ofx.kOfxImageEffectPluginPropHostFrameThreading, 0, 1);

    return ofx.kOfxStatOK;
}

fn RenderAction(effect: ofx.OfxImageEffectHandle, inArgs: ofx.OfxPropertySetHandle, _: ofx.OfxPropertySetHandle) ofx.OfxStatus {
    var time: ofx.OfxTime = 0;
    _ = gPropertySuite.?.propGetDouble.?(inArgs, ofx.kOfxPropTime, 0, &time);

    const instanceData: *InstanceData = blk: {
        var effectProps: ofx.OfxPropertySetHandle = @ptrFromInt(0);
        _ = gImageEffectSuite.?.getPropertySet.?(effect, &effectProps);
        if (FetchInstanceData(effectProps)) |innerselben| {
            break :blk innerselben;
        } else {
            return ofx.kOfxStatErrBadHandle;
        }
    };

    _ = blk: {
        var testParam: ?f64 = null;
        _ = gParameterSuite.?.paramGetValueAtTime.?(instanceData.testParameter, time, &testParam);
        if (testParam) |rts| {
            break :blk rts;
        }
        std.debug.print("THE PARAMETER WAS NOT RETRIVED \n", .{});
        return ofx.kOfxStatErrBadHandle;
    };

    return ofx.kOfxStatFailed;
}

fn CreateInstanceAction(instance: ofx.OfxImageEffectHandle) ofx.OfxStatus {
    if (!gDescribeInContextCalled) error_abort("CreateInstanceAction called before DescribeInContext.");
    gNumInstancesLiving += 1;

    var effectProps: ofx.OfxPropertySetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.getPropertySet.?(instance, &effectProps);

    const instanceData: *InstanceData = blk: {
        if (@as(?*InstanceData, @alignCast(@ptrCast(c.malloc(@sizeOf(InstanceData)))))) |v| {
            break :blk v;
        } else {
            return ofx.kOfxStatErrMemory;
        }
    };
    _ = gPropertySuite.?.propSetPointer.?(effectProps, ofx.kOfxPropInstanceData, 0, instanceData);
    var paramSet: ofx.OfxParamSetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.getParamSet.?(instance, &paramSet);
    _ = gParameterSuite.?.paramGetHandle.?(paramSet, "testParameter", &instanceData.testParameter, 0);

    return ofx.kOfxStatOK;
}

fn FetchInstanceData(effectProps: ofx.OfxPropertySetHandle) ?*InstanceData {
    var instanceData: ?*InstanceData = @ptrFromInt(0);
    _ = gPropertySuite.?.propGetPointer.?(effectProps, ofx.kOfxPropInstanceData, 0, @ptrCast(&instanceData));
    return instanceData;
}

fn DestroyInstanceAction(instance: ofx.OfxImageEffectHandle) ofx.OfxStatus {
    gNumInstancesLiving -= 1;

    var effectProps: ofx.OfxPropertySetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.getPropertySet.?(instance, &effectProps);

    if (FetchInstanceData(effectProps)) |innerselben| {
        c.free(innerselben);
    } else {
        _ = c.fprintf(c.stdout, "Instance should not be null!", "");
    }

    return ofx.kOfxStatOK;
}

fn DescribeInContextAction(descriptor: ofx.OfxImageEffectHandle, inArgs: ofx.OfxPropertySetHandle) ofx.OfxStatus {
    gDescribeInContextCalled = true;

    var context: [*c]u8 = @ptrFromInt(0);
    _ = gPropertySuite.?.propGetString.?(inArgs, ofx.kOfxImageEffectPropContext, 0, &context);

    if (c.strcmp(context, ofx.kOfxImageEffectContextFilter) != 0) {
        _ = c.fprintf(c.stdout, "FATAL ERROR: DescribeInContextAction called on unsupported contex %s", context);
        c.abort();
    }

    var props: ofx.OfxPropertySetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.clipDefine.?(descriptor, "Output", &props);
    _ = gPropertySuite.?.propSetString.?(props, ofx.kOfxImageEffectPropSupportedComponents, 0, ofx.kOfxImageComponentRGB);

    _ = gImageEffectSuite.?.clipDefine.?(descriptor, "Source", &props);
    _ = gPropertySuite.?.propSetString.?(props, ofx.kOfxImageEffectPropSupportedComponents, 0, ofx.kOfxImageComponentRGB);

    var paramSet: ofx.OfxParamSetHandle = @ptrFromInt(0);
    _ = gImageEffectSuite.?.getParamSet.?(descriptor, &paramSet);

    var paramProps: ofx.OfxPropertySetHandle = @ptrFromInt(0);
    _ = gParameterSuite.?.paramDefine.?(paramSet, ofx.kOfxParamTypeDouble, "testParameter", &paramProps);
    _ = gPropertySuite.?.propSetString.?(paramProps, ofx.kOfxParamPropDoubleType, 0, ofx.kOfxParamDoubleTypeScale);

    return ofx.kOfxStatOK;
}

fn SetHostFunc(hostStruct: [*c]ofx.OfxHost) callconv(.C) void {
    gHost = hostStruct;
}

fn MainEntryPoint(
    action: [*c]const u8,
    handle: ?*const anyopaque,
    inArgs: ofx.OfxPropertySetHandle,
    outArgs: ofx.OfxPropertySetHandle,
) callconv(.C) ofx.OfxStatus {
    _ = c.fprintf(c.stdout, ": START action is : %s \n", action);
    const effect: ofx.OfxImageEffectHandle = @ptrCast(@constCast(handle));
    var returnStatus: ofx.OfxStatus = ofx.kOfxStatReplyDefault;

    std.debug.print("Entering Action Called: {s}\n", .{action});
    if (c.strcmp(action, ofx.kOfxActionLoad) == 0) {
        returnStatus = LoadAction().?;
    } else if (c.strcmp(action, ofx.kOfxActionUnload) == 0) {
        returnStatus = UnloadAction();
    } else if (c.strcmp(action, ofx.kOfxActionDescribe) == 0) {
        returnStatus = DescribeAction(effect);
    } else if (c.strcmp(action, ofx.kOfxImageEffectActionDescribeInContext) == 0) {
        returnStatus = DescribeInContextAction(effect, inArgs);
    } else if (c.strcmp(action, ofx.kOfxImageEffectActionRender) == 0) {
        returnStatus = RenderAction(effect, inArgs, outArgs);
    } else if (c.strcmp(action, ofx.kOfxActionCreateInstance) == 0) {
        returnStatus = CreateInstanceAction(effect);
    } else if (c.strcmp(action, ofx.kOfxActionDestroyInstance) == 0) {
        returnStatus = DestroyInstanceAction(effect);
    }
    _ = c.fprintf(c.stdout, ": END action is : %s \n", action);
    return returnStatus;
}

var effectPluginStruct: ofx.OfxPlugin = .{
    .pluginApi = ofx.kOfxImageEffectPluginApi,
    .apiVersion = 1,
    .pluginIdentifier = "minimal.reproducible.example",
    .pluginVersionMajor = 1,
    .pluginVersionMinor = 0,
    .setHost = SetHostFunc,
    .mainEntry = MainEntryPoint,
};

export fn OfxGetNumberOfPlugins() i16 {
    return 1;
}

export fn OfxGetPlugin(nth: i16) ?*ofx.OfxPlugin {
    _ = switch (nth) {
        0 => return &effectPluginStruct,
        else => null,
    };

    _ = c.fprintf(c.stdout, "Host tried to get more plugins from binary than were available, called with index %d", nth);
    return @ptrFromInt(0);
}

openfx: https://github.com/AcademySoftwareFoundation/openfx.git git switch tags/OFX_Release_1_4_TAG

0

There are 0 best solutions below