pub const ext = @import("ext.zig");
const gstva = @This();

const std = @import("std");
const compat = @import("compat");
const gstvideo = @import("gstvideo1");
const gstbase = @import("gstbase1");
const gst = @import("gst1");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
/// There are two types of VA allocators:
///
/// * `GstVaAllocator`
/// * `GstVaDmabufAllocator`
pub const VaAllocator = opaque {
    pub const Parent = gst.Allocator;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = VaAllocator;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Allocate a new VASurfaceID backed `gst.Memory`.
    extern fn gst_va_allocator_alloc(p_allocator: *gst.Allocator) *gst.Memory;
    pub const alloc = gst_va_allocator_alloc;

    /// Removes all the memories in `allocator`'s pool.
    extern fn gst_va_allocator_flush(p_allocator: *gst.Allocator) void;
    pub const flush = gst_va_allocator_flush;

    /// Gets current internal configuration of `allocator`.
    extern fn gst_va_allocator_get_format(p_allocator: *gst.Allocator, p_info: ?*gstvideo.VideoInfo, p_usage_hint: ?*c_uint, p_use_derived: ?*c_int) c_int;
    pub const getFormat = gst_va_allocator_get_format;

    extern fn gst_va_allocator_peek_display(p_allocator: *gst.Allocator) *gstva.VaDisplay;
    pub const peekDisplay = gst_va_allocator_peek_display;

    /// This method will populate `buffer` with pooled VASurfaceID
    /// memories. It doesn't allocate new VASurfacesID.
    extern fn gst_va_allocator_prepare_buffer(p_allocator: *gst.Allocator, p_buffer: *gst.Buffer) c_int;
    pub const prepareBuffer = gst_va_allocator_prepare_buffer;

    /// Sets the configuration defined by `info`, `usage_hint` and
    /// `use_derived` for `allocator`, and it tries the configuration, if
    /// `allocator` has not allocated memories yet.
    ///
    /// If `allocator` has memory allocated already, and frame size and
    /// format in `info` are the same as currently configured in `allocator`,
    /// the rest of `info` parameters are updated internally.
    extern fn gst_va_allocator_set_format(p_allocator: *gst.Allocator, p_info: *gstvideo.VideoInfo, p_usage_hint: c_uint, p_feat_use_derived: gstva.VaFeature) c_int;
    pub const setFormat = gst_va_allocator_set_format;

    /// Internal method to set allocator specific logic changes.
    extern fn gst_va_allocator_set_hacks(p_allocator: *gst.Allocator, p_hacks: u32) void;
    pub const setHacks = gst_va_allocator_set_hacks;

    /// Populates an empty `buffer` with a VASuface backed `gst.Memory`.
    extern fn gst_va_allocator_setup_buffer(p_allocator: *gst.Allocator, p_buffer: *gst.Buffer) c_int;
    pub const setupBuffer = gst_va_allocator_setup_buffer;

    /// Instanciate a new pooled `gst.Allocator` backed by VASurfaceID.
    extern fn gst_va_allocator_new(p_display: *gstva.VaDisplay, p_surface_formats: *glib.Array) *gstva.VaAllocator;
    pub const new = gst_va_allocator_new;

    extern fn gst_va_allocator_get_type() usize;
    pub const getGObjectType = gst_va_allocator_get_type;

    extern fn g_object_ref(p_self: *gstva.VaAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaAllocator) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaAllocator, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// It is a generic wrapper for VADisplay. To create new instances
/// subclasses are required, depending on the display type to use
/// (v.gr. DRM, X11, Wayland, etc.).
///
/// The purpose of this class is to be shared among pipelines via
/// `gst.Context` so all the VA processing elements will use the same
/// display entry. Application developers can create their own
/// subclass, based on their display, and shared it via the synced bus
/// message for the application.
pub const VaDisplay = extern struct {
    pub const Parent = gst.Object;
    pub const Implements = [_]type{};
    pub const Class = gstva.VaDisplayClass;
    /// parent `gst.Object`
    f_parent: gst.Object,

    pub const virtual_methods = struct {
        /// This is called when the subclass has to create the internal
        /// VADisplay.
        pub const create_va_display = struct {
            pub fn call(p_class: anytype, p_self: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) ?*anyopaque {
                return gobject.ext.as(VaDisplay.Class, p_class).f_create_va_display.?(gobject.ext.as(VaDisplay, p_self));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_self: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) ?*anyopaque) void {
                gobject.ext.as(VaDisplay.Class, p_class).f_create_va_display = @ptrCast(p_implementation);
            }
        };
    };

    pub const properties = struct {
        pub const description = struct {
            pub const name = "description";

            pub const Type = ?[*:0]u8;
        };

        pub const va_display = struct {
            pub const name = "va-display";

            pub const Type = ?*anyopaque;
        };
    };

    pub const signals = struct {};

    extern fn gst_va_display_check_version(p_self: *VaDisplay, p_major: c_uint, p_minor: c_uint) c_int;
    pub const checkVersion = gst_va_display_check_version;

    /// Get the the `gstva.VaImplementation` type of `self`.
    extern fn gst_va_display_get_implementation(p_self: *VaDisplay) gstva.VaImplementation;
    pub const getImplementation = gst_va_display_get_implementation;

    /// Get the VA display handle of the `self`.
    extern fn gst_va_display_get_va_dpy(p_self: *VaDisplay) ?*anyopaque;
    pub const getVaDpy = gst_va_display_get_va_dpy;

    /// If the display is set by the user (foreign) it is assumed that the
    /// driver is already initialized, thus this function is noop.
    ///
    /// If the display is opened internally, this function will initialize
    /// the driver and it will set driver's message callbacks.
    ///
    /// NOTE: this function is supposed to be private, only used by
    /// GstVaDisplay descendants.
    extern fn gst_va_display_initialize(p_self: *VaDisplay) c_int;
    pub const initialize = gst_va_display_initialize;

    extern fn gst_va_display_get_type() usize;
    pub const getGObjectType = gst_va_display_get_type;

    extern fn g_object_ref(p_self: *gstva.VaDisplay) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaDisplay) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaDisplay, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// This is a `gstva.VaDisplay` subclass to instantiate with DRM devices.
