strawberry_x264/
encoder.rs

1use crate::{Data, Encoding, Error, Image, Picture, Result, Setup};
2use core::{mem::MaybeUninit, ptr};
3use core::ffi::c_void;
4use x264::*;
5
6/// Encodes video.
7pub struct Encoder {
8    raw: *mut x264_t,
9    params: x264_param_t,
10}
11
12impl Encoder {
13    /// Creates a new builder with default options.
14    ///
15    /// For more options see `Setup::new`.
16    pub fn builder() -> Setup {
17        Setup::default()
18    }
19
20    #[doc(hidden)]
21    pub unsafe fn from_raw(raw: *mut x264_t) -> Self {
22        let mut params = MaybeUninit::uninit();
23        x264_encoder_parameters(raw, params.as_mut_ptr());
24        let params = params.assume_init();
25        Self { raw, params }
26    }
27
28    /// Feeds a frame to the encoder.
29    ///
30    /// # Panics
31    ///
32    /// Panics if there is a mismatch between the image and the encoder
33    /// regarding width, height or colorspace.
34    pub fn encode(&mut self, pts: i64, image: Image) -> Result<(Data, Picture)> {
35        assert_eq!(image.width(), self.width());
36        assert_eq!(image.height(), self.height());
37        assert_eq!(image.encoding(), self.encoding());
38        unsafe { self.encode_unchecked(pts, image) }
39    }
40    
41    /// Feeds a frame to the encoder relying on a nalu_process callback for further processing
42    /// 
43    /// # Safety
44    /// 
45    /// `context` must be a valid pointer to pass to the callback assigned to `x264_param_t.nalu_process`
46    pub unsafe fn encode_drh(&mut self, image: Image, idr: bool, context: *mut c_void) -> Result<Picture> {
47        let image = image.raw();
48
49        let mut picture = MaybeUninit::uninit();
50        x264_picture_init(picture.as_mut_ptr());
51        let mut picture = picture.assume_init();
52        picture.opaque = context;
53        picture.img = image;
54        
55        if idr {
56            picture.i_type = X264_TYPE_IDR as i32;
57        } else {
58            picture.i_type = X264_TYPE_P as i32;
59        }
60
61        let mut len = 0;
62        let mut stuff = MaybeUninit::uninit();
63        let mut raw = MaybeUninit::uninit();
64
65        let err = x264_encoder_encode(
66            self.raw,
67            stuff.as_mut_ptr(),
68            &mut len,
69            &mut picture,
70            raw.as_mut_ptr(),
71        );
72
73        if err < 0 {
74            Err(Error)
75        } else {
76            let raw = raw.assume_init();
77            let picture = Picture::from_raw(raw);
78            Ok(picture)
79        }
80    }
81
82    /// Feeds a frame to the encoder.
83    ///
84    /// # Unsafety
85    ///
86    /// The caller must ensure that the width, height *and* colorspace
87    /// of the image are the same as that of the encoder.
88    pub unsafe fn encode_unchecked(&mut self, pts: i64, image: Image) -> Result<(Data, Picture)> {
89        let image = image.raw();
90
91        let mut picture = MaybeUninit::uninit();
92        x264_picture_init(picture.as_mut_ptr());
93        let mut picture = picture.assume_init();
94        picture.i_pts = pts;
95        picture.img = image;
96
97        let mut len = 0;
98        let mut stuff = MaybeUninit::uninit();
99        let mut raw = MaybeUninit::uninit();
100
101        let err = x264_encoder_encode(
102            self.raw,
103            stuff.as_mut_ptr(),
104            &mut len,
105            &mut picture,
106            raw.as_mut_ptr(),
107        );
108
109        if err < 0 {
110            Err(Error)
111        } else {
112            let stuff = stuff.assume_init();
113            let raw = raw.assume_init();
114            let data = Data::from_raw_parts(stuff, len as usize);
115            let picture = Picture::from_raw(raw);
116            Ok((data, picture))
117        }
118    }
119
120    /// Gets the video headers, which should be sent first.
121    pub fn headers(&mut self) -> Result<Data> {
122        let mut len = 0;
123        let mut stuff = MaybeUninit::uninit();
124
125        let err = unsafe { x264_encoder_headers(self.raw, stuff.as_mut_ptr(), &mut len) };
126
127        if err < 0 {
128            Err(Error)
129        } else {
130            let stuff = unsafe { stuff.assume_init() };
131            Ok(unsafe { Data::from_raw_parts(stuff, len as usize) })
132        }
133    }
134
135    /// Begins flushing the encoder, to handle any delayed frames.
136    ///
137    /// ```rust
138    /// # use x264::{Colorspace, Setup};
139    /// # let encoder = Setup::default().build(Colorspace::RGB, 1920, 1080).unwrap();
140    /// #
141    /// let mut flush = encoder.flush();
142    ///
143    /// while let Some(result) = flush.next() {
144    ///     if let Ok((data, picture)) = result {
145    ///         // Handle data.
146    ///     }
147    /// }
148    /// ```
149    pub fn flush(self) -> Flush {
150        Flush { encoder: self }
151    }
152
153    /// The width required of any input images.
154    pub fn width(&self) -> i32 {
155        self.params.i_width
156    }
157    /// The height required of any input images.
158    pub fn height(&self) -> i32 {
159        self.params.i_height
160    }
161    /// The encoding required of any input images.
162    pub fn encoding(&self) -> Encoding {
163        unsafe { Encoding::from_raw(self.params.i_csp) }
164    }
165}
166
167impl Drop for Encoder {
168    fn drop(&mut self) {
169        unsafe {
170            x264_encoder_close(self.raw);
171        }
172    }
173}
174
175/// Iterate through any delayed frames.
176pub struct Flush {
177    encoder: Encoder,
178}
179
180impl Flush {
181    /// Keeps flushing.
182    pub fn next(&mut self) -> Option<Result<(Data, Picture)>> {
183        let enc = self.encoder.raw;
184
185        if unsafe { x264_encoder_delayed_frames(enc) } == 0 {
186            return None;
187        }
188
189        let mut len = 0;
190        let mut stuff = MaybeUninit::uninit();
191        let mut raw = MaybeUninit::uninit();
192
193        let err = unsafe {
194            x264_encoder_encode(
195                enc,
196                stuff.as_mut_ptr(),
197                &mut len,
198                ptr::null_mut(),
199                raw.as_mut_ptr(),
200            )
201        };
202
203        Some(if err < 0 {
204            Err(Error)
205        } else {
206            Ok(unsafe {
207                let stuff = stuff.assume_init();
208                let raw = raw.assume_init();
209                (
210                    Data::from_raw_parts(stuff, len as usize),
211                    Picture::from_raw(raw),
212                )
213            })
214        })
215    }
216}