Qasar Media Server

Broadcast quality for the rest of us

Embedded Media Server

Traditionally serving video with high quality playback scales in one direction - up. If you are a small system, an individual product or an in-house application you have been stuck with the costs and expenses of systems that were designed for large enterprises and large enterprise budgets.

We went the other way. Removed all of the proprietary lockins. Qasar created a full media server capability for the small guys, one that scales down as well as up. Now all of your website videos can be full variable bitrate, completely moderated with AI tagging of the content.

There are even enough sample applications provided to enable you to create a social media experience.

HLS, DASH Packaging

utomated transcoding and packaging for multiple formats:

  • Video Processing:

    • Multi-resolution HLS transcoding (1080p, 720p, 480p)
    • DASH manifest generation
    • WebM/VP9 encoding
    • Thumbnail generation (up to 25 thumbnails per video)
    • Poster image extraction
    • Duration and dimension extraction (width, height, SAR, DAR)
  • Audio Processing:

    • WebM/Opus encoding
    • Spectrogram generation
    • Poster image from spectrogram
  • Image Processing:

    • WebP conversion
    • Thumbnail generation
    • Poster image creation

Media Managment

Comprehensive media asset management:

  • Media Retrieval: Get media by ID with full metadata
  • Search: Full-text search across labels and captions
  • Recommendations: Stub for recommendation engine integration
  • Feed Endpoints: New media, recommended media, search results
  • Metadata Management: Captions, user tags, labels
  • Status Tracking: Processing status (queued, processing, ready, error)

Another reason why customers choose you, quality, service, or results.

Label Management

Flexible labeling infrastructure:

  • Label Banks: Tenant-specific label collections
  • General Labels: Content categorization labels
  • Moderation Labels: Content moderation and safety labels
  • Label Statistics: Track label usage, confidence scores, and match counts
  • Label Associations: Link labels to media assets with confidence scores
  • Hierarchical Labels: Support for parent-child label relationships

Highlight what makes you different or why people should trust you.

Share your Vision

Use this space for a short introduction. Describe your business, service, or mission in one or two sentences so visitors know what you’re all about.

Resumable Uploads

Efficient large-file upload handling with resume support:

  • Session-based uploads: Create upload sessions with configurable chunk sizes
  • Resumable uploads: Track chunk metadata in Redis for reliable resume capability
  • Progress tracking: Real-time upload progress monitoring
  • Multi-chunk support: Upload files in configurable chunk sizes
  • Automatic validation: File integrity checks during upload

Sample Apps

  • IOS Upload package for resumable uploads
  • IOS Full videoplayer component including autoplay, closed captions, scrubbing with thumbnails support.
  • Complete, simple video composition creator. Combine multiple photos and videos to create an instant composition.
  • On device tagging and moderation.
  • HTMX based web components

Small Footprint

  • No need for AWS Media Convert, Rekognition or any third party services.
  • Runs as a service on your web server, deployed as a container
  • Scales up through docker compose or as a kubernetes service.
  • High performance playback without jitter, hangs or file downloads.
  • Industry best pracices for variable bitrate video for automated scale between 1080p, 720p and 480p

Qasar Media Server Architecture

Purpose

This document describes the current architecture of the qasar-media-server repository, including:

  • Runtime services and how they interact
  • Core backend modules and data flow
  • Storage and data models
  • Deployment topology and operational boundaries

It is intended as an implementation-focused reference for contributors.

System Context

The project is a media platform composed of three deployable services:

  • media-server: FastAPI backend for upload, media APIs, labeling APIs, and static asset serving
  • worker: background processor that consumes media processing jobs from Redis/Valkey
  • webapp: Flask demo client that exercises server APIs from browser-based workflows
  • IOS Sample: Sample mobile app demonstrating advance UI/UX capabilities

Supporting infrastructure:

  • PostgreSQL for persistent metadata
  • Redis/Valkey for upload chunk tracking and job queue
  • Shared persistent volume mounted at /assets
  • Nginx as the public reverse proxy in production

High-Level Runtime View

Clients (iOS app, web demo, API consumers)
                  |
                  v
             [ Nginx TLS ]
                  |
      +-----------+------------+
      |                        |
      v                        v
[ media-server ]         [ webapp (Flask) ]
      |
      +---------------------------+
      |                           |
      v                           v
[ PostgreSQL ]              [ Redis/Valkey ]
                                  |
                                  v
                              [ worker ]
                                  |
                                  v
                          [/assets shared volume]

Backend Service Architecture (FastAPI)

Entry Point and Middleware

app/main.py creates the FastAPI app and configures:

  • Proxy header handling for TLS/offloaded deployments
  • CORS for local/demo origins
  • Startup migration execution (alembic upgrade head)
  • Static file serving under /assets/{file_path} with path traversal checks
  • API router mounting at settings.api_prefix (default /api/v1)

API Boundaries

app/api/v1/routes.py composes three route groups:

  • upload endpoints: chunked upload session lifecycle
  • media endpoints: media retrieval, package URLs, file serving, reprocess, delete
  • labels endpoints: label banks and moderation label banks

