playa_ffmpeg/util/format/
sample.rs

1use std::{
2    ffi::{CStr, CString},
3    ops::Index,
4    ptr, slice,
5    str::from_utf8_unchecked,
6};
7
8use crate::ffi::{AVSampleFormat::*, *};
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 { from_utf8_unchecked(CStr::from_ptr(av_get_sample_fmt_name((*self).into())).to_bytes()) }
33    }
34
35    #[inline]
36    pub fn packed(&self) -> Self {
37        unsafe { Sample::from(av_get_packed_sample_fmt((*self).into())) }
38    }
39
40    #[inline]
41    pub fn planar(&self) -> Self {
42        unsafe { Sample::from(av_get_planar_sample_fmt((*self).into())) }
43    }
44
45    #[inline]
46    pub fn is_planar(&self) -> bool {
47        unsafe { av_sample_fmt_is_planar((*self).into()) == 1 }
48    }
49
50    #[inline]
51    pub fn is_packed(&self) -> bool {
52        !self.is_planar()
53    }
54
55    #[inline]
56    pub fn bytes(&self) -> usize {
57        unsafe { av_get_bytes_per_sample((*self).into()) as usize }
58    }
59
60    #[inline]
61    pub fn buffer(&self, channels: u16, samples: usize, align: bool) -> Buffer {
62        Buffer::new(*self, channels, samples, align)
63    }
64}
65
66impl From<AVSampleFormat> for Sample {
67    #[inline]
68    fn from(value: AVSampleFormat) -> Self {
69        match value {
70            AV_SAMPLE_FMT_NONE => Sample::None,
71
72            AV_SAMPLE_FMT_U8 => Sample::U8(Type::Packed),
73            AV_SAMPLE_FMT_S16 => Sample::I16(Type::Packed),
74            AV_SAMPLE_FMT_S32 => Sample::I32(Type::Packed),
75            AV_SAMPLE_FMT_S64 => Sample::I64(Type::Packed),
76            AV_SAMPLE_FMT_FLT => Sample::F32(Type::Packed),
77            AV_SAMPLE_FMT_DBL => Sample::F64(Type::Packed),
78
79            AV_SAMPLE_FMT_U8P => Sample::U8(Type::Planar),
80            AV_SAMPLE_FMT_S16P => Sample::I16(Type::Planar),
81            AV_SAMPLE_FMT_S32P => Sample::I32(Type::Planar),
82            AV_SAMPLE_FMT_S64P => Sample::I64(Type::Planar),
83            AV_SAMPLE_FMT_FLTP => Sample::F32(Type::Planar),
84            AV_SAMPLE_FMT_DBLP => Sample::F64(Type::Planar),
85
86            AV_SAMPLE_FMT_NB => Sample::None,
87        }
88    }
89}
90
91impl From<&'static str> for Sample {
92    #[inline]
93    fn from(value: &'static str) -> Self {
94        unsafe {
95            let value = CString::new(value).unwrap();
96
97            Sample::from(av_get_sample_fmt(value.as_ptr()))
98        }
99    }
100}
101
102impl From<Sample> for AVSampleFormat {
103    #[inline]
104    fn from(value: Sample) -> AVSampleFormat {
105        match value {
106            Sample::None => AV_SAMPLE_FMT_NONE,
107
108            Sample::U8(Type::Packed) => AV_SAMPLE_FMT_U8,
109            Sample::I16(Type::Packed) => AV_SAMPLE_FMT_S16,
110            Sample::I32(Type::Packed) => AV_SAMPLE_FMT_S32,
111            Sample::I64(Type::Packed) => AV_SAMPLE_FMT_S64,
112            Sample::F32(Type::Packed) => AV_SAMPLE_FMT_FLT,
113            Sample::F64(Type::Packed) => AV_SAMPLE_FMT_DBL,
114
115            Sample::U8(Type::Planar) => AV_SAMPLE_FMT_U8P,
116            Sample::I16(Type::Planar) => AV_SAMPLE_FMT_S16P,
117            Sample::I32(Type::Planar) => AV_SAMPLE_FMT_S32P,
118            Sample::I64(Type::Planar) => AV_SAMPLE_FMT_S64P,
119            Sample::F32(Type::Planar) => AV_SAMPLE_FMT_FLTP,
120            Sample::F64(Type::Planar) => AV_SAMPLE_FMT_DBLP,
121        }
122    }
123}
124
125pub struct Buffer {
126    pub format: Sample,
127    pub channels: u16,
128    pub samples: usize,
129    pub align: bool,
130
131    buffer: *mut *mut u8,
132    size: c_int,
133}
134
135impl Buffer {
136    #[inline]
137    pub fn size(format: Sample, channels: u16, samples: usize, align: bool) -> usize {
138        unsafe { av_samples_get_buffer_size(ptr::null_mut(), i32::from(channels), samples as c_int, format.into(), !align as c_int) as usize }
139    }
140
141    #[inline]
142    pub fn new(format: Sample, channels: u16, samples: usize, align: bool) -> Self {
143        unsafe {
144            let mut buf = Buffer { format, channels, samples, align, buffer: ptr::null_mut(), size: 0 };
145
146            av_samples_alloc_array_and_samples(&mut buf.buffer, &mut buf.size, i32::from(channels), samples as c_int, format.into(), !align as c_int);
147
148            buf
149        }
150    }
151}
152
153impl Index<usize> for Buffer {
154    type Output = [u8];
155
156    #[inline]
157    fn index(&self, index: usize) -> &[u8] {
158        if index >= self.samples {
159            panic!("out of bounds");
160        }
161
162        unsafe { slice::from_raw_parts(*self.buffer.add(index), self.size as usize) }
163    }
164}
165
166impl Clone for Buffer {
167    #[inline]
168    fn clone(&self) -> Self {
169        let mut buf = Buffer::new(self.format, self.channels, self.samples, self.align);
170        buf.clone_from(self);
171
172        buf
173    }
174
175    #[inline]
176    fn clone_from(&mut self, source: &Self) {
177        unsafe {
178            av_samples_copy(self.buffer, source.buffer as *const *mut u8, 0, 0, source.samples as c_int, i32::from(source.channels), source.format.into());
179        }
180    }
181}
182
183impl Drop for Buffer {
184    #[inline]
185    fn drop(&mut self) {
186        unsafe {
187            av_freep(self.buffer as *mut c_void);
188        }
189    }
190}