OptiTrack Timecode


This page covers the timecode representation in Motive and how it can be accessed through the NatNet SDK library tools.

Timecode Integration

SMPTE Timecode signals can be integrated into OptiTrack motion capture systems through the eSync 2 synchronization hub. To do this, simply connect a timecode sync source to the SMPTE Timecode Input of the eSync 2. Once the signal is detected, the corresponding timecode will be displayed at the top-right corner of the Perspective View pane in Motive. When you capture a Take with timecode signal, the information saved into the corresponding Take file.

Note: SMPTE Timecode integration requires the eSync 2 hub.

Timecode Representation

When SMPTE timecode signal is available within a system, each frame of data will contain an OptiTrack timecode stamp, which is an extended form of the typical studio SMPTE timecode stamp. Since the frame rate of an OptiTrack mocap system typically exceeds standard SMPTE timecode frame rates, an additional “subframe” value is added at the end of the timecode stamp. This “subframe” value is 0-based and indicates increments of captured mocap frames in between every SMPTE timecode frames:

In the above sample representation, a 120 FPS motion capture session is synchronized to a sync source with 30 FPS no-drop SMPTE timecode signal. In this case, there is a 4 : 1 ratio of number motion capture frames to a single frame of the sync source, and the extra motion capture frames are represented by the OptiTrack SubFrame field in the OptiTrack timecode.

The generic form for OptiTrack timecode: HH:MM:SS:FF.Y (hours:minutes:seconds:frames.subframe)

NatNet: Timecode

When using the NatNet SDK 4.0, the OptiTrack timecode is sent to NatNet clients in the form of two unsigned integers contained within the packet of sFrameOfMocapData:

  • OptiTrack encoded SMPTE timecode: Unsigned int Timecode

  • OptiTrack encoded sub-frame data: Unsigned int TimecodeSubframe

The Unsigned int Timecode parameter is interpreted differently when streaming from a live data (Live Mode) compared to when streaming from a recorded playback (Edit Mode). The differences are listed below:

  • Live mode: When streaming in real-time, the Timecode parameter is available only when SMPTE timecode signal is present in your mocap hardware setup; typically when using the eSync and a timecode generator. When present, the Timecode parameter will be a correctly formatted SMPTE timecode value.

  • Edit Mode: When streaming from a recorded playback, the Timecode parameter is the current frame number converted to SMPTE Timecode format.

NatNet: Timecode Helper Functions

Timecode values should not be used directly, but decoded using the provided NatNet tools. Within the NatNetClient class, there are methods for decoding the Timecode parameter and the TimecodeSubframe parameter (DecodeTimecode) and converting them into a string-friendly format (TimecodeStringify).

The NatNet SDK provides utility functions for decoding the Timecode parameter and the TimecodeSubframe parameter (NatNet_DecodeTimecode) and converting them into a string-friendly format (NatNet_TimecodeStringify).


Helper function to decode OptiTrack timecode data into individual timecode values bool NatNet_DecodeTimecode(unsigned int inTimecode, unsigned int inTimecodeSubframe,

            int* hour, int* minute, int* second, 
            int* frame, int* subframe);


Helper function to decode OptiTrack timecode into a user friendly string in the form “hh:mm:ss:ff:yy” bool NatNet_TimecodeStringify(unsigned int inTimecode, unsigned int inTimecodeSubframe,

            char *Buffer, int BufferSize);

C++ Sample: Using the utility functions for timecode parameters

The following is an example of how to decode timecode using the NatNet helper functions (from the SampleClient.cpp example): // decode timecode to values int hour, minute, second, frame, subframe; bool bValid = pClient->DecodeTimecode(data->Timecode, data->TimecodeSubframe,

        &hour, &minute, &second, &frame, &subframe);

// decode timecode to friendly string char szTimecode[128] = ""; pClient->TimecodeStringify(data->Timecode, data->TimecodeSubframe, szTimecode, 128); printf("Timecode : %s\n", szTimecode);

Last updated