Skip to content

Commit 49b87e6

Browse files
authored
set pts in ffmpeg screen encoder (#1020)
1 parent 5fdf8fc commit 49b87e6

File tree

5 files changed

+27
-9
lines changed

5 files changed

+27
-9
lines changed

Cargo.lock

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

crates/enc-ffmpeg/src/video/h264.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::time::Duration;
2+
13
use cap_media_info::{Pixel, VideoInfo};
24
use ffmpeg::{
35
Dictionary,
@@ -103,7 +105,7 @@ impl H264EncoderBuilder {
103105
encoder.set_width(input_config.width);
104106
encoder.set_height(input_config.height);
105107
encoder.set_format(format);
106-
encoder.set_time_base(input_config.frame_rate.invert());
108+
encoder.set_time_base(input_config.time_base);
107109
encoder.set_frame_rate(Some(input_config.frame_rate));
108110

109111
// let target_bitrate = compression.bitrate();
@@ -121,7 +123,7 @@ impl H264EncoderBuilder {
121123

122124
let mut output_stream = output.add_stream(codec)?;
123125
let stream_index = output_stream.index();
124-
output_stream.set_time_base(input_config.frame_rate.invert());
126+
// output_stream.set_time_base((1, H264Encoder::TIME_BASE));
125127
output_stream.set_rate(input_config.frame_rate);
126128
output_stream.set_parameters(&video_encoder);
127129

@@ -147,6 +149,8 @@ pub struct H264Encoder {
147149
}
148150

149151
impl H264Encoder {
152+
const TIME_BASE: i32 = 15000;
153+
150154
pub fn builder(name: &'static str, input_config: VideoInfo) -> H264EncoderBuilder {
151155
H264EncoderBuilder::new(name, input_config)
152156
}
@@ -203,6 +207,11 @@ impl H264Encoder {
203207
}
204208
self.process_frame(output);
205209
}
210+
211+
pub fn get_pts(&self, duration: Duration) -> i64 {
212+
(duration.as_secs_f32() * self.config.time_base.denominator() as f32
213+
/ self.config.time_base.numerator() as f32) as i64
214+
}
206215
}
207216

208217
fn get_codec_and_options(

crates/recording/examples/recording-cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub async fn main() {
5656

5757
tokio::time::sleep(Duration::from_millis(10)).await;
5858

59-
let (handle, _ready_rx) = instant_recording::Actor::builder(
59+
let (handle, _ready_rx) = studio_recording::Actor::builder(
6060
dir.path().into(),
6161
ScreenCaptureTarget::Display {
6262
id: Display::primary().id(),

crates/recording/src/capture_pipeline.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub trait MakeCapturePipeline: ScreenCaptureFormat + std::fmt::Debug + 'static {
2626
flume::Receiver<(Self::VideoFormat, Timestamp)>,
2727
),
2828
output_path: PathBuf,
29+
start_time: Timestamps,
2930
) -> Result<(PipelineBuilder, flume::Receiver<Timestamp>), MediaError>
3031
where
3132
Self: Sized;
@@ -54,6 +55,7 @@ impl MakeCapturePipeline for screen_capture::CMSampleBufferCapture {
5455
flume::Receiver<(Self::VideoFormat, Timestamp)>,
5556
),
5657
output_path: PathBuf,
58+
_start_time: Timestamps,
5759
) -> Result<(PipelineBuilder, flume::Receiver<Timestamp>), MediaError> {
5860
let screen_config = source.0.info();
5961
tracing::info!("screen config: {:?}", screen_config);
@@ -234,6 +236,7 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
234236
flume::Receiver<(Self::VideoFormat, Timestamp)>,
235237
),
236238
output_path: PathBuf,
239+
start_time: Timestamps,
237240
) -> Result<(PipelineBuilder, flume::Receiver<Timestamp>), MediaError>
238241
where
239242
Self: Sized,
@@ -279,10 +282,8 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
279282
either::Left((encoder, muxer))
280283
}
281284
Err(e) => {
282-
use tracing::{error, info};
283-
284-
error!("Failed to create native encoder: {e}");
285-
info!("Falling back to software H264 encoder");
285+
tracing::error!("Failed to create native encoder: {e}");
286+
tracing::info!("Falling back to software H264 encoder");
286287

287288
either::Right(
288289
cap_enc_ffmpeg::H264Encoder::builder("screen", screen_config)
@@ -351,6 +352,7 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
351352
.map_err(|e| format!("EncoderFinish: {e}"))?;
352353
}
353354
either::Right(mut encoder) => {
355+
let mut first_timestamp = None;
354356
let mut timestamp_tx = Some(timestamp_tx);
355357
let _ = ready.send(Ok(()));
356358

@@ -361,10 +363,16 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
361363
let _ = timestamp_tx.send(timestamp);
362364
}
363365

364-
let ff_frame = frame
366+
let first_timestamp = first_timestamp.get_or_insert(timestamp);
367+
368+
let mut ff_frame = frame
365369
.as_ffmpeg()
366370
.map_err(|e| format!("FrameAsFfmpeg: {e}"))?;
367371

372+
let elapsed = timestamp.duration_since(start_time)
373+
- first_timestamp.duration_since(start_time);
374+
ff_frame.set_pts(Some(encoder.get_pts(elapsed)));
375+
368376
encoder.queue_frame(ff_frame, &mut output);
369377
}
370378
encoder.finish(&mut output);

crates/recording/src/studio_recording.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ async fn create_segment_pipeline(
752752
pipeline_builder,
753753
(screen_source, screen_rx),
754754
screen_output_path.clone(),
755+
start_time,
755756
)
756757
.unwrap();
757758
pipeline_builder = pipeline_builder_;

0 commit comments

Comments
 (0)