Timestamp Output

This sample shows how to export TimestampFrame output from DELTA raw data. It uses a two-phase workflow: first save live sensor data as a .dvs file, then reopen the saved file with playback and export per-pixel ON/OFF timestamps.

Back to Code Samples.

Example Overview

Step SDK API Purpose
1 scanDevices() / openDevice() Find and open a connected DELTA Series camera.
2 applySensorSetting() Apply the recommended sensor setting file.
3 startStream() Start live USB streaming.
4 startRawSaving() / saveRawBy*() Save raw sensor data as a .dvs file.
5 openFile() / startPlayback() Reopen the saved .dvs file for offline conversion.
6 setFrameGeneration() Choose how events are grouped into generated frames.
7 setOutputType(OutputType::TimestampFrame) Generate timestamp frame output.
8 getTimestampFrameBufferSize() Get the required timestamp buffer size.
9 getTimestampFrame() Read per-pixel ON/OFF timestamp arrays.
10 setReadOverCallback() Detect when playback reaches the end of the file.

Expected Result

When the sample runs successfully, a timestamp_frame folder is created under the save directory. The folder contains the raw data captured during Phase 1 and the timestamp frame export files generated during Phase 2.

timestamp_frame/
├─ raw_data/
|   └─ year-month-day-hour-minute-second-DELTA.dvs
├─ timestamp_frame_data.bin
├─ timestamp_frame_frame_timestamps.csv
└─ timestamp_frame_metadata.txt

The raw_data folder stores the .dvs raw data file recorded from the camera.

timestamp_frame_data.bin is a binary tensor-style dump of all exported TimestampFrame data. For each generated frame, the file stores the full ON timestamp image first, followed by the full OFF timestamp image.

Frame 0: ON[H*W]  OFF[H*W]
Frame 1: ON[H*W]  OFF[H*W]
Frame 2: ON[H*W]  OFF[H*W]
...

Each value is stored as uint32 in row-major order and uses microseconds as the unit. A value of 0 means that no timestamp was recorded for that pixel in that channel.

timestamp_frame_frame_timestamps.csv stores one timestamp per generated frame. This is the lastTimestamp value for each frame and can be used later for time-surface or decay-based processing.

timestamp_frame_metadata.txt stores the information needed to read the binary file correctly.

width=960
height=720
frame_count=959
dtype=uint32
channels=on,off
units=microseconds
layout=row-major (H,W) per channel; ON channel then OFF channel per frame

Note

timestamp_frame_data.bin is not an image file. It is a compact binary export of per-pixel timestamp values. Use the metadata file to interpret the width, height, frame count, data type, channel order, and layout.

Code Walkthrough

Edit the User Control Panel

The USER CONTROL PANEL section controls camera selection, frame generation, raw saving mode, and output directories.

Select a Camera

const std::int32_t selectDeviceIndex = 0;

Select a Frame Generation Mode

Only one selected_framemode line should be active at a time.

const std::string selected_framemode = "FrameEndBased";
const std::int32_t frameEndCount = 1;

// const std::string selected_framemode = "TimeBased";
const std::int32_t framePeriodMs = 16;

// const std::string selected_framemode = "EventCountBased";
const std::int32_t eventsPerFrame = 50000;

Frame generation determines when a new TimestampFrame is produced during offline conversion.

Select a Raw Saving Mode

const std::string selected_savemode = "Continuous";

// const std::string selected_savemode = "Time";
const std::int32_t durationMs = 5000;

// const std::string selected_savemode = "FrameCount";
const std::uint64_t targetFrames = 100;

// const std::string selected_savemode = "EventCount";
const std::uint64_t targetEvents = 1000000;

Continuous starts saving when you press s and stops when you press q. Other modes call saveRawByTime(), saveRawByFrameCount(), or saveRawByEventCount().

Select Output Directories

