Skip to content

Commit 0368592

Browse files
committed
perf(media): publish a lightweight opener
1 parent 1b8f604 commit 0368592

2 files changed

Lines changed: 112 additions & 40 deletions

File tree

apps/site/components/dashboard/StatusBadge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export function toneForState(state: string): StatusTone {
4343
const stateLabels: Record<string, string> = {
4444
ready: "Ready",
4545
hls_ready: "Ready",
46-
opener_ready: "Optimizing",
46+
opener_ready: "Ready, optimizing",
4747
uploaded: "Uploaded",
4848
uploading: "Uploading",
4949
processing: "Processing",

services/rend-api/src/media.rs

Lines changed: 111 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ use crate::{
3434
const OUTPUT_LOG_LIMIT_BYTES: usize = 8 * 1024;
3535
const HLS_X264_PRESET: &str = "superfast";
3636
const HLS_AUDIO_BITRATE: &str = "96k";
37+
const OPENER_MAX_DIMENSION: i32 = 640;
38+
const OPENER_VIDEO_CRF: &str = "27";
3739
const HLS_TARGET_SEGMENT_SECONDS: u32 = 1;
3840
const HLS_FFMPEG_INIT_FILENAME: &str = "init.mp4";
3941
const HLS_DEFAULT_KEYFRAME_INTERVAL_FRAMES: u32 = 30;
@@ -631,44 +633,7 @@ async fn generate_and_upload_opener(
631633
source_path: &Path,
632634
source_probe: &SourceProbe,
633635
) -> Result<UploadedArtifact> {
634-
let compatible = source_probe.video_codec.as_deref() == Some("h264")
635-
&& (!source_probe.has_audio || source_probe.audio_codec.as_deref() == Some("aac"));
636-
let mut args = vec![
637-
os("-y"),
638-
os("-i"),
639-
source_path.as_os_str().to_owned(),
640-
os("-map"),
641-
os("0:v:0"),
642-
];
643-
if source_probe.has_audio {
644-
args.extend([os("-map"), os("0:a:0")]);
645-
}
646-
if compatible {
647-
args.extend([os("-c"), os("copy")]);
648-
} else {
649-
args.extend([
650-
os("-vf"),
651-
os("scale='min(640,iw)':-2"),
652-
os("-c:v"),
653-
os("libx264"),
654-
os("-preset"),
655-
os(HLS_X264_PRESET),
656-
os("-crf"),
657-
os("27"),
658-
os("-pix_fmt"),
659-
os("yuv420p"),
660-
]);
661-
if source_probe.has_audio {
662-
args.extend([os("-c:a"), os("aac"), os("-b:a"), os(HLS_AUDIO_BITRATE)]);
663-
}
664-
}
665-
args.extend([
666-
os("-movflags"),
667-
os("+frag_keyframe+empty_moov+default_base_moof"),
668-
os("-f"),
669-
os("mp4"),
670-
os("pipe:1"),
671-
]);
636+
let args = opener_ffmpeg_args(source_path, source_probe);
672637
let object_key = opener_object_key(&request.asset_id);
673638
let uploaded_object_key = uploaded_artifact_object_key(request, &object_key);
674639
let source_size = request
@@ -706,10 +671,65 @@ async fn generate_and_upload_opener(
706671
content_type: "video/mp4",
707672
byte_size,
708673
duration_ms: Some(source_probe.duration_ms),
709-
resolution_tier: Some(source_probe.resolution_tier.to_owned()),
674+
resolution_tier: Some(
675+
if source_probe.width.max(source_probe.height) <= OPENER_MAX_DIMENSION {
676+
source_probe.resolution_tier
677+
} else {
678+
"720p"
679+
}
680+
.to_owned(),
681+
),
710682
})
711683
}
712684

685+
fn opener_ffmpeg_args(source_path: &Path, source_probe: &SourceProbe) -> Vec<OsString> {
686+
let copy_video = source_probe.video_codec.as_deref() == Some("h264")
687+
&& source_probe.width.max(source_probe.height) <= OPENER_MAX_DIMENSION;
688+
let mut args = vec![
689+
os("-y"),
690+
os("-i"),
691+
source_path.as_os_str().to_owned(),
692+
os("-map"),
693+
os("0:v:0"),
694+
];
695+
if source_probe.has_audio {
696+
args.extend([os("-map"), os("0:a:0")]);
697+
}
698+
if copy_video {
699+
args.extend([os("-c:v"), os("copy")]);
700+
} else {
701+
args.extend([
702+
os("-vf"),
703+
os(&format!(
704+
"scale=w='if(gte(iw,ih),min({OPENER_MAX_DIMENSION},iw),-2)':h='if(gte(iw,ih),-2,min({OPENER_MAX_DIMENSION},ih))'"
705+
)),
706+
os("-c:v"),
707+
os("libx264"),
708+
os("-preset"),
709+
os(HLS_X264_PRESET),
710+
os("-crf"),
711+
os(OPENER_VIDEO_CRF),
712+
os("-pix_fmt"),
713+
os("yuv420p"),
714+
]);
715+
}
716+
if source_probe.has_audio {
717+
if copy_video && source_probe.audio_codec.as_deref() == Some("aac") {
718+
args.extend([os("-c:a"), os("copy")]);
719+
} else {
720+
args.extend([os("-c:a"), os("aac"), os("-b:a"), os(HLS_AUDIO_BITRATE)]);
721+
}
722+
}
723+
args.extend([
724+
os("-movflags"),
725+
os("+frag_keyframe+empty_moov+default_base_moof"),
726+
os("-f"),
727+
os("mp4"),
728+
os("pipe:1"),
729+
]);
730+
args
731+
}
732+
713733
fn multipart_output_part_size(estimated_bytes: u64) -> usize {
714734
const MIN_PART_SIZE: u64 = 16 * 1024 * 1024;
715735
const TARGET_PART_COUNT: u64 = 9_500;
@@ -2946,6 +2966,58 @@ mod tests {
29462966
);
29472967
}
29482968

2969+
#[test]
2970+
fn opener_downscales_large_compatible_video_and_reduces_audio() {
2971+
let source_probe = SourceProbe {
2972+
duration_ms: 75_000,
2973+
width: 1920,
2974+
height: 1080,
2975+
resolution_tier: "1080p",
2976+
has_audio: true,
2977+
video_codec: Some("h264".to_owned()),
2978+
audio_codec: Some("aac".to_owned()),
2979+
frame_rate: Some(30.0),
2980+
};
2981+
2982+
let args = opener_ffmpeg_args(Path::new("source.mp4"), &source_probe)
2983+
.into_iter()
2984+
.map(|value| value.to_string_lossy().into_owned())
2985+
.collect::<Vec<_>>();
2986+
2987+
assert!(args.windows(2).any(|pair| pair == ["-c:v", "libx264"]));
2988+
assert!(args.windows(2).any(|pair| pair == ["-c:a", "aac"]));
2989+
assert!(args.windows(2).any(|pair| pair == ["-b:a", "96k"]));
2990+
assert!(args.iter().any(|value| value.contains("min(640,iw)")));
2991+
assert!(args.iter().any(|value| value.contains("min(640,ih)")));
2992+
assert!(
2993+
args.iter()
2994+
.any(|value| value == "+frag_keyframe+empty_moov+default_base_moof")
2995+
);
2996+
}
2997+
2998+
#[test]
2999+
fn opener_keeps_zero_copy_for_small_compatible_video() {
3000+
let source_probe = SourceProbe {
3001+
duration_ms: 12_000,
3002+
width: 640,
3003+
height: 360,
3004+
resolution_tier: "720p",
3005+
has_audio: true,
3006+
video_codec: Some("h264".to_owned()),
3007+
audio_codec: Some("aac".to_owned()),
3008+
frame_rate: Some(30.0),
3009+
};
3010+
3011+
let args = opener_ffmpeg_args(Path::new("source.mp4"), &source_probe)
3012+
.into_iter()
3013+
.map(|value| value.to_string_lossy().into_owned())
3014+
.collect::<Vec<_>>();
3015+
3016+
assert!(args.windows(2).any(|pair| pair == ["-c:v", "copy"]));
3017+
assert!(args.windows(2).any(|pair| pair == ["-c:a", "copy"]));
3018+
assert!(!args.iter().any(|value| value == "-vf"));
3019+
}
3020+
29493021
#[test]
29503022
fn frame_rate_parser_handles_ffprobe_ratios() {
29513023
assert_eq!(parse_frame_rate("30/1"), Some(30.0));

0 commit comments

Comments
 (0)