1use std::env;
2use std::fs;
3use std::io::Write;
4
5use motioncam_decoder::Decoder;
6
7fn write_audio(audio_chunks: &[motioncam_decoder::AudioChunk], output_path: &str) {
8 let mut file = fs::File::create(output_path).expect("failed to create audio file");
9 for chunk in audio_chunks {
10 let bytes: Vec<u8> = chunk
11 .samples
12 .iter()
13 .flat_map(|s| s.to_le_bytes())
14 .collect();
15 file.write_all(&bytes).expect("failed to write audio");
16 }
17 println!(" wrote {}", output_path);
18}
19
20fn write_raw_frame(data: &[u16], width: usize, height: usize, output_path: &str) {
21 let bytes: Vec<u8> = data.iter().flat_map(|s| s.to_le_bytes()).collect();
22 fs::write(output_path, &bytes).expect("failed to write frame");
23 println!(" wrote {} ({}x{})", output_path, width, height);
24}
25
26fn fmt_metadata(meta: &serde_json::Value) -> String {
27 let w = meta["width"].as_u64().unwrap_or(0);
28 let h = meta["height"].as_u64().unwrap_or(0);
29 let comp = meta["compressionType"].as_i64().unwrap_or(-1);
30 format!("{}x{} comp={}", w, h, comp)
31}
32
33fn main() {
34 let args: Vec<String> = env::args().collect();
35 if args.len() < 2 {
36 eprintln!("Usage: decode <input.mcraw> [-n <num_frames>]");
37 std::process::exit(1);
38 }
39
40 let input_path = &args[1];
41 let mut end_frame: Option<usize> = None;
42
43 if args.len() > 3 && args[2] == "-n" {
44 end_frame = Some(args[3].parse().expect("invalid frame count"));
45 }
46
47 let decoder = Decoder::from_path(input_path).expect("failed to open decoder");
48
49 let timestamps: Vec<i64> = decoder.frame_timestamps().collect();
50
51 println!("Found {} frames", timestamps.len());
52
53 let end = end_frame.unwrap_or(timestamps.len()).min(timestamps.len());
54
55 {
59 let audio_chunks = decoder.load_audio().expect("failed to load audio");
60 if !audio_chunks.is_empty() {
61 println!(
62 "Audio: {} chunks, {} Hz, {} channels",
63 audio_chunks.len(),
64 decoder.audio_sample_rate_hz(),
65 decoder.num_audio_channels()
66 );
67 write_audio(&audio_chunks, "audio.raw");
68 } else {
69 println!("Audio: none");
70 }
71 }
72
73 for i in 0..end {
77 let (pixels, meta) = decoder
78 .load_frame(timestamps[i])
79 .unwrap_or_else(|e| panic!("failed to decode frame {}: {}", i, e));
80
81 let width = meta["width"].as_u64().unwrap_or(0) as usize;
82 let height = meta["height"].as_u64().unwrap_or(0) as usize;
83
84 let filename = format!("frame_{:06}.raw", i);
85 println!("Frame {}: {} (ts={})", i, fmt_metadata(&meta), timestamps[i]);
86 write_raw_frame(&pixels, width, height, &filename);
87 }
88}