Formats¶
AvialSync is intentionally open to lab-specific formats. It includes common video and tabular-data support, while plugins can add other recordings without changing the application itself.
Video¶
AvialSync decodes video itself and needs nothing installed alongside it, so what it can open is whatever its bundled FFmpeg supports — 272 video decoders, including H.264, HEVC, VP8/VP9, AV1, MPEG-4, MJPEG, ProRes, DNxHD, FFV1, and DV. This no longer varies with how a machine’s own FFmpeg happened to be compiled.
Common containers — .mp4, .m4v, .mov, .mkv, .webm, .avi, .mpg, .ts, .mts,
.m2ts, .wmv, .flv, .ogv, .3gp, .dv, .mxf, .vob, .y4m — are recognised from the
file name. A recording with an unfamiliar extension is still opened: AvialSync reads its header
and accepts it if it genuinely holds video, so a rig that names its files something of its own
works without anyone extending a list.
Still images are deliberately refused even though FFmpeg would open a PNG as a one-frame video, and tables, arrays, and audio are left to the loaders that understand them.
Raw formats such as .bin are the exception, and unavoidably so: they carry no header describing
resolution, pixel format, or rate, so nothing can infer how to read them. Those belong in a
plugin, which can declare the parameters and convert on import.
Timing comes from the frames, not the container¶
AvialSync reads every frame’s own presentation timestamp rather than trusting the rate a container declares. That matters more often than it sounds: a camera running at a varying exposure trigger routinely writes a file claiming a constant 30 fps, and its own timestamps prove otherwise.
Those timestamps decide whether a recording is treated as CFR or VFR, where a frame step lands, and which frame is named at any moment. They are cached in the per-user cache folder after the first read, so opening it again does not walk the file a second time.
AOL camera sessions and microscope trials¶
An AOL camera session can contain .mp4 or .avi cameras beside matching
<camera>-relative times.txt files. Matching uses the exact camera stem, including underscores;
when both extensions share a stem, the MP4 is selected and the AVI is reported as a duplicate.
The relative-times file supplies every AOL camera frame time in milliseconds, for both MP4 and AVI.
The camera timing report is read when present to compare its frame counts and rate with the timing
rows and video headers. Unreadable files and disagreements are reported while the rest of the
session continues loading.
The wall-clock stamps in the per-camera files have no time-zone marker. AvialSync treats the first stamp as the camera PC’s local wall-clock fields and uses the median camera start as the shared session start. This follows the rig’s external-trigger setup; the camera stop is not triggered, so the cameras may end on different frames. A spread larger than one frame period is shown as a quality warning. The timestamp is not evidence of UTC synchronization between computers.
A microscope trial folder (HH-MM-SS) or experiment folder (experiment_N) opens as one
imaging source: every RibbonScan_ROI_*.mat tile of the scan in one mosaic, laid out as the
reconstructed dendritic tree (branches as columns, their segments stacked, population patches
beside them) and oriented as the lab’s own figures show it. Each frame carries the midpoint of
its line scan; the timing note gives how far its tiles were scanned either side. An experiment
folder places each trial at its own STARTTIME, so the time between trials stays on the
timeline as a gap, and the trials are drawn as a Trials lane in Data Streams and as dashed
boundaries at both edges of each trial on the plots. Each camera’s per-trial recordings become
one video on the same timeline, each started on its trial’s trigger and trimmed to the trial.
Between trials nothing is shown: the cameras show No Footage, the imaging viewer says there
is no imaging data, and the plots have a gap. A trial without a STARTTIME, or one that starts
inside the trial before it, is left out and named; only when no trial recorded a STARTTIME do
the trials play back to back, and the warnings say so. The recordings are not changed or
copied.
The camera PC names its folders by its own clock, so they never match the trial names
(12-21-24 for trial 12-21-28). AvialSync pairs them by when they recorded: the cameras’
first-frame stamp against each trial’s STARTTIME, after removing the controller’s time zone
(from its folder names) and the offset most recordings agree on between the two PCs’ clocks.
Pairs are one to one and in time order, within Preferences → AOL → Camera-to-trial
match tolerance. A lone recording left between two matched trials, beside a lone unmatched
trial, is paired with it “by order only” and reported. A camera that started more than a second
from its trial’s trigger is placed where its own clock says rather than on the trigger, and only
its frames inside the trial are joined; one that recorded entirely outside its trial is named and
left out, as is a recording no trial was running for. Every such case is listed in the status
bar’s warnings. Cameras are looked for inside and beside the trial folders, under AOL camera
saved-data folder, and in any folder beside the date folder that mirrors
<date>/<experiment> (for example videos/2026-09-03/experiment_2 next to 2026-09-03).
What you drop decides what is joined. One trial folder opens that trial and its cameras; an
experiment folder, or several trial folders selected together, open together, each trial at its
STARTTIME. Trial and
camera folders (or an experiment folder and its camera experiment folder) dropped together are
paired with each other, wherever the camera folders are. Camera folders dropped onto trials
already open join those trials where they now sit; trials dropped onto an open camera session
are placed on its cameras. Several camera folders dropped on their own (or the camera PC’s
experiment folder) load as their trials when AvialSync can find them, beside the camera tree or
under AOL microscope saved-data folder: the imaging is offered in the import review, where
you can skip it. Without trials, each camera’s recordings join into one video, each recording at
its first-frame stamp on the camera PC’s clock. Either way the same cameras are one video each, not one per recording. Channels named Green and Red start in those colours, taken from the lab’s record
(index 1 green, index 0 red, unless the trial’s analysis says otherwise). When a trial’s line
clock and duration are missing, the controller’s Log.txt rate for that trial is used before
AvialSync asks for one. A single RibbonScan_ROI_*.mat can also be opened on its own like any
HDF5 or TIFF stack: its stored 16-bit pixels, both channels, at that ROI’s exact line-clock times
when the trial’s params.mat is beside it. The lab’s ROI-analysis files (roi_activity/,
thin_mask.mat masks) are not loaded. When the controller logged the running wheel into the
trial’s params.mat (behaviour/encoder), its speed is plotted in rpm, on the trial’s clock,
each trial at its start; with the stimulus TTL the trial commanded beside it. The controller saves its stimulus trigger
settings with each trial – whether it fires during acquisition, the delay from the trial’s start,
the pulse width, and the number and period of pulses – and AvialSync rebuilds the 0/1 trace from
them, on the trial’s clock and ending with the trial, so the row has a gap between trials: on 2026-09-03 experiment_2 one
pulse 4 s into every trial from 12-21-28 on, 1 s long (0.1 s in the last two), exactly as
Log.txt notes. No edge is recorded, so this is the commanded schedule rather than a measured
one; the source is labelled “stimulus TTL” and its pulses are found by the Stimulus Grid’s
threshold scan at the default 0.5. Wheel speed and the TTL come from one trial file and form one
group in the grid export, where streams of different units are stacked, each on its own scale. An AOL camera
session’s encoder_log.txt is plotted instead when one is open, and its angle is loaded hidden
by default so the existing wheel prop can still use it.
With an AOL camera session loaded, Align → Find microscope trial… searches the dated folder,
matches the camera wall clock against the trial’s UTC STARTTIME, and presents the evidence for
review. The derived time-zone offset assumes both PCs use the same local zone. Accepting places
the trial on camera frame zero as one undoable change; it does not alter the already-open camera
session. Clock matching was checked against a real experiment (2026-09-03, experiment_2: 18 of
19 camera recordings paired with 24 trials, the camera PC 0.71 s ahead of the controller, two
recordings off their trigger). AvialSync does not apply the controller’s optional clock
calibration correction.
Two-photon imaging¶
Open .h5, .hdf5, .tif, .tiff or .nwb through File → Open Imaging or drag the stack into
the window. Imaging is a separate time-indexed source, shown below the 3D view when both are present.
It follows the same master playhead as video and plots. PyAV continues to decode camera videos only.
The HDF5 reader selects a three-dimensional TYX dataset when the file has exactly one plausible
stack; otherwise it lists the candidates to choose from. Four- and five-dimensional datasets need an
axis order (T, C, Z, Y, X, from an axes attribute or asked at import). A Z axis with
more than one plane asks which depth to show; a C axis is shown as overlaid channels. The TIFF
reader supports page-per-time TYX, QYX, or IYX series, OME series with T, optional C/Z,
then YX axes, and ScanImage files, whose channel- and slice-interleaved pages are separated using
ScanImage’s own frame data. Other TIFF layouts need a format plugin. These choices are saved in the
session file.
Timing comes from, in order: a frame-time table you supply, a per-frame timestamp table in the file
(an HDF5 frame_times, timestamps or time dataset beside the images, or OME per-plane
DeltaT), a frame rate you typed, and finally a rate the file states (HDF5 fps/frame_rate/dt
attributes, OME TimeIncrement, ScanImage’s scan frame or volume rate). A stack with none of these
asks for its frame rate rather than guessing one.
The viewer reads only the requested HDF5 hyperslab or TIFF page on a background thread and keeps recently read planes under a fixed memory budget, so large stacks do not need to fit in RAM. Brightness, contrast, channel colours and moving averages change the displayed picture only; the raw pixels are unchanged. TIFF compression that needs an unavailable codec is reported for the affected page.
Sensor and tracking data¶
Delimited text data can be imported through the guided importer. It lets you identify the time column, time units, units for channels, missing-value sentinels, and timestamp details. Tracking CSV files can be treated as frame-indexed when that is how the source was produced.
Pose estimates¶
DeepLabCut and LightningPose multi-index CSVs are recognised by their own header — a scorer
row above a bodyparts row — rather than by their file name, and are read as frame-indexed. Each
body part becomes a channel; any complete name_x / name_y / name_z triplet also becomes a
point in the 3D pane.
Correcting a point by hand writes pose_csv_avialfix.csv (for a pose.csv) beside the original — a plain
frame,bodypart,x,y table with a commented header, readable with
pd.read_csv(path, comment="#"). The pose file itself is never modified, so deleting the
corrections file restores exactly what the model predicted. Corrections can be exported either as a
corrected copy of the pose CSV, which anything that read the original will read unchanged, or as a
retraining set for DeepLabCut or single-view Lightning Pose: a new folder whose contents are copied
into the project root. See Correcting a tracked
point.
Vicon Nexus motion capture¶
Drop a Vicon session folder containing .c3d trials, matching .xcp calibration files, and the
camera AVI files. AvialSync reads marker positions directly from C3D; it does not use companion CSV
exports. The XCP video-camera calibration projects the 3D markers into that camera’s image, and the
session scanner pairs each trial to its AVI by the calibrated camera’s device ID. Intrinsics,
Vicon radial distortion, and video-resolution scaling are applied before projection. The markers are
sampled onto the video frame grid and use the normal per-source tracking overlay controls. A trial
without a usable calibrated video-camera entry or a uniquely matching AVI is reported and left out
of the overlay rather than projected with guessed calibration. When importing a C3D separately,
assign its matching AVI as the overlay target; AvialSync reads that video’s dimensions and scales
the XCP projection to its pixel grid.
Each Vicon trial is placed where it was captured: its .xcp records every camera’s capture start
and end to the millisecond, so the trials of a session sit one after another with the time between
them kept. Each camera’s trials load as one video and its markers as one tracking source – one
pane, one Data Streams lane, one object in the 3D view – with each trial still projected through
its own calibration. A marker a trial did not track is missing for that trial, not interpolated. Those stamps are
the capture PC’s local time without a time zone, so they order and space the trials but the clock
shows time from the first trial rather than wall-clock time. A video’s file name carries the time
it was exported, not captured, and is not used.
To open one trial, copy its .c3d, matching .xcp, and camera AVI into a separate folder and drop
that folder onto AvialSync. The review dialog lists the paired video and tracking file, with the
Vicon labels, combined 3D-pose/2D-overlay role, and XCP calibration preselected. Confirm the rows to
load native XYZ markers in the 3D view and their calibrated projection on the paired video. If you
drop the files individually, choose 3D Marker Tracking for the .c3d, select the XCP in the
Calibration (XCP) column, then choose the combined 3D-pose and 2D-overlay role for its AVI. The
.xcp is not imported as tracking data, and .x2d is not currently supported as a tracking source.
Acquisition recordings¶
Electrophysiology and instrument recordings are read through neo, so the formats it supports arrive in the same shape as everything else: continuous streams become plots, and TTL lines become a square wave drawn from their edges rather than a dense trace.
Open Ephys folders are recognised as whole sessions. Drop the recording folder — or the folder
holding it and the cameras recorded beside it — and the streams, TTL lines, and videos are laid out
together on the recording’s own clock, with wall-clock time taken from the recording’s own
sync_messages.txt rather than assumed. A folder holding several recordings names each one in the
Trials lane where its samples sit; the time between recordings stays a gap.
Both Open Ephys layouts are read, including the free text each one stores:
Binary format (GUI v0.6 and later) — messages typed into the GUI’s Message Center.
Original format (
.continuousfiles, earlier versions) — the messages saved inmessages.events.
In both cases the recording’s sync preamble is used to place the clock and is not listed as a message: it is what the software wrote about the recording, not something a person typed.
Neurodata Without Borders (NWB)¶
An .nwb file holds a whole session — electrophysiology, imaging, behaviour, trials — and
AvialSync opens it as one. Drop the file (or choose it with File → Open) and the review lists:
NWB Time Series: every time series in the file, one plot row per column, named by where the series sits (
ophys.DfOverF.RoiResponseSeries.roi12,Position.SpatialSeries.x) so that two series with the same name stay apart, and grouped in the channel list on those dots. Columns are named after what they measure where the file says: electrodes by their id (ch17), ROIs by theirs (roi12), spatial series by axis. Values are scaled by the file’sconversion,channel_conversionandoffset, and shown in its units (voltsreads as V).NWB Imaging: each imaging series stored in the file (two-photon, one-photon, any
ImageSeries) opens in the imaging viewer, named after the series. It reads one plane at a time in its stored pixel type, so channels, display levels and centred averaging work without making a copy of the full stack. The separate video-compatible proxy reader remains available to plugins; its lossless copy reports progress and completes an in-progress encoding before a cancellation takes effect.Videos the file points to: an
ImageSeriesthat names an external video file is opened from beside the NWB file, placed at the time the series says its first frame was.
Everything is placed on the file’s own clock, with no alignment step: every NWB timestamp counts
from the file’s timestamps_reference_time (normally its session_start_time), which becomes the
session’s zero, and times read as wall clock.
Trials, epochs, and any other interval table become a row that is 1 inside an interval and 0
outside it, plus one message per row listing its columns (trials 3 · 12.3–14.1 s · condition=left).
The file’s trials table is also drawn as the Trials lane in Data Streams, each trial where it
ran, with dashed boundaries on the plots.
IntervalSeries (reward, licking epochs) become the same kind of row. Spike-sorted units become one
row per unit, high for an instant at each spike. Text annotations become messages.
What cannot be shown is listed when the file opens rather than skipped silently: series whose data is not a signal over time (spike waveforms, frequency decompositions), a video the file names but that is not beside it, and a start time recorded without a time zone (read as UTC).
Versions: NWB 1.x and 2.x HDF5 files, and NWB Zarr v2/v3 folders. Extension types are recognised
from the specification each file carries when available. NWB 1.x series under
acquisition/timeseries use the same plotted and imaging routes. Choose File → Open NWB… and
browse to a local file, or paste a DANDI asset download URL or its public S3 content URL; the app streams the
requested HDF5 ranges or Zarr chunks and keeps a small link in your application-data folder for
session restore. External videos referenced by a remote file must be opened locally. Imaging
creates a lossless cached copy and shows percentage progress while it is encoded; that encoding
finishes once started.
Trigger and TTL files¶
Delimited text carrying pulses rather than data: a DAQ export with a time column and one or more logical lines, or a camera log with one timestamp per exposure. Open these through Align → Open Trigger Evidence… rather than as sensor data — they are evidence about when things happened, and nothing in them is plotted.
AvialSync reads the header and offers every column that looks like a trigger line. You then say what each one is, because the file cannot: whether a line is a camera’s exposure strobe, an external frame trigger, a shared sync pulse train, or a handful of landmarks. That declaration decides which alignment models are available, so nothing is assumed for you — every column is offered as a sync train until you say otherwise. See the alignment tutorial for what each kind licenses.
One file may carry several lines about different cameras. What you declared is saved with the session; the pulses are re-read from the file each time it loads.
Lab formats¶
Ask your lab for its AvialSync plugin, or see the plugin guide to write one. Plugins describe how to recognise, read, and label a format; they do not need to change the core app.