video: probe frame rate via ffprobe and return on /video/generate
Adds frame_rate to GenerateVideoResponse so the mobile scrubber can step at the source's real fps instead of a hardcoded 30. probe_video_stream_meta gains a frame_rate field (avg_frame_rate preferred, r_frame_rate fallback, nonsense values rejected) and is now pub so the handler can reuse it. Cost is one ffprobe per /video/generate call; degrades silently to None on probe failure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+16
-1
@@ -25,7 +25,9 @@ use crate::files::is_valid_full_path;
|
||||
use crate::libraries;
|
||||
use crate::otel::{extract_context_from_request, global_tracer};
|
||||
use crate::state::AppState;
|
||||
use crate::video::actors::{GeneratePreviewClipMessage, QueueVideosMessage, VideoToQueue};
|
||||
use crate::video::actors::{
|
||||
GeneratePreviewClipMessage, QueueVideosMessage, VideoToQueue, probe_video_stream_meta,
|
||||
};
|
||||
use crate::video::hls_paths;
|
||||
|
||||
/// Response body for `POST /video/generate`. Clients consume
|
||||
@@ -46,6 +48,11 @@ struct GenerateVideoResponse {
|
||||
/// transcode was queued; clients should retry the URL after a short
|
||||
/// delay (or rely on HLS.js's own retry policy).
|
||||
ready: bool,
|
||||
/// Source-video frame rate in Hz, probed via ffprobe. `None` when the
|
||||
/// probe failed or ffprobe couldn't parse either rate field — clients
|
||||
/// fall back to their own default (typically 30) for frame stepping.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
frame_rate: Option<f32>,
|
||||
}
|
||||
|
||||
#[post("/video/generate")]
|
||||
@@ -182,11 +189,19 @@ pub async fn generate_video(
|
||||
hls_paths::PLAYLIST_FILENAME
|
||||
);
|
||||
|
||||
// Probe the source for frame rate so the mobile scrubber can step at
|
||||
// the right interval. Cheap (~tens of ms) and only runs once per video
|
||||
// open. Probe failures degrade silently — clients have a fallback.
|
||||
let frame_rate = probe_video_stream_meta(&full_path.to_string_lossy())
|
||||
.await
|
||||
.frame_rate;
|
||||
|
||||
span.set_status(Status::Ok);
|
||||
HttpResponse::Ok().json(GenerateVideoResponse {
|
||||
playlist_url,
|
||||
content_hash: content_hash_str,
|
||||
ready,
|
||||
frame_rate,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user