Search code examples
datetimetimevideo-capture

How to synchronize separate free-running hardware timestamp components?


I am working with an API from a chinese video compression board that is somewhat 'unfriendly'. In each video frame buffer that comes back from the driver, there is a video timestamp. However, the timestamp is broken into two separate free-running components:

1) A DateTime structure defined as

struct DateTime
{
    unsigned long second    :6;   // 0-59
    unsigned long minute    :6;   // 0-59
    unsigned long hour      :5;   // 0-23
    unsigned long day       :5;   // 1-31
    unsigned long month     :4;   // 1-12
    unsigned long year      :6;   // 2000-2063
};

2) A free-running, 16-bit (2byte) unsigned millisecond counter that rolls over.

There is nothing synchronized between these two timestamps. The millisecond rollover does not correspond to the DateTime.second increment. Performing a simple modulo 1000 division on the millisecond timer does not correspond to a DateTime.second increment either.

I need to come up with a way to combine both of these into a unified video frame timestamp that is always monotonically increasing. I would like to keep the original timestamp as delivered by the driver, but overriding theirs and attaching my own timestamp is also an option. Any suggestions are greatly appreciated!


Solution

  • I came up with a solution that seems to work for the moment. Just posting it here for completeness. My approach is to maintain a running value of the 16bit unsigned millisecond counter (named 'm_timeStampOffset'), but update it only when DateTime.second changes:

    // called at video frame rate
    if (m_prevSecond != header.timeStamp.second)
    {
        // save current value of 16bit millisec counter
        m_timeStampOffset = header.timeMs;
        m_prevSecond = header.timeStamp.second;
    }
    

    Then later on when forming the complete video frame timestamp during a client request, find the difference between the the current header.timeMs and the saved m_timeStampOffset and use that as the true millisecond timestamp:

    #define USHORT_DIFF(t0, t1)     (((t1) < (t0)) ? 0xFFFF - (t0) + (t1) : (t1) - (t0));
    // returns the full timestamp
    void get_full_timestamp(VIDEO_TIMESTAMP& ts)
    {
        ts.year   = 2000 + header.timeStamp.year;
        ts.month  = header.timeStamp.month;
        ts.day    = header.timeStamp.day;
        ts.hour   = header.timeStamp.hour;
        ts.minute = header.timeStamp.minute;
        ts.second = header.timeStamp.second;
    
        ts.milliseconds = USHORT_DIFF(m_timeStampOffset, header.timeMs);
        ts.milliseconds %= 1000;
    }