Examples#

This page provides examples of how to use mne-videobrowser package. All examples require you to have your own MEG/EEG data and video/audio files and modify the file paths in the scripts accordingly. See examples/ directory in the GitHub repository for these examples as Python files and also two examples that can be run without your own data (they are not included here as they have boilerplate code for creating fake data).

Standalone video and audio browsing#

Video Browser#

Simple video browser without MEG/EEG data synchronization:

"""Browse a video file with video browser.

Running this requires some video file. It can be either a video file recorded
with Helsinki VideoMEG project software or a standard video file format like .mp4.
Adjust the file path and video type as needed.
"""

import logging

from qtpy.QtWidgets import QApplication

from mne_videobrowser import VideoFileCV2, VideoFileHelsinkiVideoMEG  # noqa: F401
from mne_videobrowser.browsers import VideoBrowser


def main() -> None:
    """Run the video browser demo."""
    logging.basicConfig(
        level=logging.DEBUG,
        format="%(asctime)s [%(levelname)s] %(message)s",
    )

    video_path = (
        "/u/69/taivait1/unix/video_meg_testing/Subject_2_Luna/Video_MEG/"
        "animal_meg_subject_2_240614.video.dat"
    )

    # Choose the type of video file by uncommenting/commenting.

    with VideoFileHelsinkiVideoMEG(video_path, magic_str="ELEKTA_VIDEO_FILE") as video:
        # Or use VideoFileCV2(video_path)  # for .mp4, .avi, etc.

        # Print video stats
        video.print_stats()

        app = QApplication([])
        window = VideoBrowser([video])
        window.resize(1000, 800)
        window.show()
        app.exec_()


if __name__ == "__main__":
    main()

Audio Browser#

Simple audio browser without MEG/EEG data synchronization:

"""Demo script for the AudioBrowser.

Running this requires an audio file in Helsinki VideoMEG project format.
Adjust the file path as needed.
"""

import logging

from qtpy.QtWidgets import QApplication

from mne_videobrowser import AudioFileHelsinkiVideoMEG
from mne_videobrowser.browsers import AudioBrowser


def main() -> None:
    """Run the audio browser demo."""
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(message)s",
    )

    # Replace this with the path to your audio file
    audio_path = (
        "/u/69/taivait1/unix/video_meg_testing/2025-07-11_MEG2MEG_test/"
        "2025-07-11--18-18-41_audio_00.aud"
    )

    with AudioFileHelsinkiVideoMEG(audio_path) as audio:
        audio.print_stats()

        app = QApplication([])
        window = AudioBrowser(audio)
        window.resize(1000, 600)
        window.show()
        app.exec_()


if __name__ == "__main__":
    main()

Synchronized Examples#

Video with MEG data#

Browse MEG data with synchronized video:

"""Inspect MEG data and video recorded with Helsinki VideoMEG project software.

Running this requires MEG data and video files recorded with the Helsinki VideoMEG
project software. You also need to adjust file paths.
"""

import logging
import os.path as op

import mne

from mne_videobrowser import (
    TimestampAligner,
    VideoFileHelsinkiVideoMEG,
    browse_raw_with_video,
    compute_raw_timestamps,
)


