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}