Skip to content

Commit f01a998

Browse files
committed
extract ffmpeg encoder logic into common base
1 parent d4957d1 commit f01a998

8 files changed

Lines changed: 188 additions & 185 deletions

File tree

crates/enc-ffmpeg/src/audio/aac.rs

Lines changed: 17 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use ffmpeg::{
88
threading::Config,
99
};
1010

11-
use crate::{AudioEncoder, audio::buffered_resampler::BufferedResampler};
11+
use crate::{
12+
AudioEncoder,
13+
audio::{base::AudioEncoderBase, buffered_resampler::BufferedResampler},
14+
};
1215

1316
#[derive(thiserror::Error, Debug)]
1417
pub enum AACEncoderError {
@@ -18,14 +21,12 @@ pub enum AACEncoderError {
1821
CodecNotFound,
1922
#[error("Sample rate not supported: {0}")]
2023
RateNotSupported(i32),
24+
#[error("Resampler: {0}")]
25+
Resampler(ffmpeg::Error),
2126
}
2227

2328
pub struct AACEncoder {
24-
encoder: encoder::Audio,
25-
packet: ffmpeg::Packet,
26-
resampler: BufferedResampler,
27-
stream_index: usize,
28-
first_pts: Option<i64>,
29+
base: AudioEncoderBase,
2930
}
3031

3132
impl AACEncoder {
@@ -71,20 +72,8 @@ impl AACEncoder {
7172
output_config.sample_format = Self::SAMPLE_FORMAT;
7273
output_config.sample_rate = rate as u32;
7374

74-
let resampler = ffmpeg::software::resampler(
75-
(
76-
input_config.sample_format,
77-
input_config.channel_layout(),
78-
input_config.sample_rate,
79-
),
80-
(
81-
output_config.sample_format,
82-
output_config.channel_layout(),
83-
output_config.sample_rate,
84-
),
85-
)
86-
.unwrap();
87-
let resampler = BufferedResampler::new(resampler);
75+
let resampler = BufferedResampler::new(input_config, output_config)
76+
.map_err(AACEncoderError::Resampler)?;
8877

8978
encoder.set_bit_rate(Self::OUTPUT_BITRATE);
9079
encoder.set_rate(rate);
@@ -100,76 +89,30 @@ impl AACEncoder {
10089
output_stream.set_parameters(&encoder);
10190

10291
Ok(Self {
103-
encoder,
104-
stream_index,
105-
packet: ffmpeg::Packet::empty(),
106-
resampler,
107-
first_pts: None,
92+
base: AudioEncoderBase::new(encoder, resampler, stream_index),
10893
})
10994
}
11095

11196
pub fn queue_frame(
11297
&mut self,
113-
mut frame: frame::Audio,
98+
frame: frame::Audio,
11499
timestamp: Duration,
115100
output: &mut format::context::Output,
116-
) {
117-
if timestamp != Duration::MAX {
118-
let Some(pts) = frame.pts() else {
119-
tracing::error!("Frame has no pts");
120-
return;
121-
};
122-
123-
let time_base = self.encoder.time_base();
124-
let rate = time_base.denominator() as f64 / time_base.numerator() as f64;
125-
frame.set_pts(Some((timestamp.as_secs_f64() * rate).round() as i64));
126-
127-
let first_pts = self.first_pts.get_or_insert(pts);
128-
129-
frame.set_pts(Some(pts - *first_pts));
130-
}
131-
132-
self.resampler.add_frame(frame);
133-
134-
let frame_size = self.encoder.frame_size() as usize;
135-
136-
while let Some(frame) = self.resampler.get_frame(frame_size) {
137-
self.encoder.send_frame(&frame).unwrap();
138-
139-
self.process_packets(output);
140-
}
141-
}
142-
143-
fn process_packets(&mut self, output: &mut format::context::Output) {
144-
while self.encoder.receive_packet(&mut self.packet).is_ok() {
145-
self.packet.set_stream(self.stream_index);
146-
self.packet.rescale_ts(
147-
self.encoder.time_base(),
148-
output.stream(self.stream_index).unwrap().time_base(),
149-
);
150-
self.packet.write_interleaved(output).unwrap();
151-
}
101+
) -> Result<(), ffmpeg::Error> {
102+
self.base.send_frame(frame, timestamp, output)
152103
}
153104

154-
pub fn finish(&mut self, output: &mut format::context::Output) {
155-
while let Some(frame) = self.resampler.flush(self.encoder.frame_size() as usize) {
156-
self.encoder.send_frame(&frame).unwrap();
157-
158-
self.process_packets(output);
159-
}
160-
161-
self.encoder.send_eof().unwrap();
162-
163-
self.process_packets(output);
105+
pub fn finish(&mut self, output: &mut format::context::Output) -> Result<(), ffmpeg::Error> {
106+
self.base.finish(output)
164107
}
165108
}
166109

167110
impl AudioEncoder for AACEncoder {
168111
fn queue_frame(&mut self, frame: frame::Audio, output: &mut format::context::Output) {
169-
self.queue_frame(frame, Duration::MAX, output);
112+
let _ = self.queue_frame(frame, Duration::MAX, output);
170113
}
171114

172115
fn finish(&mut self, output: &mut format::context::Output) {
173-
self.finish(output);
116+
let _ = self.finish(output);
174117
}
175118
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::buffered_resampler::BufferedResampler;
2+
use crate::base::EncoderBase;
3+
use ffmpeg::{codec::encoder, format, frame};
4+
use std::time::Duration;
5+
6+
pub struct AudioEncoderBase {
7+
inner: EncoderBase,
8+
encoder: encoder::Audio,
9+
resampler: BufferedResampler,
10+
}
11+
12+
impl AudioEncoderBase {
13+
pub fn new(encoder: encoder::Audio, resampler: BufferedResampler, stream_index: usize) -> Self {
14+
Self {
15+
inner: EncoderBase::new(stream_index),
16+
encoder,
17+
resampler,
18+
}
19+
}
20+
21+
pub fn send_frame(
22+
&mut self,
23+
mut frame: frame::Audio,
24+
timestamp: Duration,
25+
output: &mut format::context::Output,
26+
) -> Result<(), ffmpeg::Error> {
27+
self.inner
28+
.update_pts(&mut frame, timestamp, &mut self.encoder);
29+
30+
self.resampler.add_frame(frame);
31+
32+
while let Some(frame) = self.resampler.get_frame(self.encoder.frame_size() as usize) {
33+
self.inner.send_frame(&frame, output, &mut self.encoder)?;
34+
}
35+
36+
Ok(())
37+
}
38+
39+
pub fn finish(&mut self, output: &mut format::context::Output) -> Result<(), ffmpeg::Error> {
40+
while let Some(frame) = self.resampler.flush(self.encoder.frame_size() as usize) {
41+
self.inner.send_frame(&frame, output, &mut self.encoder)?;
42+
}
43+
44+
self.inner.process_eof(output, &mut self.encoder)
45+
}
46+
}

crates/enc-ffmpeg/src/audio/buffered_resampler.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::VecDeque;
22

3+
use cap_media_info::AudioInfo;
34
use ffmpeg::software::resampling;
45

56
/// Consumes audio frames, resmaples them, buffers the results,
@@ -16,13 +17,18 @@ pub struct BufferedResampler {
1617
}
1718

1819
impl BufferedResampler {
19-
pub fn new(resampler: ffmpeg::software::resampling::Context) -> Self {
20-
Self {
20+
pub fn new(from: AudioInfo, to: AudioInfo) -> Result<Self, ffmpeg::Error> {
21+
let resampler = ffmpeg::software::resampler(
22+
(from.sample_format, from.channel_layout(), from.sample_rate),
23+
(to.sample_format, to.channel_layout(), to.sample_rate),
24+
)?;
25+
26+
Ok(Self {
2127
resampler,
2228
buffer: VecDeque::new(),
2329
sample_index: 0,
2430
min_next_pts: None,
25-
}
31+
})
2632
}
2733

2834
fn remaining_samples(&self) -> usize {

crates/enc-ffmpeg/src/audio/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod audio_encoder;
2+
mod base;
23
mod buffered_resampler;
34
pub use audio_encoder::*;
45

crates/enc-ffmpeg/src/audio/opus.rs

Lines changed: 11 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,11 @@ use ffmpeg::{
88
threading::Config,
99
};
1010

11-
use crate::audio::buffered_resampler::BufferedResampler;
12-
1311
use super::AudioEncoder;
12+
use crate::audio::{base::AudioEncoderBase, buffered_resampler::BufferedResampler};
1413

1514
pub struct OpusEncoder {
16-
encoder: encoder::Audio,
17-
packet: ffmpeg::Packet,
18-
resampler: BufferedResampler,
19-
stream_index: usize,
20-
first_pts: Option<i64>,
15+
base: AudioEncoderBase,
2116
}
2217

2318
#[derive(thiserror::Error, Debug)]
@@ -28,6 +23,8 @@ pub enum OpusEncoderError {
2823
CodecNotFound,
2924
#[error("Sample rate not supported: {0}")]
3025
RateNotSupported(i32),
26+
#[error("Resampler: {0}")]
27+
Resampler(ffmpeg::Error),
3128
}
3229

3330
impl OpusEncoder {
@@ -73,20 +70,8 @@ impl OpusEncoder {
7370
output_config.sample_format = Self::SAMPLE_FORMAT;
7471
output_config.sample_rate = rate as u32;
7572

76-
let resampler = ffmpeg::software::resampler(
77-
(
78-
input_config.sample_format,
79-
input_config.channel_layout(),
80-
input_config.sample_rate,
81-
),
82-
(
83-
output_config.sample_format,
84-
output_config.channel_layout(),
85-
output_config.sample_rate,
86-
),
87-
)
88-
.unwrap();
89-
let resampler = BufferedResampler::new(resampler);
73+
let resampler = BufferedResampler::new(input_config, output_config)
74+
.map_err(OpusEncoderError::Resampler)?;
9075

9176
encoder.set_bit_rate(Self::OUTPUT_BITRATE);
9277
encoder.set_rate(rate);
@@ -102,67 +87,21 @@ impl OpusEncoder {
10287
output_stream.set_parameters(&encoder);
10388

10489
Ok(Self {
105-
encoder,
106-
stream_index,
107-
packet: ffmpeg::Packet::empty(),
108-
resampler,
109-
first_pts: None,
90+
base: AudioEncoderBase::new(encoder, resampler, stream_index),
11091
})
11192
}
11293

11394
pub fn queue_frame(
11495
&mut self,
115-
mut frame: frame::Audio,
96+
frame: frame::Audio,
11697
timestamp: Duration,
11798
output: &mut format::context::Output,
11899
) {
119-
if timestamp != Duration::MAX {
120-
let Some(pts) = frame.pts() else {
121-
tracing::error!("Frame has no pts");
122-
return;
123-
};
124-
125-
let time_base = self.encoder.time_base();
126-
let rate = time_base.denominator() as f64 / time_base.numerator() as f64;
127-
frame.set_pts(Some((timestamp.as_secs_f64() * rate).round() as i64));
128-
129-
let first_pts = self.first_pts.get_or_insert(pts);
130-
131-
frame.set_pts(Some(pts - *first_pts));
132-
}
133-
134-
self.resampler.add_frame(frame);
135-
136-
let frame_size = self.encoder.frame_size() as usize;
137-
138-
while let Some(frame) = self.resampler.get_frame(frame_size) {
139-
self.encoder.send_frame(&frame).unwrap();
140-
141-
self.process_packets(output);
142-
}
143-
}
144-
145-
fn process_packets(&mut self, output: &mut format::context::Output) {
146-
while self.encoder.receive_packet(&mut self.packet).is_ok() {
147-
self.packet.set_stream(self.stream_index);
148-
self.packet.rescale_ts(
149-
self.encoder.time_base(),
150-
output.stream(self.stream_index).unwrap().time_base(),
151-
);
152-
self.packet.write_interleaved(output).unwrap();
153-
}
100+
self.base.send_frame(frame, timestamp, output);
154101
}
155102

156-
pub fn finish(&mut self, output: &mut format::context::Output) {
157-
while let Some(frame) = self.resampler.flush(self.encoder.frame_size() as usize) {
158-
self.encoder.send_frame(&frame).unwrap();
159-
160-
self.process_packets(output);
161-
}
162-
163-
self.encoder.send_eof().unwrap();
164-
165-
self.process_packets(output);
103+
pub fn finish(&mut self, output: &mut format::context::Output) -> Result<(), ffmpeg::Error> {
104+
self.base.finish(output)
166105
}
167106
}
168107

0 commit comments

Comments
 (0)