1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::*;
use byteorder::{LittleEndian, WriteBytesExt};

pub(crate) fn save_indices<F: Write + Seek>(
    f: &mut F,
    index_frame: &[TimestampLoc],
    index_keyframes: &BTreeMap<Vec<u8>, Vec<TimestampLoc>>,
) -> UFMFResult<usize> {
    let mut pos = 0;
    pos += start_dict(f, 2)?;

    // write frame dict
    pos += write_key(f, b"frame")?;
    pos += write_idx(f, index_frame)?;

    pos += write_key(f, b"keyframe")?;
    {
        let n_keyframe_types = cast::u8(index_keyframes.len())?;
        pos += start_dict(f, n_keyframe_types)?;
        for (keyframe_type, keyframe_index) in index_keyframes.iter() {
            pos += write_key(f, keyframe_type)?;
            pos += write_idx(f, keyframe_index)?;
        }
    }

    Ok(pos)
}

fn write_idx<F: Write + Seek>(f: &mut F, idx: &[TimestampLoc]) -> UFMFResult<usize> {
    let mut pos = 0;

    if !idx.is_empty() {
        let locs: Vec<_> = idx.iter().map(|x| x.loc).collect();
        let timestamps: Vec<_> = idx.iter().map(|x| x.timestamp).collect();

        pos += start_dict(f, 2)?;
        pos += write_key(f, b"loc")?;
        pos += write_locs(f, &locs)?;
        pos += write_key(f, b"timestamp")?;
        pos += write_timestamps(f, &timestamps)?;
    } else {
        pos += start_dict(f, 0)?;
    }
    Ok(pos)
}

fn start_dict<F: Write + Seek>(f: &mut F, n_keys: u8) -> UFMFResult<usize> {
    let mut pos = 0;
    pos += f.write(&[b'd', n_keys])?;
    Ok(pos)
}

fn write_key<F: Write + Seek>(f: &mut F, key: &[u8]) -> UFMFResult<usize> {
    let mut pos = 0;
    let buf0 = structure!("<H").pack(cast::u16(key.len())?)?;
    let buf1 = key;
    pos += f.write(&buf0)?;
    pos += f.write(buf1)?;
    Ok(pos)
}

fn write_locs<F: Write + Seek>(f: &mut F, locs: &[u64]) -> UFMFResult<usize> {
    let mut pos = 0;
    let dtype_char = b'l';
    let bytes_per_element = 8;

    pos += f.write(&[b'a', dtype_char])?;

    let buf = structure!("<I").pack(cast::u32(locs.len() * bytes_per_element)?)?;
    pos += f.write(&buf)?;

    for loc in locs {
        f.write_u64::<LittleEndian>(*loc)?;
        pos += 8;
    }

    Ok(pos)
}

fn write_timestamps<F: Write + Seek>(f: &mut F, timestamps: &[f64]) -> UFMFResult<usize> {
    let mut pos = 0;
    let dtype_char = b'd';
    let bytes_per_element = 8;

    pos += f.write(&[b'a', dtype_char])?;

    let buf = structure!("<I").pack(cast::u32(timestamps.len() * bytes_per_element)?)?;
    pos += f.write(&buf)?;

    for timestamp in timestamps {
        f.write_f64::<LittleEndian>(*timestamp)?;
        pos += 8;
    }

    Ok(pos)
}