def main() -> None:
    """Run the demo."""
    BASE_PATH = "/u/69/taivait1/unix/video_meg_testing/Subject_2_Luna"
    RAW_TIMING_CHANNEL = "STI016"

    logging.basicConfig(
        level=logging.INFO,
        format="[%(asctime)s] [%(levelname)s] %(name)s:%(lineno)d %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Create a video file object
    with VideoFileHelsinkiVideoMEG(
        op.join(BASE_PATH, "Video_MEG", "animal_meg_subject_2_240614.video.dat"),
        magic_str="ELEKTA_VIDEO_FILE",
    ) as video_file:
        video_file.print_stats()

        # Create a raw data object
        raw = mne.io.read_raw_fif(
            op.join(BASE_PATH, "Raw", "animal_meg_subject_2_240614.fif"), preload=True
        )

        # Extract raw and video timestamps
        raw_timestamps_ms = compute_raw_timestamps(raw, RAW_TIMING_CHANNEL)
        video_timestamps_ms = video_file.timestamps_ms

        # Set up mapping between raw data points and video frames
        aligner = TimestampAligner(
            raw_timestamps_ms,
            video_timestamps_ms,
            name_a="raw",
            name_b="video",
        )

        # Instantiate the browsers.
        raw_browser = raw.plot(block=False, show=False, use_opengl=True)
        browse_raw_with_video(
            raw_browser,
            raw,
            [video_file],
            [aligner],
        )


if __name__ == "__main__":
    main()

Audio with MEG data#

Browse MEG data with synchronized audio:

"""Run audio browser in sync with MNE raw data browser.

Running this requires audio file recorded with the Helsinki VideoMEG project software.
You also need to adjust file paths. Used MEG data is from MNE sample dataset.
"""

import logging

import mne
import numpy as np
from mne.datasets import sample

from mne_videobrowser import (
    AudioFileHelsinkiVideoMEG,
    TimestampAligner,
    browse_raw_with_audio,
)

# Replace this with the path to your audio file.
AUDIO_PATH = (
    "/u/69/taivait1/unix/video_meg_testing/2025-07-11_MEG2MEG_test/"
    "2025-07-11--18-18-41_audio_00.aud"
)


def main() -> None:
    """Run the demo."""
    logging.basicConfig(
        level=logging.INFO,
        format="[%(asctime)s] [%(levelname)s] %(name)s:%(lineno)d %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Load sample raw data.
    data_path = sample.data_path()
    raw_fname = data_path / "MEG" / "sample" / "sample_audvis_raw.fif"
    raw = mne.io.read_raw_fif(raw_fname, preload=True)
    raw.crop(tmax=60)  # Crop to the first 60 seconds.

    # Load the audio.
    with AudioFileHelsinkiVideoMEG(AUDIO_PATH) as audio:
        audio.print_stats()

        # Extract timestamps for each audio sample.
        audio_timestamps_ms = audio.get_audio_timestamps_ms()

        # Create artificial timestamps for raw data.
        start_ts = audio_timestamps_ms[0]  # Start at the first audio timestamp
        # End at 60 seconds later (convert to milliseconds)
        end_ts = start_ts + 60 * 1000
        raw_timestamps_ms = np.linspace(start_ts, end_ts, raw.n_times, endpoint=False)

        # Align the raw data with the audio.
        aligner = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=audio_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="audio",
        )

        # Start the synced raw and audio browsers.
        raw_browser = raw.plot(block=False, show=False, use_opengl=True)
        browse_raw_with_audio(raw_browser, raw, audio, aligner)


if __name__ == "__main__":
    main()

Video and Audio with MEG Data#

Browse MEG data with both video and audio synchronized:

"""Demonstrates browsing raw data along with synchronized video and audio.

Running this requires video and audio files recorded with Helsinki VideoMEG project
software. File paths also need adjustment.
"""

import logging
import os.path as op

import mne
import numpy as np
from mne.datasets import sample

from mne_videobrowser import (
    AudioFileHelsinkiVideoMEG,
    TimestampAligner,
    VideoFileHelsinkiVideoMEG,
    browse_raw_with_video_and_audio,
)

BASE_PATH = "/u/69/taivait1/unix/video_meg_testing/2025-07-11_MEG2MEG_test/"


def main() -> None:
    """Run the video and audio sync demo."""
    logging.basicConfig(
        level=logging.INFO,
        format="[%(asctime)s] [%(levelname)s] %(name)s:%(lineno)d %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Load sample raw data.
    data_path = sample.data_path()
    raw_fname = data_path / "MEG" / "sample" / "sample_audvis_raw.fif"
    raw = mne.io.read_raw_fif(raw_fname, preload=True)
    raw.crop(tmax=60)  # Crop to 60 seconds

    # Load video and audio.
    with (
        VideoFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_video_01.vid")
        ) as video,
        AudioFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_audio_00.aud")
        ) as audio,
    ):
        # Print stats for video and audio.
        video.print_stats()
        audio.print_stats()

        # Extract video and audio timestamps.
        video_timestamps_ms = video.timestamps_ms
        audio_timestamps_ms = audio.get_audio_timestamps_ms()

        # Create artificial timestamps for raw data.
        start_ts = audio_timestamps_ms[0]  # Start at the first audio timestamp
        end_ts = (
            start_ts + 60 * 1000
        )  # End at 60 seconds later (convert to milliseconds)
        raw_timestamps_ms = np.linspace(start_ts, end_ts, raw.n_times, endpoint=False)

        # Create a separate aligner for video and audio.
        video_aligner = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=video_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="video",
        )
        audio_aligner = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=audio_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="audio",
        )

        # Start the browser.
        raw_browser = raw.plot(block=False, show=False, use_opengl=True)
        browse_raw_with_video_and_audio(
            raw_browser, raw, [video], [video_aligner], audio, audio_aligner
        )


if __name__ == "__main__":
    main()

Two Videos with MEG Data#

Browse MEG data with two synchronized videos:

"""Example script that demonstrates inspecting two videos in sync with raw data.

Loads sample MEG data and two video files, creates artificial MEG timestamps that align
well with the video timestamps and displays the videos in sync with the raw data.

Running this requires two video files recorded with Helsinki VideoMEG project software.
File paths also need adjustment.
"""

