• Pl chevron_right

      Michael Calabrese: Synchronizing Timeline Ticks with GES Framerates in Rust

      news.movim.eu / PlanetGnome • 1 day ago • 1 minute

    While working on my GSoC project (rewriting the Pitivi timeline in Rust), I ran into an issue getting precise UI ticks that map to the absolute nanosecond timestamps of the video frames. Initially I hardcoded NTSC fractional math (24000/1001) to calculate the boundaries of frames.

    This led to issues with truncated timestamps, and had a glaring issue with other framerates (like 30fps). I needed a more robust solution that could handle any framerate and provide accurate tick positions.

    I assumed that I could extract the framerate directly from ges::Timeline , however there is no direct getter in the Rust bindings. After some digging, I discovered that the framerate is actually stored in the gst::Caps of the timeline's video stream as a gst::Fraction .

    My Approach

    The steps I used:

    • Enumerate the timeline tracks ( timeline.tracks() )
    • Filter for the video track (checking ges::TrackType::VIDEO )
    • Read the track's restriction_caps
    • Extract the gst::Fraction

    My helper

    I wrote a helper function to extract the framerate from the timeline:

    
    pub fn get_fps(&self, timeline: &ges::Timeline) -> Option<(i128, i128)> {
        timeline
            .tracks()
            .into_iter()
            .find(|track| track.track_type().contains(ges::TrackType::VIDEO))
            .and_then(|track| {
                let caps = track.restriction_caps().or_else(|| track.caps())?;
                let structure = caps.structure(0)?;
                let fps = structure.get::<gst::Fraction>("framerate").ok()?;
    
                // Extract the safe numerator and denominator
                Some((fps.numer() as i128, fps.denom() as i128))
            })
    }
    
    // ... inside the timeline injection logic:
    if let Some((fps_num, fps_denom)) = self.get_fps(timeline) {
        self.fps_num.set(fps_num.max(1) as i32);
        self.fps_denom.set(fps_denom.max(1) as i32);
    } else {
        // Default to 23.976 if we can't find a valid framerate caps
        self.fps_num.set(24_000);
        self.fps_denom.set(1_001);
    }
    
    

    I make some assumptions here, such as only one video track existing, and that the framerate is always present in the caps. This solution made the tick spacing and labels line up with the timeline’s actual frame boundaries at any framerate.