pub const VaDisplayDrm = opaque {
    pub const Parent = gstva.VaDisplay;
    pub const Implements = [_]type{};
    pub const Class = gstva.VaDisplayDrmClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {
        pub const path = struct {
            pub const name = "path";

            pub const Type = ?[*:0]u8;
        };
    };

    pub const signals = struct {};

    /// Creates a new `gstva.VaDisplay` from a DRM device . It will try to open
    /// and operate the device in `path`.
    extern fn gst_va_display_drm_new_from_path(p_path: [*:0]const u8) *gstva.VaDisplayDrm;
    pub const newFromPath = gst_va_display_drm_new_from_path;

    extern fn gst_va_display_drm_get_type() usize;
    pub const getGObjectType = gst_va_display_drm_get_type;

    extern fn g_object_ref(p_self: *gstva.VaDisplayDrm) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaDisplayDrm) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaDisplayDrm, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// This is a `gstva.VaDisplay` instantiaton subclass for custom created
/// VADisplay, such as X11 or Wayland, wrapping it.
pub const VaDisplayWrapped = opaque {
    pub const Parent = gstva.VaDisplay;
    pub const Implements = [_]type{};
    pub const Class = gstva.VaDisplayWrappedClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a `gstva.VaDisplay` wrapping an already created and initialized
    /// VADisplay.
    ///
    /// The lifetime of `handle` must be hold by the provider while the
    /// pipeline is instantiated. Do not call vaTerminate on it while the
    /// pipeline is not in NULL state.
    extern fn gst_va_display_wrapped_new(p_handle: ?*anyopaque) *gstva.VaDisplayWrapped;
    pub const new = gst_va_display_wrapped_new;

    extern fn gst_va_display_wrapped_get_type() usize;
    pub const getGObjectType = gst_va_display_wrapped_get_type;

    extern fn g_object_ref(p_self: *gstva.VaDisplayWrapped) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaDisplayWrapped) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaDisplayWrapped, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// A pooled memory allocator backed by the DMABufs exported from a
