transcode_file/
transcode_file.rs1use std::{env, path::PathBuf, time::Instant};
2
3use lumen_ffmpeg::{
4 DecodeMode, InputContext, MuxedEncoder, VideoCodec, VideoDecoder, VideoDecoderConfig,
5 VideoEncoderConfig,
6};
7
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9 let mut args = env::args().skip(1);
10 let input_path = args
11 .next()
12 .map(PathBuf::from)
13 .ok_or("usage: transcode_file <input> <output> [max_frames] [encoder]")?;
14 let output_path = args
15 .next()
16 .map(PathBuf::from)
17 .ok_or("missing output path")?;
18 let max_frames = args.next().and_then(|value| value.parse::<usize>().ok());
19 let encoder_name = args.next();
20
21 let started = Instant::now();
22 let mut input = InputContext::open(input_path.to_string_lossy().to_string())?;
23 let stream = input.best_video_stream()?;
24 let mut decoder = VideoDecoder::open(
25 &input,
26 VideoDecoderConfig {
27 stream_index: stream.stream_index,
28 mode: DecodeMode::Cpu,
29 },
30 )?;
31 let fps = stream
32 .avg_frame_rate
33 .as_f64()
34 .filter(|fps| *fps > 0.0)
35 .unwrap_or(60.0)
36 .round()
37 .clamp(1.0, u32::MAX as f64) as u32;
38 let mut config =
39 VideoEncoderConfig::cpu_rgba(stream.width, stream.height, fps, VideoCodec::H264);
40 if let Some(encoder_name) = encoder_name {
41 config.encoder_name = Some(encoder_name);
42 }
43 let mut encoder = MuxedEncoder::create(output_path.to_string_lossy().to_string(), config)?;
44
45 let mut frames = 0_usize;
46 'decode: while let Some(packet) = input.read_packet()? {
47 decoder.send_packet(&packet)?;
48 while let Some(frame) = decoder.receive_cpu_frame()? {
49 encoder.write_video_frame(&frame)?;
50 frames = frames.saturating_add(1);
51 if max_frames.is_some_and(|limit| frames >= limit) {
52 break 'decode;
53 }
54 }
55 }
56
57 if max_frames.is_none_or(|limit| frames < limit) {
58 decoder.send_eof()?;
59 while let Some(frame) = decoder.receive_cpu_frame()? {
60 encoder.write_video_frame(&frame)?;
61 frames = frames.saturating_add(1);
62 if max_frames.is_some_and(|limit| frames >= limit) {
63 break;
64 }
65 }
66 }
67
68 encoder.finish()?;
69 println!("input={}", input_path.display());
70 println!("output={}", output_path.display());
71 println!("frames={frames}");
72 println!("elapsed_ms={}", started.elapsed().as_millis());
73 println!(
74 "fps={:.2}",
75 frames as f64 / started.elapsed().as_secs_f64().max(1e-9)
76 );
77 Ok(())
78}