Skip to main content

ffmpeg_pipeline/audio/
auto_buffer.rs

1use super::*;
2use ffmpeg_next::{
3    codec::Capabilities,
4    filter::{self, Context, Graph},
5};
6
7/// auto re-sample and buffer the audio frame from the decoder to the encoder
8///
9/// some encode, like opus support variable frame size, the frame decoded from other format
10/// may not be the same as the frame size of the encoder, this filter graph will handle the
11/// re-sample and frame split.
12pub 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}