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

const std = @import("std");
const compat = @import("compat");
const gst = @import("gst1");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
/// Private intance object for `gstallocators.DRMDumbAllocator`.
pub const DRMDumbAllocator = opaque {
    pub const Parent = gst.Allocator;
    pub const Implements = [_]type{};
    pub const Class = gstallocators.DRMDumbAllocatorClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {
        pub const drm_device_path = struct {
            pub const name = "drm-device-path";

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

        pub const drm_fd = struct {
            pub const name = "drm-fd";

            pub const Type = c_int;
        };
    };

    pub const signals = struct {};

    /// Creates a new `gstallocators.DRMDumbAllocator` for the specific device path. This
    /// function can fail if the path does not exist, is not a DRM device or if
    /// the DRM device doesnot support DUMB allocation.
    extern fn gst_drm_dumb_allocator_new_with_device_path(p_drm_device_path: [*:0]const u8) ?*gstallocators.DRMDumbAllocator;
    pub const newWithDevicePath = gst_drm_dumb_allocator_new_with_device_path;

    /// Creates a new `gstallocators.DRMDumbAllocator` for the specific file desciptor. This
    /// function can fail if the file descriptor is not a DRM device or if
    /// the DRM device does not support DUMB allocation.
    extern fn gst_drm_dumb_allocator_new_with_fd(p_drm_fd: c_int) ?*gstallocators.DRMDumbAllocator;
    pub const newWithFd = gst_drm_dumb_allocator_new_with_fd;

    /// Allocated a DRM buffer object for the specific `drm_fourcc`, `width` and
    /// `height`. Note that the DRM Dumb allocation interface is agnostic to the
    /// pixel format. This `drm_fourcc` is converted into a bpp (bit-per-pixel)
    /// number and the height is scaled according to the sub-sampling.
    extern fn gst_drm_dumb_allocator_alloc(p_allocator: *DRMDumbAllocator, p_drm_fourcc: u32, p_width: u32, p_height: u32, p_out_pitch: *u32) *gst.Memory;
    pub const alloc = gst_drm_dumb_allocator_alloc;

    /// This function allow verifying if the driver support dma-buf exportation.
    extern fn gst_drm_dumb_allocator_has_prime_export(p_allocator: *DRMDumbAllocator) c_int;
    pub const hasPrimeExport = gst_drm_dumb_allocator_has_prime_export;

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

    extern fn g_object_ref(p_self: *gstallocators.DRMDumbAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstallocators.DRMDumbAllocator) void;
    pub const unref = g_object_unref;

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

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

/// Base class for allocators with dmabuf-backed memory
pub const DmaBufAllocator = extern struct {
    pub const Parent = gstallocators.FdAllocator;
    pub const Implements = [_]type{};
    pub const Class = gstallocators.DmaBufAllocatorClass;
    f_parent: gstallocators.FdAllocator,
    f__gst_reserved: [4]*anyopaque,

    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Return a `gst.Memory` that wraps a dmabuf file descriptor.
    extern fn gst_dmabuf_allocator_alloc(p_allocator: *gst.Allocator, p_fd: c_int, p_size: usize) ?*gst.Memory;
    pub const alloc = gst_dmabuf_allocator_alloc;

    /// Return a `gst.Memory` that wraps a dmabuf file descriptor.
    extern fn gst_dmabuf_allocator_alloc_with_flags(p_allocator: *gst.Allocator, p_fd: c_int, p_size: usize, p_flags: gstallocators.FdMemoryFlags) ?*gst.Memory;
    pub const allocWithFlags = gst_dmabuf_allocator_alloc_with_flags;

    /// Return a new dmabuf allocator.
    extern fn gst_dmabuf_allocator_new() *gstallocators.DmaBufAllocator;
    pub const new = gst_dmabuf_allocator_new;

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

    extern fn g_object_ref(p_self: *gstallocators.DmaBufAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstallocators.DmaBufAllocator) void;
    pub const unref = g_object_unref;

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

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

/// Base class for allocators with fd-backed memory
pub const FdAllocator = extern struct {
    pub const Parent = gst.Allocator;
    pub const Implements = [_]type{};
    pub const Class = gstallocators.FdAllocatorClass;
    f_parent: gst.Allocator,

    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Return a `gst.Memory` that wraps a generic file descriptor.
    extern fn gst_fd_allocator_alloc(p_allocator: *gst.Allocator, p_fd: c_int, p_size: usize, p_flags: gstallocators.FdMemoryFlags) ?*gst.Memory;
    pub const alloc = gst_fd_allocator_alloc;

    /// Return a new fd allocator.
    extern fn gst_fd_allocator_new() *gstallocators.FdAllocator;
    pub const new = gst_fd_allocator_new;

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

    extern fn g_object_ref(p_self: *gstallocators.FdAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstallocators.FdAllocator) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *FdAllocator, 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 subclass of `gstallocators.FdAllocator` that implements the
/// `gst.Allocator.alloc` method using ``memfd_create`` when available, POSIX
/// ``shm_open`` otherwise. Platforms not supporting any of those (Windows) will
/// always return `NULL`.
///
/// Note that allocating new shared memories has a significant performance cost,
/// it is thus recommended to keep a pool of pre-allocated `gst.Memory`, using
/// `gst.BufferPool`. For that reason, this allocator has the
/// `GST_ALLOCATOR_FLAG_NO_COPY` flag set.
pub const ShmAllocator = opaque {
    pub const Parent = gstallocators.FdAllocator;
    pub const Implements = [_]type{};
    pub const Class = gstallocators.ShmAllocatorClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Get the `gstallocators.ShmAllocator` singleton previously registered with
    /// `gstallocators.ShmAllocator.initOnce`.
    extern fn gst_shm_allocator_get() ?*gst.Allocator;
    pub const get = gst_shm_allocator_get;

    /// Register a `gstallocators.ShmAllocator` using `gst.Allocator.register` with the name
    /// `GST_ALLOCATOR_SHM`. This is no-op after the first call.
    extern fn gst_shm_allocator_init_once() void;
    pub const initOnce = gst_shm_allocator_init_once;

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

    extern fn g_object_ref(p_self: *gstallocators.ShmAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstallocators.ShmAllocator) void;
    pub const unref = g_object_unref;

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

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

pub const PhysMemoryAllocator = opaque {
    pub const Prerequisites = [_]type{gst.Allocator};
    pub const Iface = gstallocators.PhysMemoryAllocatorInterface;
    pub const virtual_methods = struct {
        /// Implementations shall return the physicall memory address
        ///    that is backing the provided memory, or 0 if none.
        pub const get_phys_addr = struct {
            pub fn call(p_class: anytype, p_allocator: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mem: *gst.Memory) usize {
                return gobject.ext.as(PhysMemoryAllocator.Iface, p_class).f_get_phys_addr.?(gobject.ext.as(PhysMemoryAllocator, p_allocator), p_mem);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_allocator: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mem: *gst.Memory) callconv(.c) usize) void {
                gobject.ext.as(PhysMemoryAllocator.Iface, p_class).f_get_phys_addr = @ptrCast(p_implementation);
            }
        };
    };

    pub const properties = struct {};

    pub const signals = struct {};

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

    extern fn g_object_ref(p_self: *gstallocators.PhysMemoryAllocator) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstallocators.PhysMemoryAllocator) void;
    pub const unref = g_object_unref;

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

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

pub const DRMDumbAllocatorClass = extern struct {
    pub const Instance = gstallocators.DRMDumbAllocator;

    /// Parent Class.
    f_parent_class: gst.AllocatorClass,

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

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

pub const DmaBufAllocatorClass = extern struct {
    pub const Instance = gstallocators.DmaBufAllocator;

    f_parent_class: gstallocators.FdAllocatorClass,
    f__gst_reserved: [4]*anyopaque,

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

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

pub const FdAllocatorClass = extern struct {
    pub const Instance = gstallocators.FdAllocator;

    f_parent_class: gst.AllocatorClass,

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

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

/// Marker interface for allocators with physical address backed memory
pub const PhysMemoryAllocatorInterface = extern struct {
    pub const Instance = gstallocators.PhysMemoryAllocator;

    f_parent_iface: gobject.TypeInterface,
    /// Implementations shall return the physicall memory address
    ///    that is backing the provided memory, or 0 if none.
    f_get_phys_addr: ?*const fn (p_allocator: *gstallocators.PhysMemoryAllocator, p_mem: *gst.Memory) callconv(.c) usize,

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

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

pub const ShmAllocatorClass = extern struct {
    pub const Instance = gstallocators.ShmAllocator;

    /// Parent Class.
    f_parent_class: gstallocators.FdAllocatorClass,

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

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

/// Various flags to control the operation of the fd backed memory.
pub const FdMemoryFlags = packed struct(c_uint) {
    keep_mapped: bool = false,
    map_private: bool = false,
    dont_close: bool = false,
    _padding3: bool = false,
    _padding4: bool = false,
    _padding5: bool = false,
    _padding6: bool = false,
    _padding7: bool = false,
    _padding8: bool = false,
    _padding9: bool = false,
    _padding10: bool = false,
    _padding11: bool = false,
    _padding12: bool = false,
    _padding13: bool = false,
    _padding14: bool = false,
    _padding15: bool = false,
    _padding16: bool = false,
    _padding17: bool = false,
    _padding18: bool = false,
    _padding19: bool = false,
    _padding20: bool = false,
    _padding21: bool = false,
    _padding22: bool = false,
    _padding23: bool = false,
    _padding24: bool = false,
    _padding25: bool = false,
    _padding26: bool = false,
    _padding27: bool = false,
    _padding28: bool = false,
    _padding29: bool = false,
    _padding30: bool = false,
    _padding31: bool = false,

    pub const flags_none: FdMemoryFlags = @bitCast(@as(c_uint, 0));
    pub const flags_keep_mapped: FdMemoryFlags = @bitCast(@as(c_uint, 1));
    pub const flags_map_private: FdMemoryFlags = @bitCast(@as(c_uint, 2));
    pub const flags_dont_close: FdMemoryFlags = @bitCast(@as(c_uint, 4));

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

/// Return the file descriptor associated with `mem`.
extern fn gst_dmabuf_memory_get_fd(p_mem: *gst.Memory) c_int;
pub const dmabufMemoryGetFd = gst_dmabuf_memory_get_fd;

/// Exports a DMABuf from the DRM Bumb buffer object. One can check if this
/// feature is supported using `gstallocators.DRMDumbAllocator.hasPrimeExport`;
extern fn gst_drm_dumb_memory_export_dmabuf(p_mem: *gst.Memory) *gst.Memory;
pub const drmDumbMemoryExportDmabuf = gst_drm_dumb_memory_export_dmabuf;

/// Return the DRM buffer object handle associated with `mem`.
extern fn gst_drm_dumb_memory_get_handle(p_mem: *gst.Memory) u32;
pub const drmDumbMemoryGetHandle = gst_drm_dumb_memory_get_handle;

/// Get the fd from `mem`. Call `gstallocators.isFdMemory` to check if `mem` has
/// an fd.
extern fn gst_fd_memory_get_fd(p_mem: *gst.Memory) c_int;
pub const fdMemoryGetFd = gst_fd_memory_get_fd;

/// Check if `mem` is dmabuf memory.
extern fn gst_is_dmabuf_memory(p_mem: *gst.Memory) c_int;
pub const isDmabufMemory = gst_is_dmabuf_memory;

extern fn gst_is_drm_dumb_memory(p_mem: *gst.Memory) c_int;
pub const isDrmDumbMemory = gst_is_drm_dumb_memory;

/// Check if `mem` is memory backed by an fd
extern fn gst_is_fd_memory(p_mem: *gst.Memory) c_int;
pub const isFdMemory = gst_is_fd_memory;

extern fn gst_is_phys_memory(p_mem: *gst.Memory) c_int;
pub const isPhysMemory = gst_is_phys_memory;

extern fn gst_phys_memory_get_phys_addr(p_mem: *gst.Memory) usize;
pub const physMemoryGetPhysAddr = gst_phys_memory_get_phys_addr;

pub const ALLOCATOR_DMABUF = "dmabuf";
pub const ALLOCATOR_FD = "fd";
/// Name of this allocator, to be used for example with `gst.Allocator.find` and
/// `gst.Memory.isType`.
pub const ALLOCATOR_SHM = "shm";
/// Constant that defines the caps feature name for DMA buffer sharing.
///
/// It has to be used for non-mappable dma-buf only, i.e. when the underlying
/// memory is not mappable to user space. Or when the mapped memory contains
/// non meaningful data. It can be the case for protected content or when the
/// user wants explicitly avoid any software post processing.
///
/// In these cases all elements between the exported and the importer has to work
/// in passthrough mode. This is done by adding this caps feature.
///
/// When the memory is mappable for read and write requests then it is assumes
/// to be a fast path and so this caps feature should not be used. Though
/// according to the dma-buf protocol, while it is mapped it prevents the
/// exporter to migrate the buffer.
///
/// This caps feature should not serve at all the purpose of selecting the
/// `GST_ALLOCATOR_DMABUF` allocator during caps negotiation.
/// When the exporter is the upstream element from the importer point of view,
/// the exporter should try to map the dma buffer at runtime (preferably during
/// decide_allocation phase). When it succeeds for `GST_MAP_READWRITE` this caps
/// feature should not be used. This allows scalers, color converts and any image
/// processing filters to work directly on the dma buffer.
/// In this case the importer element should check all incoming memory using
/// `gstallocators.isDmabufMemory`.
pub const CAPS_FEATURE_MEMORY_DMABUF = "memory:DMABuf";

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