playa_ffmpeg/software/resampling/
context.rs1use std::ptr;
2
3use super::Delay;
4use crate::{ChannelLayout, Dictionary, Error, ffi::*, frame, util::format};
5use libc::c_int;
6use std::ffi::c_void;
7
8#[derive(Eq, PartialEq, Copy, Clone)]
9pub struct Definition {
10 pub format: format::Sample,
11 pub channel_layout: ChannelLayout,
12 pub rate: u32,
13}
14
15pub struct Context {
16 ptr: *mut SwrContext,
17
18 input: Definition,
19 output: Definition,
20}
21
22unsafe impl Send for Context {}
23
24impl Context {
25 #[doc(hidden)]
26 pub unsafe fn as_ptr(&self) -> *const SwrContext {
27 self.ptr as *const _
28 }
29
30 #[doc(hidden)]
31 pub unsafe fn as_mut_ptr(&mut self) -> *mut SwrContext {
32 self.ptr
33 }
34}
35
36impl Context {
37 pub fn get(src_format: format::Sample, src_channel_layout: ChannelLayout, src_rate: u32, dst_format: format::Sample, dst_channel_layout: ChannelLayout, dst_rate: u32) -> Result<Self, Error> {
39 Self::get_with(src_format, src_channel_layout, src_rate, dst_format, dst_channel_layout, dst_rate, Dictionary::new())
40 }
41
42 pub fn get_with(src_format: format::Sample, src_channel_layout: ChannelLayout, src_rate: u32, dst_format: format::Sample, dst_channel_layout: ChannelLayout, dst_rate: u32, options: Dictionary) -> Result<Self, Error> {
44 unsafe {
45 #[allow(unused_assignments)]
46 let mut ptr = std::ptr::null_mut();
47
48 #[cfg(not(feature = "ffmpeg_7_0"))]
49 {
50 ptr = swr_alloc_set_opts(ptr::null_mut(), dst_channel_layout.bits() as i64, dst_format.into(), dst_rate as c_int, src_channel_layout.bits() as i64, src_format.into(), src_rate as c_int, 0, ptr::null_mut());
51 }
52 #[cfg(feature = "ffmpeg_7_0")]
53 {
54 let e = swr_alloc_set_opts2(&mut ptr, &dst_channel_layout.into(), dst_format.into(), dst_rate as c_int, &src_channel_layout.into(), src_format.into(), src_rate as c_int, 0, ptr::null_mut());
55 if e != 0 {
56 return Err(Error::from(e));
57 }
58 }
59
60 let mut opts = options.disown();
61 let res = av_opt_set_dict(ptr as *mut c_void, &mut opts);
62 Dictionary::own(opts);
63
64 if res != 0 {
65 return Err(Error::from(res));
66 }
67
68 if !ptr.is_null() {
69 match swr_init(ptr) {
70 e if e < 0 => Err(Error::from(e)),
71
72 _ => Ok(Context { ptr, input: Definition { format: src_format, channel_layout: src_channel_layout, rate: src_rate }, output: Definition { format: dst_format, channel_layout: dst_channel_layout, rate: dst_rate } }),
73 }
74 } else {
75 Err(Error::InvalidData)
76 }
77 }
78 }
79
80 pub fn input(&self) -> &Definition {
82 &self.input
83 }
84
85 pub fn output(&self) -> &Definition {
87 &self.output
88 }
89
90 pub fn delay(&self) -> Option<Delay> {
92 unsafe {
93 match swr_get_delay(self.as_ptr() as *mut _, 1) {
94 0 => None,
95 _ => Some(Delay::from(self)),
96 }
97 }
98 }
99
100 pub fn run(&mut self, input: &frame::Audio, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
104 unsafe {
105 (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
106 }
107
108 unsafe {
109 if output.is_empty() {
110 output.alloc(self.output.format, input.samples(), self.output.channel_layout);
111 }
112
113 match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) {
114 0 => Ok(self.delay()),
115
116 e => Err(Error::from(e)),
117 }
118 }
119 }
120
121 pub fn flush(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
125 unsafe {
126 (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
127 }
128
129 unsafe {
130 match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) {
131 0 => Ok(self.delay()),
132
133 e => Err(Error::from(e)),
134 }
135 }
136 }
137}
138
139impl Drop for Context {
140 fn drop(&mut self) {
141 unsafe {
142 swr_free(&mut self.as_mut_ptr());
143 }
144 }
145}