1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use std::{fmt, mem, os::unix::prelude::IntoRawFd};

use glib::{prelude::*, translate::*};
use gst::{Memory, MemoryRef};

use crate::{ffi, DRMDumbAllocator, DmaBufMemory};

gst::memory_object_wrapper!(
    DRMDumbMemory,
    DRMDumbMemoryRef,
    gst::ffi::GstMemory,
    |mem: &gst::MemoryRef| { unsafe { from_glib(ffi::gst_is_drm_dumb_memory(mem.as_mut_ptr())) } },
    Memory,
    MemoryRef
);

impl fmt::Debug for DRMDumbMemory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        DRMDumbMemoryRef::fmt(self, f)
    }
}

impl fmt::Debug for DRMDumbMemoryRef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        MemoryRef::fmt(self, f)
    }
}

impl DRMDumbMemoryRef {
    #[doc(alias = "gst_drm_dumb_memory_get_handle")]
    pub fn fd(&self) -> u32 {
        skip_assert_initialized!();
        unsafe { ffi::gst_drm_dumb_memory_get_handle(self.as_mut_ptr()) }
    }

    #[doc(alias = "gst_drm_dumb_memory_export_dmabuf")]
    pub fn export_dmabuf(&self) -> Result<DmaBufMemory, glib::BoolError> {
        skip_assert_initialized!();
        unsafe {
            Option::<DmaBufMemory>::from_glib_full(ffi::gst_drm_dumb_memory_export_dmabuf(
                self.as_mut_ptr(),
            ))
            .ok_or_else(|| glib::bool_error!("Failed to export as dmabuf"))
        }
    }
}

impl DRMDumbAllocator {
    /// Creates a new [`DRMDumbAllocator`][crate::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.
    /// ## `drm_fd`
    /// file descriptor of the DRM device
    ///
    /// # Returns
    ///
    /// a new DRM Dumb allocator. Use `gst_object_unref()`
    ///  to release the allocator after usage.
    #[doc(alias = "gst_drm_dumb_allocator_new_with_fd")]
    #[doc(alias = "new_with_fd")]
    pub fn with_fd<A: IntoRawFd>(drm_fd: A) -> Result<DRMDumbAllocator, glib::BoolError> {
        assert_initialized_main_thread!();
        unsafe {
            Option::<gst::Allocator>::from_glib_full(ffi::gst_drm_dumb_allocator_new_with_fd(
                drm_fd.into_raw_fd(),
            ))
            .map(|o| o.unsafe_cast())
            .ok_or_else(|| glib::bool_error!("Failed to create allocator"))
        }
    }

    /// 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.
    /// ## `drm_fourcc`
    /// the DRM format to allocate for
    /// ## `width`
    /// padded width for this allocation
    /// ## `height`
    /// padded height for this allocation
    ///
    /// # Returns
    ///
    /// a new DRM Dumb [`gst::Memory`][crate::gst::Memory]. Use `gst_memory_unref()`
    ///  to release the memory after usage.
    ///
    /// ## `out_pitch`
    /// the pitch as returned by the driver
    #[doc(alias = "gst_drm_dumb_allocator_alloc")]
    pub unsafe fn alloc(
        &self,
        drm_fourcc: u32,
        width: u32,
        height: u32,
    ) -> Result<(gst::Memory, u32), glib::BoolError> {
        skip_assert_initialized!();
        let mut out_pitch = mem::MaybeUninit::uninit();
        Option::<_>::from_glib_full(ffi::gst_drm_dumb_allocator_alloc(
            self.to_glib_none().0,
            drm_fourcc,
            width,
            height,
            out_pitch.as_mut_ptr(),
        ))
        .ok_or_else(|| glib::bool_error!("Failed to allocate memory"))
        .map(|mem| (mem, unsafe { out_pitch.assume_init() }))
    }
}