const std::filesystem::path rawSaveDirectory =
    std::filesystem::path(DELTA_SAMPLE_ROOT) / "saved_data" / "timestamp_frame" / "raw_data";
const std::filesystem::path outputSaveDirectory =
    std::filesystem::path(DELTA_SAMPLE_ROOT) / "saved_data" / "timestamp_frame";

Phase 1: Capture Raw Data

The example saves a .dvs file first so timestamp export speed does not affect live sensor capture.

status = delta::startStream(cameraHandle);
status = delta::startRawSaving(cameraHandle, rawSaveDirectoryString.c_str());

After saving finishes, the example locates the newly saved .dvs file.

Phase 2: Select TimestampFrame Output

The saved file is reopened with playback, and TimestampFrame is selected as the only processing output.

status = delta::openFile(rawFileString.c_str(), &fileHandle);
status = delta::setPlaybackMode(fileHandle, delta::PlaybackMode::Once);
status = delta::setFrameGeneration(fileHandle, frameGeneration);
status = delta::setOutputType(fileHandle, delta::OutputType::TimestampFrame);

Prepare Timestamp Buffers

TimestampFrame requires two equally sized uint32_t arrays.

const std::uint32_t tsBufferSize =
    delta::getTimestampFrameBufferSize(fileHandle);

const std::uint32_t tsPixelCount =
    tsBufferSize / sizeof(std::uint32_t);

std::vector<std::uint32_t> tsOnBuffer(tsPixelCount);
std::vector<std::uint32_t> tsOffBuffer(tsPixelCount);

delta::TimestampFrame tsFrame{};
tsFrame.onEvent    = tsOnBuffer.data();
tsFrame.offEvent   = tsOffBuffer.data();
tsFrame.bufferSize = tsBufferSize;
Buffer Meaning
onEvent Latest ON event timestamp per pixel.
offEvent Latest OFF event timestamp per pixel.
lastTimestamp Latest timestamp observed for the generated frame.

Timestamp values are in microseconds. A value of 0 means no timestamp is stored for that pixel.

Detect End of Playback

PlaybackMode::Once fires this callback once the file has been fully read. A few more frames can still be in flight in the processing pipeline at that point, so the sample keeps polling for a short grace period afterward instead of stopping immediately.

std::atomic<bool> playbackDone{false};

status = delta::setReadOverCallback(
    fileHandle,
    [](void* userData) { static_cast<std::atomic<bool>*>(userData)->store(true); },
    &playbackDone
);

Once playbackDone is set, the polling loop allows up to 100 consecutive empty polls to drain any remaining frames before it stops.

constexpr int kDrainRetriesAfterEnd = 100;
int drainRetries = 0;

while (true) {
    status = delta::getTimestampFrame(fileHandle, &tsFrame, 0);

    if (status != delta::Status::Success) {
        if (playbackDone.load() && ++drainRetries >= kDrainRetriesAfterEnd) { break; }
        continue;
    }
    drainRetries = 0;

    // ... write frame to output files ...
}

Export Timestamp Data

The sample writes three output files.

File Contents
timestamp_frame_data.bin Concatenated frames. Each frame stores ON timestamps followed by OFF timestamps.
timestamp_frame_frame_timestamps.csv Per-frame lastTimestamp values.
timestamp_frame_metadata.txt Width, height, frame count, dtype, units, and layout information.
status = delta::getTimestampFrame(fileHandle, &tsFrame, 0);

binFile.write(
    reinterpret_cast<const char*>(tsOnBuffer.data()),
    tsOnBuffer.size() * sizeof(std::uint32_t)
);
binFile.write(
    reinterpret_cast<const char*>(tsOffBuffer.data()),
    tsOffBuffer.size() * sizeof(std::uint32_t)
);

timestampsFile << frameIndex << ',' << tsFrame.lastTimestamp << '\n';

Stop Playback

delta::stopPlayback(fileHandle);
delta::closeFile(fileHandle);