Sign in Get started

Video

Upload videos, probe metadata, and extract frames as images into a dataset.

View as Markdown

Pictograph annotates frames, not videos. The video resource handles upload and frame extraction; once extracted, frames are regular images you annotate with the standard SAM3 / annotation workflows.

from pictograph import Client
client = Client()

upload

Three-step upload (signed URL → PUT → register), same pattern as images.

from pathlib import Path

info = client.video.upload(
    file_path=Path("./recording.mp4"),
    dataset_id="proj-uuid",
    folder_path="/raw-footage",
)
print(info.gcs_path, info.video_id)
ArgTypeDefaultNotes
file_pathstr | PathrequiredLocal video file
dataset_idstrrequiredDestination dataset
folder_pathstr"/"Virtual folder

Supported codecs: anything ffmpeg can demux (H.264, H.265, VP9, AV1, etc.).

probe

Inspect a video’s metadata without extracting frames. Pass the gcs_path returned by upload().

meta = client.video.probe(info.gcs_path)
print(meta.duration_seconds, meta.fps, meta.width, meta.height)
print(meta.codec, meta.frame_count)

Returns VideoMetadata from a server-side ffprobe invocation.

extract_frames

Extract frames from a video into the destination dataset as images.

job = client.video.extract_frames(
    gcs_path=info.gcs_path,
    dataset_id="proj-uuid",
    folder_path="/raw-footage/frames",
    fps=2.0,                       # extract 2 frames per second of source video
    start_seconds=10.0,
    end_seconds=120.0,
    max_frames=200,                # cap on output count
    wait=True,
    poll_interval=5.0,
    timeout=1800.0,
)
print(job.status, job.frames_extracted)

Frames are written as {video_basename}_{frame_index:06d}.jpg in the target folder. Each becomes a regular Image row — ready for annotation, search, training.

ArgTypeDefaultNotes
gcs_pathstrrequiredSource video
dataset_idstrrequiredDestination dataset
folder_pathstr"/"Virtual folder for the extracted frames
fpsfloat1.0Frames per source second
start_secondsfloat | NoneNoneSkip the first N seconds
end_secondsfloat | NoneNoneStop at second N
max_framesint | NoneNoneCap on output count
waitboolTruePoll until terminal

fps=1.0 is the cheapest setting; fps=30.0 extracts every frame of a 30 fps source. Frame extraction does not consume credits — you pay only for the storage of the resulting images.

get_extraction / wait_for_extraction

job = client.video.get_extraction(job_id)
job = client.video.wait_for_extraction(job_id, timeout=600.0)

Common errors

StatusExceptionCause
404NotFoundErrorgcs_path missing or dataset_id invalid
415ValidationErrorUnsupported codec
408PollTimeoutErrorLong videos may exceed default timeout
413ApiErrorVideo file exceeds upload limit (10 GB)
Copied to clipboard