Skip to content

Commit c43608b

Browse files
committed
[*] use openh264 as video encoder for windows
1 parent 827504c commit c43608b

File tree

11 files changed

+522
-189
lines changed

11 files changed

+522
-189
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/mp4m/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ image.workspace = true
2727
env_logger.workspace = true
2828

2929
[target.'cfg(target_os = "linux")'.dev-dependencies]
30-
recorder = { workspace = true, features = ["wayland-wlr"] }
30+
recorder = { workspace = true, features = [
31+
"wayland-wlr",
32+
"x264-video-encoder",
33+
] }

lib/mp4m/examples/mp4_processor_demo.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use image::{ImageBuffer, Rgb};
33
use mp4m::mp4_processor::{
44
AudioConfig, Mp4Processor, Mp4ProcessorConfigBuilder, VideoConfig, VideoFrameType,
55
};
6-
use recorder::{EncodedFrame, FPS, VideoEncoder};
6+
use recorder::{self, EncodedFrame, FPS, VideoEncoderConfig};
77
use std::{path::PathBuf, thread, time::Duration};
88

99
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -98,12 +98,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
9898
log::debug!("Sent {} audio samples in total", total_sent);
9999
}
100100

101-
// Generate and send video frames
102-
let mut h264_encoder = VideoEncoder::new(width, height, fps, false)?;
103-
let headers_data = Some(h264_encoder.headers()?.entirety().to_vec());
101+
let config = VideoEncoderConfig::new(width, height).with_fps(fps);
102+
let mut h264_encoder = recorder::video_encoder_new(config)?;
103+
let headers_data = h264_encoder.headers()?;
104104

105105
let processor_thread = thread::spawn(move || {
106-
if let Err(e) = processor.run_processing_loop(headers_data) {
106+
if let Err(e) = processor.run_processing_loop(Some(headers_data)) {
107107
log::warn!("MP4 processing error: {}", e);
108108
}
109109
});
@@ -128,25 +128,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
128128
}
129129
}
130130

131-
match h264_encoder.flush() {
132-
Ok(mut flush) => {
133-
while let Some(result) = flush.next() {
134-
match result {
135-
Ok((data, _)) => {
136-
let data = data.entirety().to_vec();
137-
if let Err(e) = video_sender.send(VideoFrameType::Frame(data)) {
138-
log::warn!("video sender send flushed data failed: {e}");
139-
}
140-
}
141-
Err(e) => {
142-
log::warn!("Failed to flush encoder frame: {:?}", e);
143-
}
144-
}
145-
}
146-
}
147-
Err(e) => {
148-
log::warn!("Failed to flush encoder: {}", e);
131+
let video_sender_clone = video_sender.clone();
132+
if let Err(e) = h264_encoder.flush(Box::new(move |data| {
133+
if let Err(e) = video_sender_clone.send(VideoFrameType::Frame(data)) {
134+
log::warn!("video sender send flushed data failed: {e}");
149135
}
136+
})) {
137+
log::warn!("Failed to flush encoder frame: {:?}", e);
150138
}
151139

152140
thread::sleep(Duration::from_secs(1));

lib/mp4m/examples/mp4_processor_two_audios_demo.rs

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use image::{ImageBuffer, Rgb};
33
use mp4m::mp4_processor::{
44
AudioConfig, Mp4Processor, Mp4ProcessorConfigBuilder, VideoConfig, VideoFrameType,
55
};
6-
use recorder::{EncodedFrame, FPS, VideoEncoder};
6+
use recorder::{EncodedFrame, FPS, VideoEncoderConfig};
77
use std::{path::PathBuf, thread, time::Duration};
88

99
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -177,8 +177,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
177177
}
178178

179179
// Generate and send video frames
180-
let mut h264_encoder = VideoEncoder::new(width, height, fps, false)?;
181-
let headers_data = h264_encoder.headers()?.entirety().to_vec();
180+
let config = VideoEncoderConfig::new(width, height).with_fps(fps);
181+
let mut h264_encoder = recorder::video_encoder_new(config)?;
182+
let headers_data = h264_encoder.headers()?;
182183
if let Err(e) = video_sender.send(VideoFrameType::Frame(headers_data)) {
183184
panic!("video sender h264 header failed: {e}");
184185
}
@@ -203,25 +204,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
203204
}
204205
}
205206

