Skip to main content

decode/
decode.rs

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    //
56    // Audio
57    //
58    {
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    //
74    // Frames
75    //
76    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}