Video ingest#
Upload a video file as a channel on a dataset with add_video().
With the right start time, it plays in sync with the telemetry in the same run.
Connect the client#
This guide assumes you have installed the client and setup your API keys.
from nominal.core import NominalClient
client = NominalClient.from_profile("default")
Convert the video#
add_video takes H.264 or H.265 video. For smooth playback, it also needs YUV420p pixels and regular keyframes.
normalize_video() converts a file to that format with FFmpeg, which must be installed with ffprobe:
from nominal.experimental.video_processing import normalize_video
normalize_video("engine_fire.mov", "engine_fire.mp4", force=False) # force=False keeps an existing output
It writes H.264 with a keyframe about every 2 seconds, converting any audio to AAC.
resolution scales the video down, keeping its aspect ratio.
Normalizing can change the number of frames, and logs a warning when it does.
Upload with a start time#
start is the absolute time of the first frame. Use the real capture time, or the video won’t line up with its telemetry.
from datetime import datetime, timezone
dataset = client.create_dataset("Engine fire tests")
file = dataset.add_video(
"engine_fire.mp4",
channel="engine_cam",
start=datetime(2026, 9, 10, 14, 38, 19, tzinfo=timezone.utc),
)
file.poll_until_ingestion_completed()
If you know each frame’s capture time, pass them as epoch nanoseconds in frame_timestamps instead of start.
More files on the same channel add to it.
overwrite_overlapping=True deletes earlier segments that overlap the new file.
For MCAP files, see MCAP video ingest.
The standalone Video APIs, such as client.create_video(), are deprecated in favor of video channels.
Review it in a run#
Create a run over the file’s time range and attach the dataset:
assert file.bounds is not None # set once ingestion succeeds
run = client.create_run("Engine fire", start=file.bounds.start, end=file.bounds.end)
run.add_dataset("engine_video", dataset)
In a workbook on the run, add a video panel and select engine_cam. See Runs for other ways to organize data.
Inspect and remove files#
list_video_files() lists a dataset’s video files and their metadata:
for video in dataset.list_video_files():
print(video.name, video.num_frames, video.media_frame_rate, video.bounds)
To delete one file, call delete() on it.
dataset.archive() archives the whole dataset, including its telemetry.
To process frames before uploading, see Object identification.