This keeps transport concerns in routers while business logic lives in app/services.

Background Processing Architecture

The worker process (app/workers/processor.py) runs an infinite dequeue loop:

  1. Block-pop from Redis list queue (processing:queue)
  2. Parse payload (media_id)
  3. Call process_media_job(media_id) in processing_service
  4. Catch/log per-job exceptions and continue

Queue interface (app/services/queue.py):

  • enqueue_job(payload) uses LPUSH
  • dequeue_job(timeout) uses BRPOP

This is a simple at-least-once queue pattern without explicit acknowledgements, dead-letter queue, or retries.

Core Data Flows

Upload and Ingest Flow

  1. Client creates upload session via POST /api/v1/upload
  2. Server persists UploadSession row and initializes chunk metadata in Redis
  3. Client uploads chunks via PUT /api/v1/upload/{session_id}/chunk
  4. Chunks are validated and written to /assets/…/.chunks/…
  5. Client completes session via POST /api/v1/upload/{session_id}/complete
  6. Server merges chunks into original file under /assets/ / / /media/…
  7. Server creates MediaAsset row
  8. If media type is non-packaged, mark ready immediately
  9. Otherwise enqueue {media_id} to Redis queue for worker processing
  10. Optional user-provided labels/caption/tags are persisted during completion

Processing Flow

  1. Worker fetches media asset and marks status as processing
  2. Worker resolves input path and initializes metadata
  3. Processing branch by media type:

    • Video: HLS, DASH, optional WebM, thumbnails, poster, dimensions, duration
    • Audio: optional WebM, spectrogram thumbnail, poster
    • Image: optional WebP, thumbnail, poster
    • Document: PDF/EPUB poster extraction
  4. Optional transcript placeholder generation when enabled
  5. Optional worker labeling for video after successful packaging
  6. Worker commits final metadata and sets status ready or error

Data Model Architecture

Primary tables (from app/db/models.py):

  • upload_sessions: transient upload lifecycle state
  • mediaassets: canonical media records and processing metadata
  • labels: normalized label dictionary
  • asset_labels: per-media aggregate label stats (count/confidence/frame data)
  • label_banks: tenant/global label bank definitions
  • label_bank_entries: entries for a label bank
  • label_bank_phrases: phrase-level synonyms/expressions per entry
  • label_bank_stats: aggregate usage/statistics per label bank entry

Multi-Tenancy Model

  • tenant_id and user_id are first-class columns on upload and media entities
  • Physical storage path is tenant/user/media scoped
  • Label banks support tenant-specific variants via tenant_id uniqueness constraints

Storage Architecture

Root path is configurable (STORAGE_ROOT, default /assets).

Canonical per-media structure:

/assets/<tenant_id>/<user_id>/<media_id>/
  media/        # original uploaded file
  hls/          # HLS playlists and segments
  dash/         # DASH manifest and segments
  webm/         # generated WebM outputs
  webp/         # generated WebP outputs
  thumbnails/   # thumbnail images
  posters/      # poster images
  transcripts/  # transcript text files
  .chunks/      # temporary upload chunks (session-scoped)

mediaassets.file_metadata (JSONB) stores derived artifact paths and API URLs.

Delivery and URL Strategy

The system uses two URL styles:

  • Static asset serving from /assets/… (direct file mapping in FastAPI)
  • API file-serving endpoints under /api/v1/media/{media_id}/… for packaged assets

file_base_url and request base URL normalization are used to build absolute URLs when needed.

Webapp and iOS Roles

  • webapp is a thin Flask-based demo client that consumes the media server API (feed, creator/upload, label management views).
  • ios contains a SwiftUI sample app and local Swift packages (QasarCreator, VideoPlayer) that integrate with the same REST API contract.

These are clients, not core infrastructure dependencies.

Deployment Topology

docker-compose.yml defines three services on external network qasar-devops_infra_net:

  • media-server container
  • worker container
  • webapp container

Shared dependencies are expected to exist on that network:

  • External Postgres
  • External Valkey/Redis
  • External named volume qasar-media-server_assets_data mounted at /assets

Production traffic is typically terminated by host-level Nginx and forwarded to:

  • 127.0.0.1:8000 (media-server)
  • 127.0.0.1:5000 (webapp)

Configuration Surface

Runtime behavior is primarily environment-driven via app/settings.py:

  • Connection settings: DATABASE_URL,REDIS_URL
  • Storage and URL settings: STORAGE_ROOT, FILE_BASE_URL, CHUNK_TMP_DIR_NAME
  • Processing feature flags: ENABLE_HLS, ENABLE_DASH, ENABLE_WEBM, ENABLE_THUMBNAILS, ENABLE_POSTERS, ENABLE_TRANSCRIPTS, ENABLE_WEBP
  • Labeling toggles: ENABLE_WORKER_LABELING, FPS/threshold/source controls

This enables the same codebase to run in local/dev/prod with different capabilities enabled.