/// VASurfaceID. Also it is possible to import DMAbufs into a
/// VASurfaceID.
pub const VaDmabufAllocator = opaque {
    pub const Parent = gst.Allocator;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = VaDmabufAllocator;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Removes all the memories in `allocator`'s pool.
    extern fn gst_va_dmabuf_allocator_flush(p_allocator: *gst.Allocator) void;
    pub const flush = gst_va_dmabuf_allocator_flush;

    /// Gets current internal configuration of `allocator`.
    extern fn gst_va_dmabuf_allocator_get_format(p_allocator: *gst.Allocator, p_info: ?*gstvideo.VideoInfoDmaDrm, p_usage_hint: ?*c_uint) c_int;
    pub const getFormat = gst_va_dmabuf_allocator_get_format;

    /// This method will populate `buffer` with pooled VASurfaceID/DMABuf
    /// memories. It doesn't allocate new VASurfacesID.
    extern fn gst_va_dmabuf_allocator_prepare_buffer(p_allocator: *gst.Allocator, p_buffer: *gst.Buffer) c_int;
    pub const prepareBuffer = gst_va_dmabuf_allocator_prepare_buffer;

    /// Sets the configuration defined by `info` and `usage_hint` for
    /// `allocator`, and it tries the configuration, if `allocator` has not
    /// allocated memories yet.
    ///
    /// If `allocator` has memory allocated already, and frame size, format
    /// and modifier in `info` are the same as currently configured in
    /// `allocator`, the rest of `info` parameters are updated internally.
    extern fn gst_va_dmabuf_allocator_set_format(p_allocator: *gst.Allocator, p_info: *gstvideo.VideoInfoDmaDrm, p_usage_hint: c_uint) c_int;
    pub const setFormat = gst_va_dmabuf_allocator_set_format;

    /// This function creates a new VASurfaceID and exposes its DMABufs,
    /// later it populates the `buffer` with those DMABufs.
    extern fn gst_va_dmabuf_allocator_setup_buffer(p_allocator: *gst.Allocator, p_buffer: *gst.Buffer) c_int;
    pub const setupBuffer = gst_va_dmabuf_allocator_setup_buffer;

    /// Instanciate a new pooled allocator backed with both DMABuf and
    /// VASurfaceID.
    extern fn gst_va_dmabuf_allocator_new(p_display: *gstva.VaDisplay) *gstva.VaDmabufAllocator;
    pub const new = gst_va_dmabuf_allocator_new;

    extern fn gst_va_dmabuf_allocator_get_type() usize;
    pub const getGObjectType = gst_va_dmabuf_allocator_get_type;

    extern fn g_object_ref(p_self: *gstva.VaDmabufAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaDmabufAllocator) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaDmabufAllocator, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `GstVaPool` is a buffer pool for VA allocators.
pub const VaPool = opaque {
    pub const Parent = gst.BufferPool;
    pub const Implements = [_]type{};
    pub const Class = opaque {
        pub const Instance = VaPool;
    };
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Helper function to retrieve the VA surface size provided by `pool`.
    extern fn gst_va_pool_get_buffer_size(p_pool: *gst.BufferPool, p_size: ?*c_uint) c_int;
    pub const getBufferSize = gst_va_pool_get_buffer_size;

    /// Retuns: `TRUE` if `pool` always add `gstvideo.VideoMeta` to its
    ///     buffers. Otherwise, `FALSE`.
    extern fn gst_va_pool_requires_video_meta(p_pool: *gst.BufferPool) c_int;
    pub const requiresVideoMeta = gst_va_pool_requires_video_meta;

    extern fn gst_va_pool_new() *gstva.VaPool;
    pub const new = gst_va_pool_new;

    extern fn gst_va_pool_new_with_config(p_caps: *gst.Caps, p_min_buffers: c_uint, p_max_buffers: c_uint, p_usage_hint: c_uint, p_use_derived: gstva.VaFeature, p_allocator: *gst.Allocator, p_alloc_params: *gst.AllocationParams) *gstva.VaPool;
    pub const newWithConfig = gst_va_pool_new_with_config;

    extern fn gst_va_pool_get_type() usize;
    pub const getGObjectType = gst_va_pool_get_type;

    extern fn g_object_ref(p_self: *gstva.VaPool) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstva.VaPool) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *VaPool, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// The common VA display object class structure.
pub const VaDisplayClass = extern struct {
    pub const Instance = gstva.VaDisplay;

    /// parent `gst.ObjectClass`
    f_parent_class: gst.ObjectClass,
    f_create_va_display: ?*const fn (p_self: *gstva.VaDisplay) callconv(.c) ?*anyopaque,

    pub fn as(p_instance: *VaDisplayClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const VaDisplayDrmClass = opaque {
    pub const Instance = gstva.VaDisplayDrm;

    pub fn as(p_instance: *VaDisplayDrmClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const VaDisplayWrappedClass = opaque {
    pub const Instance = gstva.VaDisplayWrapped;

    pub fn as(p_instance: *VaDisplayWrappedClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const VaFeature = enum(c_int) {
    disabled = 0,
    enabled = 1,
    auto = 2,
    _,

    extern fn gst_va_feature_get_type() usize;
    pub const getGObjectType = gst_va_feature_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Types of different VA API implemented drivers. These are the typical and
/// the most widely used VA drivers.
pub const VaImplementation = enum(c_int) {
    mesa_gallium = 0,
    intel_i965 = 1,
    intel_ihd = 2,
    other = 3,
    invalid = 4,
    _,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Video alignment is not handled as expected by VA since it uses
/// opaque surfaces, not directly mappable memory. Still, decoders
/// might need to request bigger surfaces for coded size rather than
/// display sizes. This method will set the coded size to bufferpool's
/// configuration, out of the typical video aligment.
extern fn gst_buffer_pool_config_set_va_alignment(p_config: *gst.Structure, p_align: *const gstvideo.VideoAlignment) void;
pub const bufferPoolConfigSetVaAlignment = gst_buffer_pool_config_set_va_alignment;

/// Sets the usage hint for the buffers handled by the buffer pool.
extern fn gst_buffer_pool_config_set_va_allocation_params(p_config: *gst.Structure, p_usage_hint: c_uint, p_use_derived: gstva.VaFeature) void;
pub const bufferPoolConfigSetVaAllocationParams = gst_buffer_pool_config_set_va_allocation_params;

extern fn gst_context_get_va_display(p_context: *gst.Context, p_type_name: [*:0]const u8, p_render_device_path: [*:0]const u8, p_display_ptr: **gstva.VaDisplay) c_int;
pub const contextGetVaDisplay = gst_context_get_va_display;

/// Set the `display` in the `context`
extern fn gst_context_set_va_display(p_context: *gst.Context, p_display: *gstva.VaDisplay) void;
pub const contextSetVaDisplay = gst_context_set_va_display;

/// Creates a new VASurfaceID with `buffer`'s allocator and attached it
/// to it.
///
/// *This method is used only by plugin's internal VA decoder.*
extern fn gst_va_buffer_create_aux_surface(p_buffer: *gst.Buffer) c_int;
pub const vaBufferCreateAuxSurface = gst_va_buffer_create_aux_surface;

extern fn gst_va_buffer_get_aux_surface(p_buffer: *gst.Buffer) c_uint;
pub const vaBufferGetAuxSurface = gst_va_buffer_get_aux_surface;

extern fn gst_va_buffer_get_surface(p_buffer: *gst.Buffer) c_uint;
pub const vaBufferGetSurface = gst_va_buffer_get_surface;

extern fn gst_va_buffer_peek_display(p_buffer: *gst.Buffer) *gstva.VaDisplay;
pub const vaBufferPeekDisplay = gst_va_buffer_peek_display;

/// Query the specified context type name.
extern fn gst_va_context_query(p_element: *gst.Element, p_context_type: [*:0]const u8) void;
pub const vaContextQuery = gst_va_context_query;

/// Get the underlying modifier for specified `format` and `usage_hint`.
extern fn gst_va_dmabuf_get_modifier_for_format(p_display: *gstva.VaDisplay, p_format: gstvideo.VideoFormat, p_usage_hint: c_uint) u64;
pub const vaDmabufGetModifierForFormat = gst_va_dmabuf_get_modifier_for_format;

/// It imports the array of `mem`, representing a single frame, into a
/// VASurfaceID and it's attached into every `mem`.
extern fn gst_va_dmabuf_memories_setup(p_display: *gstva.VaDisplay, p_drm_info: *gstvideo.VideoInfoDmaDrm, p_mem: *[4]*gst.Memory, p_fds: *[4]usize, p_offset: *[4]usize, p_usage_hint: c_uint) c_int;
pub const vaDmabufMemoriesSetup = gst_va_dmabuf_memories_setup;

/// Propagate `display` by posting it as `gst.Context` in the pipeline's bus.
extern fn gst_va_element_propagate_display_context(p_element: *gst.Element, p_display: *gstva.VaDisplay) void;
pub const vaElementPropagateDisplayContext = gst_va_element_propagate_display_context;

/// Called by the va element to ensure a valid `gstva.VaDisplay`.
extern fn gst_va_ensure_element_data(p_element: ?*anyopaque, p_render_device_path: [*:0]const u8, p_display_ptr: **gstva.VaDisplay) c_int;
pub const vaEnsureElementData = gst_va_ensure_element_data;

/// Used by elements when processing their pad's queries, propagating
/// element's `gstva.VaDisplay` if the processed query requests it.
extern fn gst_va_handle_context_query(p_element: *gst.Element, p_query: *gst.Query, p_display: *gstva.VaDisplay) c_int;
pub const vaHandleContextQuery = gst_va_handle_context_query;

/// Called by elements in their `gst.ElementClass.signals.set_context` vmethod.
/// It gets a valid `gstva.VaDisplay` if `context` has it.
extern fn gst_va_handle_set_context(p_element: *gst.Element, p_context: *gst.Context, p_render_device_path: [*:0]const u8, p_display_ptr: **gstva.VaDisplay) c_int;
pub const vaHandleSetContext = gst_va_handle_set_context;

extern fn gst_va_memory_get_surface(p_mem: *gst.Memory) c_uint;
pub const vaMemoryGetSurface = gst_va_memory_get_surface;

extern fn gst_va_memory_peek_display(p_mem: *gst.Memory) *gstva.VaDisplay;
pub const vaMemoryPeekDisplay = gst_va_memory_peek_display;

pub const ALLOCATOR_VASURFACE = "VAMemory";
pub const CAPS_FEATURE_MEMORY_VA = "memory:VAMemory";
/// Flag indicating that we should map the VASurfaceID instead of to
/// system memory, so users can use libva primitives to operate with
/// that surface.
pub const MAP_VA = 131072;
pub const VA_DISPLAY_HANDLE_CONTEXT_TYPE_STR = "gst.va.display.handle";

test {
    @setEvalBranchQuota(100_000);
    std.testing.refAllDecls(@This());
    std.testing.refAllDecls(ext);
}
