Add rotation check to video transcoding logic
Seems like vertical videos aren't preserving rotation logic on copy.
This commit is contained in:
@@ -138,6 +138,36 @@ async fn is_h264_encoded(video_path: &str) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a video has rotation metadata
|
||||||
|
/// Returns the rotation angle in degrees (0, 90, 180, 270) or 0 if none detected
|
||||||
|
async fn get_video_rotation(video_path: &str) -> i32 {
|
||||||
|
let output = tokio::process::Command::new("ffprobe")
|
||||||
|
.arg("-v")
|
||||||
|
.arg("error")
|
||||||
|
.arg("-select_streams")
|
||||||
|
.arg("v:0")
|
||||||
|
.arg("-show_entries")
|
||||||
|
.arg("stream_tags=rotate")
|
||||||
|
.arg("-of")
|
||||||
|
.arg("default=noprint_wrappers=1:nokey=1")
|
||||||
|
.arg(video_path)
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Ok(output) if output.status.success() => {
|
||||||
|
let rotation_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let rotation_str = rotation_str.trim();
|
||||||
|
if rotation_str.is_empty() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
rotation_str.parse::<i32>().unwrap_or(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VideoPlaylistManager {
|
pub struct VideoPlaylistManager {
|
||||||
playlist_dir: PathBuf,
|
playlist_dir: PathBuf,
|
||||||
playlist_generator: Addr<PlaylistGenerator>,
|
playlist_generator: Addr<PlaylistGenerator>,
|
||||||
@@ -346,9 +376,19 @@ impl Handler<GeneratePlaylistMessage> for PlaylistGenerator {
|
|||||||
|
|
||||||
// Check if video is already h264 encoded
|
// Check if video is already h264 encoded
|
||||||
let is_h264 = is_h264_encoded(&video_file).await;
|
let is_h264 = is_h264_encoded(&video_file).await;
|
||||||
let use_copy = is_h264;
|
|
||||||
|
|
||||||
if use_copy {
|
// Check for rotation metadata
|
||||||
|
let rotation = get_video_rotation(&video_file).await;
|
||||||
|
let has_rotation = rotation != 0;
|
||||||
|
|
||||||
|
let use_copy = is_h264 && !has_rotation;
|
||||||
|
|
||||||
|
if has_rotation {
|
||||||
|
info!("Video {} has rotation metadata ({}°), transcoding to apply rotation", video_file, rotation);
|
||||||
|
span.add_event("Transcoding due to rotation", vec![
|
||||||
|
KeyValue::new("rotation_degrees", rotation as i64)
|
||||||
|
]);
|
||||||
|
} else if use_copy {
|
||||||
info!("Video {} is already h264, using stream copy", video_file);
|
info!("Video {} is already h264, using stream copy", video_file);
|
||||||
span.add_event("Using stream copy (h264 detected)", vec![]);
|
span.add_event("Using stream copy (h264 detected)", vec![]);
|
||||||
} else {
|
} else {
|
||||||
@@ -362,10 +402,11 @@ impl Handler<GeneratePlaylistMessage> for PlaylistGenerator {
|
|||||||
|
|
||||||
if use_copy {
|
if use_copy {
|
||||||
// Video is already h264, just copy the stream
|
// Video is already h264, just copy the stream
|
||||||
|
// Note: rotation metadata will be preserved in the stream
|
||||||
cmd.arg("-c:v").arg("copy");
|
cmd.arg("-c:v").arg("copy");
|
||||||
cmd.arg("-c:a").arg("aac"); // Still need to ensure audio is compatible
|
cmd.arg("-c:a").arg("aac"); // Still need to ensure audio is compatible
|
||||||
} else {
|
} else {
|
||||||
// Need to transcode
|
// Need to transcode - autorotate is enabled by default and will apply rotation
|
||||||
cmd.arg("-c:v").arg("h264");
|
cmd.arg("-c:v").arg("h264");
|
||||||
cmd.arg("-crf").arg("21");
|
cmd.arg("-crf").arg("21");
|
||||||
cmd.arg("-preset").arg("veryfast");
|
cmd.arg("-preset").arg("veryfast");
|
||||||
|
|||||||
Reference in New Issue
Block a user