import logging
import os.path as op

import mne
import numpy as np
from mne.datasets import sample

from mne_videobrowser import (
    TimestampAligner,
    VideoFileHelsinkiVideoMEG,
    browse_raw_with_video,
)


def main() -> None:
    """Run the two-video synchronization demo."""
    BASE_PATH = "/u/69/taivait1/unix/video_meg_testing/2025-07-11_MEG2MEG_test/"

    logging.basicConfig(
        level=logging.INFO,
        format="[%(asctime)s] [%(levelname)s] %(name)s:%(lineno)d %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Load sample data.
    data_path = sample.data_path()
    raw_fname = data_path / "MEG" / "sample" / "sample_audvis_raw.fif"
    raw = mne.io.read_raw_fif(raw_fname, preload=True)
    raw.crop(tmax=60)

    # Load videos.
    with (
        VideoFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_video_01.vid")
        ) as video1,
        VideoFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_video_02.vid")
        ) as video2,
    ):
        for video in [video1, video2]:
            video.print_stats()

        # Create artificial timestamps for raw data.
        start_ts = video1.timestamps_ms[0]
        end_ts = video1.timestamps_ms[-1]
        raw_timestamps_ms = np.linspace(start_ts, end_ts, raw.n_times, endpoint=False)

        # Create a separate aligner for both videos
        aligner1 = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=video1.timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="video1",
        )
        aligner2 = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=video2.timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="video2",
        )

        # Start the browser.
        raw_browser = raw.plot(block=False, show=False, use_opengl=True)
        browse_raw_with_video(
            raw_browser,
            raw,
            [video1, video2],
            [aligner1, aligner2],
            video_splitter_orientation="vertical",
        )


if __name__ == "__main__":
    main()

Two Videos and Audio with MEG Data#

Browse MEG data with two videos and audio all synchronized:

"""Demonstrates browsing raw data along with two synchronized videos and audio.

Running this requires video and audio files recorded with Helsinki VideoMEG project
software. File paths also need adjustment.
"""

import logging
import os.path as op

import mne
import numpy as np
from mne.datasets import sample

from mne_videobrowser import (
    AudioFileHelsinkiVideoMEG,
    TimestampAligner,
    VideoFileHelsinkiVideoMEG,
    browse_raw_with_video_and_audio,
)

BASE_PATH = "/u/69/taivait1/unix/video_meg_testing/2025-07-11_MEG2MEG_test/"


def main() -> None:
    """Run the video and audio sync demo."""
    logging.basicConfig(
        level=logging.INFO,
        format="[%(asctime)s] [%(levelname)s] %(name)s:%(lineno)d %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    # Load sample data.
    data_path = sample.data_path()
    raw_fname = data_path / "MEG" / "sample" / "sample_audvis_raw.fif"
    raw = mne.io.read_raw_fif(raw_fname, preload=True)
    raw.crop(tmax=60)

    # Load videos and audio.
    with (
        VideoFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_video_01.vid")
        ) as video1,
        VideoFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_video_02.vid")
        ) as video2,
        AudioFileHelsinkiVideoMEG(
            op.join(BASE_PATH, "2025-07-11--18-18-41_audio_00.aud")
        ) as audio,
    ):
        for video in [video1, video2]:
            video.print_stats()
        audio.print_stats()

        # Extract video and audio timestamps.
        video1_timestamps_ms = video1.timestamps_ms
        video2_timestamps_ms = video2.timestamps_ms
        audio_timestamps_ms = audio.get_audio_timestamps_ms()

        # Create artificial timestamps for raw data.
        start_ts = audio_timestamps_ms[0]  # Start at the first audio timestamp
        # End at 60 seconds later (convert to milliseconds)
        end_ts = start_ts + 60 * 1000
        raw_timestamps_ms = np.linspace(start_ts, end_ts, raw.n_times, endpoint=False)

        # Create an aligner for each video and audio.
        vid_aligner1 = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=video1_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="video1",
        )
        vid_aligner2 = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=video2_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="video2",
        )
        audio_aligner = TimestampAligner(
            timestamps_a=raw_timestamps_ms,
            timestamps_b=audio_timestamps_ms,
            timestamp_unit="milliseconds",
            name_a="raw",
            name_b="audio",
        )

        # Start the browser.
        raw_browser = raw.plot(block=False, show=False, use_opengl=True)
        browse_raw_with_video_and_audio(
            raw_browser,
            raw,
            [video1, video2],
            [vid_aligner1, vid_aligner2],
            audio,
            audio_aligner,
            video_splitter_orientation="vertical",
        )


if __name__ == "__main__":
    main()