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
use crate::{CError, CErrorCode, CStringView};

#[allow(unsafe_code)]
#[no_mangle]
pub extern "C" fn rr_video_asset_read_frame_timestamps_ns(
    video_bytes: *const u8,
    video_bytes_len: u64,
    media_type: CStringView,
    alloc_context: *mut std::ffi::c_void,
    alloc_func: Option<
        extern "C" fn(context: *mut std::ffi::c_void, num_timestamps: u32) -> *mut i64,
    >,
    error: *mut CError,
) -> *mut i64 {
    if video_bytes.is_null() {
        CError::unexpected_null("video_bytes").write_error(error);
        return std::ptr::null_mut();
    }
    let Some(alloc_func) = alloc_func else {
        CError::unexpected_null("alloc_func").write_error(error);
        return std::ptr::null_mut();
    };

    let video_bytes = unsafe { std::slice::from_raw_parts(video_bytes, video_bytes_len as usize) };
    let media_type_str = media_type.as_str("media_type").ok();

    let Some(media_type_str) =
        media_type_str.or_else(|| infer::Infer::new().get(video_bytes).map(|v| v.mime_type()))
    else {
        CError::new(
            CErrorCode::VideoLoadError,
            &re_video::VideoLoadError::UnrecognizedMimeType.to_string(),
        )
        .write_error(error);
        return std::ptr::null_mut();
    };

    let video = match re_video::VideoData::load_from_bytes(video_bytes, media_type_str) {
        Ok(video) => video,
        Err(err) => {
            CError::new(
                CErrorCode::VideoLoadError,
                &format!("Failed to load video data: {err}"),
            )
            .write_error(error);
            return std::ptr::null_mut();
        }
    };

    let num_timestamps = video.samples.len();
    let timestamps_ns_memory = alloc_func(alloc_context, num_timestamps as u32);
    let timestamps_ns =
        unsafe { std::slice::from_raw_parts_mut(timestamps_ns_memory, num_timestamps) };
    for (segment, timestamp_ns) in video.frame_timestamps_ns().zip(timestamps_ns.iter_mut()) {
        *timestamp_ns = segment;
    }

    timestamps_ns.as_mut_ptr()
}