ffmpeg_pipeline/audio/
auto_buffer.rs1use super::*;
2use ffmpeg_next::{
3 codec::Capabilities,
4 filter::{self, Context, Graph},
5};
6
7pub struct AutoAudioBuffer {
13 _graph: Graph,
14 input: Context,
15 output: Context,
16}
17
18impl AutoAudioBuffer {
19 pub fn new<S, D>(src: S, dst: D) -> FFmpegResult<Self>
20 where
21 S: TryInto<AudioSpec, Error = FFmpegError>,
22 D: TryInto<AudioSpec, Error = FFmpegError>,
23 {
24 let src: AudioSpec = src.try_into()?;
25 let dst: AudioSpec = dst.try_into()?;
26
27 let mut graph = Graph::new();
28
29 graph.add(
30 &filter::find("abuffer").unwrap(),
31 "in",
32 &format!(
33 "time_base={}:sample_rate={}:sample_fmt={}:channel_layout=0x{:x}",
34 src.time_base,
35 src.sample_rate,
36 src.format.name(),
37 src.channel_layout.bits()
38 ),
39 )?;
40 graph.add(&filter::find("abuffersink").unwrap(), "out", "")?;
41
42 {
43 let mut out = graph.get("out").unwrap();
44
45 out.set_sample_format(dst.format);
46 out.set_channel_layout(dst.channel_layout);
47 out.set_sample_rate(dst.sample_rate);
48 }
49
50 graph.output("in", 0)?.input("out", 0)?.parse("anull")?;
51 graph.validate()?;
52
53 if let Some(codec) = dst.codec {
54 if !codec
55 .capabilities()
56 .contains(Capabilities::VARIABLE_FRAME_SIZE)
57 {
58 graph
59 .get("out")
60 .unwrap()
61 .sink()
62 .set_frame_size(dst.frame_size);
63 }
64 }
65
66 let input = graph.get("in").unwrap();
67 let output = graph.get("out").unwrap();
68
69 Ok(Self {
70 _graph: graph,
71 input,
72 output,
73 })
74 }
75
76 pub fn add_frame(&mut self, frame: &AudioFrame) -> FFmpegResult {
77 self.input.source().add(frame)?;
78 Ok(())
79 }
80
81 pub fn recv_frames<F>(&mut self, cb: &mut F) -> FFmpegResult
82 where
83 F: FnMut(AudioFrame) -> FFmpegResult,
84 {
85 let mut sink = self.output.sink();
86 let mut filtered = AudioFrame::empty();
87 while sink.frame(&mut filtered).is_ok() {
88 cb(filtered.clone())?;
89 }
90
91 Ok(())
92 }
93
94 pub fn flush(&mut self) -> FFmpegResult {
95 self.input.source().flush()?;
96 Ok(())
97 }
98}