Skip to main content

ffmpeg_next/util/format/
sample.rs

1use std::ffi::{CStr, CString};
2use std::ops::Index;
3use std::ptr;
4use std::slice;
5use std::str::from_utf8_unchecked;
6
7use crate::ffi::AVSampleFormat::*;
8use crate::ffi::*;
9use libc::{c_int, c_void};
10
11#[derive(Eq, PartialEq, Copy, Clone, Debug)]
12pub enum Sample {
13    None,
14
15    U8(Type),
16    I16(Type),
17    I32(Type),
18    I64(Type),
19    F32(Type),
20    F64(Type),
21}
22
23#[derive(Eq, PartialEq, Copy, Clone, Debug)]
24pub enum Type {
25    Packed,
26    Planar,
27}
28
29impl Sample {
30    #[inline]
31    pub fn name(&self) -> &'static str {
32        unsafe {
33            from_utf8_unchecked(CStr::from_ptr(av_get_sample_fmt_name((*self).into())).to_bytes())
34        }
35    }
36
37    #[inline]
38    pub fn packed(&self) -> Self {
39        unsafe { Sample::from(av_get_packed_sample_fmt((*self).into())) }
40    }
41
42    #[inline]
43    pub fn planar(&self) -> Self {
44        unsafe { Sample::from(av_get_planar_sample_fmt((*self).into())) }
45    }
46
47    #[inline]
48    pub fn is_planar(&self) -> bool {
49        unsafe { av_sample_fmt_is_planar((*self).into()) == 1 }
50    }
51
52    #[inline]
53    pub fn is_packed(&self) -> bool {
54        !self.is_planar()
55    }
56
57    #[inline]
58    pub fn bytes(&self) -> usize {
59        unsafe { av_get_bytes_per_sample((*self).into()) as usize }
60    }
61
62    #[inline]
63    pub fn buffer(&self, channels: u16, samples: usize, align: bool) -> Buffer {
64        Buffer::new(*self, channels, samples, align)
65    }
66}
67
68impl From<AVSampleFormat> for Sample {
69    #[inline]
70    fn from(value: AVSampleFormat) -> Self {
71        match value {
72            AV_SAMPLE_FMT_NONE => Sample::None,
73
74            AV_SAMPLE_FMT_U8 => Sample::U8(Type::Packed),
75            AV_SAMPLE_FMT_S16 => Sample::I16(Type::Packed),
76            AV_SAMPLE_FMT_S32 => Sample::I32(Type::Packed),
77            AV_SAMPLE_FMT_S64 => Sample::I64(Type::Packed),
78            AV_SAMPLE_FMT_FLT => Sample::F32(Type::Packed),
79            AV_SAMPLE_FMT_DBL => Sample::F64(Type::Packed),
80
81            AV_SAMPLE_FMT_U8P => Sample::U8(Type::Planar),
82            AV_SAMPLE_FMT_S16P => Sample::I16(Type::Planar),
83            AV_SAMPLE_FMT_S32P => Sample::I32(Type::Planar),
84            AV_SAMPLE_FMT_S64P => Sample::I64(Type::Planar),
85            AV_SAMPLE_FMT_FLTP => Sample::F32(Type::Planar),
86            AV_SAMPLE_FMT_DBLP => Sample::F64(Type::Planar),
87
88            AV_SAMPLE_FMT_NB => Sample::None,
89
90            #[cfg(feature = "non-exhaustive-enums")]
91            _ => unimplemented!(),
92        }
93    }
94}
95
96impl From<&'static str> for Sample {
97    #[inline]
98    fn from(value: &'static str) -> Self {
99        unsafe {
100            let value = CString::new(value).unwrap();
101
102            Sample::from(av_get_sample_fmt(value.as_ptr()))
103        }
104    }
105}
106
107impl From<Sample> for AVSampleFormat {
108    #[inline]
109    fn from(value: Sample) -> AVSampleFormat {
110        match value {
111            Sample::None => AV_SAMPLE_FMT_NONE,
112
113            Sample::U8(Type::Packed) => AV_SAMPLE_FMT_U8,
114            Sample::I16(Type::Packed) => AV_SAMPLE_FMT_S16,
115            Sample::I32(Type::Packed) => AV_SAMPLE_FMT_S32,
116            Sample::I64(Type::Packed) => AV_SAMPLE_FMT_S64,
117            Sample::F32(Type::Packed) => AV_SAMPLE_FMT_FLT,
118            Sample::F64(Type::Packed) => AV_SAMPLE_FMT_DBL,
119
120            Sample::U8(Type::Planar) => AV_SAMPLE_FMT_U8P,
121            Sample::I16(Type::Planar) => AV_SAMPLE_FMT_S16P,
122            Sample::I32(Type::Planar) => AV_SAMPLE_FMT_S32P,
123            Sample::I64(Type::Planar) => AV_SAMPLE_FMT_S64P,
124            Sample::F32(Type::Planar) => AV_SAMPLE_FMT_FLTP,
125            Sample::F64(Type::Planar) => AV_SAMPLE_FMT_DBLP,
126        }
127    }
128}
129
130pub struct Buffer {
131    pub format: Sample,
132    pub channels: u16,
133    pub samples: usize,
134    pub align: bool,
135
136    buffer: *mut *mut u8,
137    size: c_int,
138}
139
140impl Buffer {
141    #[inline]
142    pub fn size(format: Sample, channels: u16, samples: usize, align: bool) -> usize {
143        unsafe {
144            av_samples_get_buffer_size(
145                ptr::null_mut(),
146                i32::from(channels),
147                samples as c_int,
148                format.into(),
149                !align as c_int,
150            ) as usize
151        }
152    }
153
154    #[inline]
155    pub fn new(format: Sample, channels: u16, samples: usize, align: bool) -> Self {
156        unsafe {
157            let mut buf = Buffer {
158                format,
159                channels,
160                samples,
161                align,
162
163                buffer: ptr::null_mut(),
164                size: 0,
165            };
166
167            av_samples_alloc_array_and_samples(
168                &mut buf.buffer,
169                &mut buf.size,
170                i32::from(channels),
171                samples as c_int,
172                format.into(),
173                !align as c_int,
174            );
175
176            buf
177        }
178    }
179}
180
181impl Index<usize> for Buffer {
182    type Output = [u8];
183
184    #[inline]
185    fn index(&self, index: usize) -> &[u8] {
186        if index >= self.samples {
187            panic!("out of bounds");
188        }
189
190        unsafe { slice::from_raw_parts(*self.buffer.add(index), self.size as usize) }
191    }
192}
193
194impl Clone for Buffer {
195    #[inline]
196    fn clone(&self) -> Self {
197        let mut buf = Buffer::new(self.format, self.channels, self.samples, self.align);
198        buf.clone_from(self);
199
200        buf
201    }
202
203    #[inline]
204    fn clone_from(&mut self, source: &Self) {
205        unsafe {
206            av_samples_copy(
207                self.buffer,
208                source.buffer as *const *mut u8,
209                0,
210                0,
211                source.samples as c_int,
212                i32::from(source.channels),
213                source.format.into(),
214            );
215        }
216    }
217}
218
219impl Drop for Buffer {
220    #[inline]
221    fn drop(&mut self) {
222        unsafe {
223            av_freep(self.buffer as *mut c_void);
224        }
225    }
226}