How to
How do I build a video processing pipeline in Python?
A video processing pipeline turns clips into frames, detections, transcripts, and searchable moments. Video analysis AI is those models attached to the stills and the soundtrack, not a folder of JPEGs with lost timestamps. The pipeline is incremental: a new file recomputes that row; unchanged clips stay cached.
Updated · Part of How do I ... in Python?
Before you start
About 25 min.
- Python 3.11+
- pip install -U 'pixeltable[serve]'
- pxt init in the project root
- ffmpeg
- openai-whisper
- pixeltable-yolox
1. Ingest clips as video, not as paths in a spreadsheet
A typed Video column is what later frame extraction and audio extraction read. Titles and categories stay on the same row so you can filter after analysis.
import pixeltable as pxtfrom pixeltable.functions.video import extract_audio, frame_iteratorfrom pixeltable.functions.whisper import transcribefrom pixeltable.functions.yolox import yoloxTableModel = pxt.model_base()class Videos(TableModel, name='videos'):title: pxt.Stringcategory: pxt.Stringvideo: pxt.Videoaudio = extract_audio(video)transcript = transcribe(audio, model='base').text.astype(pxt.String)
2. Extract frames and run object detection on each still
A view emits one image row per sampled frame. YOLOX writes boxes, scores, and labels on that still. frame_attrs keeps the time so a detection is a moment in the clip.
class Frames(TableModel,name='frames',base=Videos,iterator=frame_iterator(video=Videos.video, fps=1),):detections = yolox(frame, model_id='yolox_s', threshold=0.5)# frame_attrs["index"] is the stream index# frame_attrs["time"] is the presentation timestamp in seconds (pts * time_base)
3. Split into clips when the unit is a scene, not a still
video_splitter emits time ranges (segment_start, segment_end, video_segment) when you want clip-level analysis instead of one row per frame. Use it beside the frame view, not instead of timestamps on stills.
from pixeltable.functions.video import video_splitterclass Segments(TableModel,name='segments',base=Videos,iterator=video_splitter(video=Videos.video, duration=10.0, min_segment_duration=1.0),):pass
Glue stack versus one video processing pipeline
| Job | Typical glue stack | One schema |
|---|---|---|
| Store the clip | Object storage plus a metadata database | A Video column on the table you own |
| Sample frames | A scheduled ffmpeg job between stores | A frame_iterator view on that clip |
| Detect objects | A vision service you poll and copy out | yolox as a column on each still |
| Transcribe speech | A second job on an extracted wav | extract_audio, then Whisper on the clip |
| After a new file | Rerun the DAG | Recompute the rows that changed |
Where Pixeltable fits
Pixeltable is the unified multimodal backend for a video processing pipeline: Video, frame_iterator, yolox, extract_audio, and Whisper as columns. Video analysis AI is those expressions, cached per row. Compare Pixeltable vs Twelve Labs when a hosted video model is the product, and Pixeltable vs Voxel51 when a labeling UI is the product.
import pixeltable as pxtfrom pixeltable.functions.video import extract_audio, frame_iteratorfrom pixeltable.functions.whisper import transcribefrom pixeltable.functions.yolox import yoloxTableModel = pxt.model_base()class Videos(TableModel, name='videos'):title: pxt.Stringvideo: pxt.Videoaudio = extract_audio(video)transcript = transcribe(audio, model='base').text.astype(pxt.String)class Frames(TableModel,name='frames',base=Videos,iterator=frame_iterator(video=Videos.video, fps=1),):detections = yolox(frame, model_id='yolox_s', threshold=0.5)
Questions
- Is this an Airflow DAG with ffmpeg tasks?
- No. The transforms are columns. Insert a clip and that row runs. Unchanged clips stay cached. Airflow can still sit outside when you already run a fleet of unrelated jobs; see Pixeltable vs Airflow.
- Where does video analysis AI run?
- On the stills and the soundtrack: YOLOX on each frame, Whisper on extracted audio. The output stays on those rows with frame_attrs so a detection is a timestamp.
- Can I use keyframes instead of 1 FPS?
- Yes. frame_iterator(..., keyframes_only=True) emits I-frames. Set only one of fps, num_frames, or keyframes_only. Detection then runs on fewer stills.