Industry

Pixeltable for media and entertainment

Media teams need a moment in a library, not a filename. Sample stills, transcribe speech, index both, and serve search. Twelve Labs and Mixpeek are managed video APIs. Pixeltable is the table, the timestamps, and HTTP in a file you own.

Updated · Matching docs cookbook

A streaming catalog, a sports archive, or a trailer bay is thousands of hours. Editorial asks for "the shot where the product hits the table." Legal asks for every time a competitor logo is on screen. Post asks for spoken-word search over interviews. The files already live on S3. The missing piece is stills with timestamps, a transcript, and an index that updates when a new master lands.

Managed video APIs (Twelve Labs, Mixpeek) return JSON. That is the right product when you do not want a table. This page is the table: a Video column, frame_iterator, Whisper, CLIP, and FastAPIRouter. The reference architecture is /reference-architecture/video-search.

Trailer and archive search pipeline

  1. Insert title, show, and the mezzanine or trailer file.
  2. Extract audio and transcribe with Whisper (or a hosted STT API on the same column).
  3. Sample one still per second. Keep frame_attrs.
  4. Index stills with CLIP and the transcript with a sentence embedding.
  5. Serve /trailers insert, /search over stills, and /search-speech over transcripts. A still hit is a title plus a presentation timestamp; a transcript hit is the trailer.

Worked example: search trailers by what is shown or said

This is the video-search architecture with a show column for editorial filters. Keep S3 as the archive. Keep Twelve Labs when a hosted video model is the product. WhisperX is a separate cookbook if you need speakers.

import pixeltable as pxt
from pixeltable.functions.huggingface import clip, sentence_transformer
from pixeltable.functions.video import extract_audio, frame_iterator
from pixeltable.functions.whisper import transcribe
from pixeltable.serving import FastAPIRouter
TableModel = pxt.model_base()
clip_embed = clip.using(model_id='openai/clip-vit-base-patch32')
text_embed = sentence_transformer.using(model_id='all-MiniLM-L6-v2')
class Trailers(TableModel, name='trailers'):
title: pxt.String
show: pxt.String
video: pxt.Video
audio = extract_audio(video)
transcript = transcribe(audio, model='base').text.astype(pxt.String)
__indexes__ = [
pxt.EmbeddingIndex(transcript, string_embed=text_embed),
]
class Frames(
TableModel,
name='frames',
base=Trailers,
iterator=frame_iterator(video=Trailers.video, fps=1),
):
__indexes__ = [
pxt.EmbeddingIndex(frame, embedding=clip_embed),
]
@pxt.query
def search_shots(query: str, limit: int = 5):
sim = Frames.frame.similarity(string=query)
return (
Frames.order_by(sim, asc=False)
.limit(limit)
.select(title=Trailers.title, show=Trailers.show, frame_attrs=Frames.frame_attrs, score=sim)
)
@pxt.query
def search_speech(query: str, limit: int = 5):
sim = Trailers.transcript.similarity(string=query)
return (
Trailers.order_by(sim, asc=False)
.limit(limit)
.select(Trailers.title, Trailers.show, score=sim)
)
api = FastAPIRouter(name='trailers')
api.add_insert_route(
Trailers,
path='/trailers',
inputs=[Trailers.title, Trailers.show],
uploadfile_inputs=[Trailers.video],
)
api.add_query_route(path='/search', query=search_shots)
api.add_query_route(path='/search-speech', query=search_speech)
# pxt init
# pxt schema update app.py trailers -f
# pxt service update app.py trailers -f

To run a sketch, install pixeltable[serve] and the packages its model functions import (such as sentence-transformers, openai, or openai-whisper), export the provider key a model call reads (such as OPENAI_API_KEY), save the file as app.py, and run the commands in its last lines. The tables start empty: insert a row, or POST to an insert route, then select the computed columns. Get started covers the CLI.

Honest alternatives per slot

Named alternatives for Pixeltable for media and entertainment
SlotRolePixeltableNamed alternatives
Managed video APIHosted embed and captionCLIP and Whisper as columns on your table
  • Twelve Labs. You want Marengo / Pegasus and no GPU of your own
  • Mixpeek. A managed multimodal retrieval API is the product
Object storeMezzanines and trailersVideo column, or insert the S3 URL
  • Amazon S3. The archive already lives there
  • Cloudflare R2. S3-compatible storage with no egress fee on that vendor
Speech-to-textSpoken-word searchwhisper.transcribe or openai.transcriptions on extract_audio
  • Deepgram, AssemblyAI. A hosted STT API is the model choice
  • WhisperX. You need speakers; that is a separate cookbook

Where Pixeltable fits

Pixeltable is the library table: trailers, frames, transcripts, CLIP, and HTTP. Keep S3 as the archive. Keep Twelve Labs or Mixpeek when their API is the product. Pixeltable vs Twelve Labs and Pixeltable vs Mixpeek are that split. The how-to is How do I index a video library and search it by text. The gallery app is /recipes/video-search.

Questions

Can I filter by show after CLIP ranks stills?

Yes. Add .where(Trailers.show == name) on the query. That is hybrid search in the sense of similarity plus metadata, not BM25 fusion. BM25 fusion is Weaviate.

Do I need to reindex the archive when a trailer is replaced?

Insert or update that row. Computed columns and indexes recompute the affected episode. Unchanged titles stay cached. A managed API has its own reindex contract; read theirs.