206-
match h264_encoder.flush() {
207-
Ok(mut flush) => {
208-
while let Some(result) = flush.next() {
209-
match result {
210-
Ok((data, _)) => {
211-
let data = data.entirety().to_vec();
212-
if let Err(e) = video_sender.send(VideoFrameType::Frame(data)) {
213-
log::warn!("video sender send flushed data failed: {e}");
214-
}
215-
}
216-
Err(e) => {
217-
log::warn!("Failed to flush encoder frame: {:?}", e);
218-
}
219-
}
220-
}
221-
}
222-
Err(e) => {
223-
log::warn!("Failed to flush encoder: {}", e);
207+
let video_sender_clone = video_sender.clone();
208+
if let Err(e) = h264_encoder.flush(Box::new(move |data| {
209+
if let Err(e) = video_sender_clone.send(VideoFrameType::Frame(data)) {
210+
log::warn!("video sender send flushed data failed: {e}");
224211
}
212+
})) {
213+
log::warn!("Failed to flush encoder frame: {:?}", e);
225214
}
226215

227216
thread::sleep(Duration::from_secs(1));

lib/recorder/Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ spin_sleep.workspace = true
2424
nnnoiseless.workspace = true
2525
derive_setters.workspace = true
2626
screen-capture.workspace = true
27+
openh264 = { workspace = true, optional = true }
2728
yuv = { workspace = true, features = ["rayon"] }
2829
fast_image_resize = { workspace = true, features = ["rayon"] }
2930

3031
[target.'cfg(target_os = "linux")'.dependencies]
31-
x264.workspace = true
32+
x264 = { workspace = true, optional = true }
3233
pipewire.workspace = true
3334
screen-capture-wayland-wlr = { workspace = true, optional = true }
3435
screen-capture-wayland-portal = { workspace = true, optional = true }
@@ -50,6 +51,10 @@ env_logger.workspace = true
5051

5152
[features]
5253
default = ["wayland-wlr"]
53-
windows = []
54-
wayland-wlr = ["dep:screen-capture-wayland-wlr"]
55-
wayland-portal = ["dep:screen-capture-wayland-portal"]
54+
# default = ["wayland-wlr", "openh264-video-encoder"] # TODO:
55+
windows = ["openh264-video-encoder"]
56+
wayland-wlr = ["dep:screen-capture-wayland-wlr", "x264-video-encoder"]
57+
wayland-portal = ["dep:screen-capture-wayland-portal", "x264-video-encoder"]
58+
59+
x264-video-encoder = ["dep:x264"]
60+
openh264-video-encoder = ["dep:openh264"]

lib/recorder/examples/encode_frame_demo.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use recorder::{FPS, VideoEncoder};
1+
use recorder::{FPS, VideoEncoderConfig};
22
use std::path::PathBuf;
33

44
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -14,7 +14,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1414
let img = image::open(&img_path)?;
1515
log::debug!("Loaded image {}x{}", img.width(), img.height());
1616

17-
let mut encoder = VideoEncoder::new(img.width(), img.height(), FPS::Fps30, false)?;
17+
let config = VideoEncoderConfig::new(img.width(), img.height()).with_fps(FPS::Fps30);
18+
let mut encoder = recorder::video_encoder_new(config)?;
1819
let now = std::time::Instant::now();
1920
encoder.encode_frame(img.into())?;
2021
log::info!("MP4 encoding time: {:.2?}", now.elapsed());

lib/recorder/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub use resolution::Resolution;
2121
pub use speaker_recorder::{
2222
SpeakerRecorder, SpeakerRecorderConfig, SpeakerRecorderError, platform_speaker_recoder,
2323
};
24-
pub use video_encoder::{EncodedFrame, VideoEncoder};
24+
pub use video_encoder::{EncodedFrame, VideoEncoder, VideoEncoderConfig, new as video_encoder_new};
2525

2626
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2727
pub enum ProgressState {

lib/recorder/src/recorder.rs

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::{
22
AudioRecorder, CursorTracker, CursorTrackerConfig, EncodedFrame, FPS, Frame, FrameUser,
33
ProgressState, RecorderConfig, RecorderError, Resolution, SimpleFpsCounter, SpeakerRecorder,
4-
StatsUser, VideoEncoder, platform_speaker_recoder, speaker_recorder::SpeakerRecorderConfig,
4+
StatsUser, VideoEncoder, VideoEncoderConfig, platform_speaker_recoder,
5+
speaker_recorder::SpeakerRecorderConfig,
56
};
67
use crossbeam::channel::{Receiver, Sender, bounded};
78
use derive_setters::Setters;
@@ -68,7 +69,7 @@ pub struct RecordingSession {
6869
h264_frame_sender: Option<Sender<VideoFrameType>>,
6970

7071
crop_region_receiver: Option<Receiver<Rectangle>>,
71-
video_encoder: Option<VideoEncoder>,
72+
video_encoder: Option<Box<dyn VideoEncoder>>,
7273

7374
// statistic
7475
start_time: Instant,
@@ -146,9 +147,11 @@ impl RecordingSession {
146147
self.config.screen_size.width as u32,
147148
self.config.screen_size.height as u32,
148149
);
149-
let mut video_encoder =
150-
VideoEncoder::new(encoder_width, encoder_height, self.config.fps, false)?;
151-
let headers_data = video_encoder.headers()?.entirety().to_vec();
150+
151+
let video_encoder_config =
152+
VideoEncoderConfig::new(encoder_width, encoder_height).with_fps(self.config.fps);
153+
let mut video_encoder = crate::video_encoder::new(video_encoder_config)?;
154+
let headers_data = video_encoder.headers()?;
152155
let (audio_sender, speaker_sender) = self.mp4_worker(Some(headers_data.clone()))?;
153156

154157
self.video_encoder = Some(video_encoder);
@@ -853,28 +856,15 @@ impl RecordingSession {
853856
}
854857
}
855858

856-
match self.video_encoder.take().unwrap().flush() {
857-
Ok(mut flush) => {
858-
while let Some(result) = flush.next() {
859-
match result {
860-
Ok((data, _)) => {
861-
if let Some(ref sender) = self.h264_frame_sender {
862-
if let Err(e) =
863-
sender.try_send(VideoFrameType::Frame(data.entirety().to_vec()))
864-
{
865-
log::warn!("Try send h264 flushed frame faield: {e}");
866-
}
867-
}
868-
}
869-
Err(e) => {
870-
log::warn!("Failed to flush encoder frame: {e:?}");
871-
}
872-
}
859+
if let Some(sender) = self.h264_frame_sender.clone()
860+
&& let Some(ve) = self.video_encoder.take()
861+
&& let Err(e) = ve.flush(Box::new(move |data| {
862+
if let Err(e) = sender.try_send(VideoFrameType::Frame(data)) {
863+
log::warn!("Try send h264 flushed frame faield: {e}");
873864
}
874-
}
875-
Err(e) => {
876-
log::warn!("Failed to flush encoder: {e}");
877-
}
865+
}))
866+
{
867+
log::warn!("Failed to flush encoder frame: {e:?}");
878868
}
879869

880870
if let Some(stop_sig) = self.audio_mixer_stop_sig {
@@ -1104,7 +1094,10 @@ impl RecordingSession {
11041094
pub fn warmup_video_encoder(screen_size: LogicalSize, resolution: Resolution, fps: FPS) {
11051095
let (encoder_width, encoder_height) =
11061096
resolution.dimensions(screen_size.width as u32, screen_size.height as u32);
1107-
match VideoEncoder::new(encoder_width, encoder_height, fps, false) {
1097+
1098+
let video_encoder_config =
1099+
VideoEncoderConfig::new(encoder_width, encoder_height).with_fps(fps);
1100+
match crate::video_encoder::new(video_encoder_config) {
11081101
Ok(_) => log::info!("Warmup video encoder successfully"),
11091102
Err(e) => log::warn!("Warmup video encoder failed: {e}"),
11101103
}

0 commit comments

Comments
 (0)